mirror of
https://iceshrimp.dev/limepotato/jormungandr-bite.git
synced 2024-11-09 11:41:30 -07:00
Toggle between different CW styles
This commit is contained in:
parent
a112f77ae0
commit
e3131e9b11
6 changed files with 240 additions and 42 deletions
|
@ -2125,3 +2125,8 @@ _feeds:
|
|||
rss: "RSS"
|
||||
atom: "Atom"
|
||||
jsonFeed: "JSON feed"
|
||||
cwStyle: "Content Warning appearance"
|
||||
_cwStyle:
|
||||
modern: "Modern"
|
||||
classic: "Classic (Misskey/Foundkey-like)"
|
||||
alternative: "Alternative (Firefish-like)"
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
<button
|
||||
ref="el"
|
||||
class="_button"
|
||||
:class="{ showLess: modelValue, fade: !modelValue }"
|
||||
:class="[cwButton, { showLess: modelValue, fade: !modelValue, }]"
|
||||
@click.stop="toggle"
|
||||
>
|
||||
<span
|
||||
<span class="cw-toggle-text"
|
||||
>{{ modelValue ? i18n.ts._cw.hide : i18n.ts._cw.show }}
|
||||
<span v-if="!modelValue">{{ label }}</span>
|
||||
<span class="cw-char-count" v-if="!modelValue">{{ label }}</span>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
@ -18,6 +18,7 @@ import { length } from "stringz";
|
|||
import type * as misskey from "iceshrimp-js";
|
||||
import { concat } from "@/scripts/array";
|
||||
import { i18n } from "@/i18n";
|
||||
import {defaultStore} from "@/store";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
|
@ -43,6 +44,8 @@ const label = computed(() => {
|
|||
] as string[][]).join(", ");
|
||||
});
|
||||
|
||||
const cwButton = computed (() => `_button_${defaultStore.state.cwStyle}`);
|
||||
|
||||
const toggle = () => {
|
||||
emit("update:modelValue", !props.modelValue);
|
||||
};
|
||||
|
@ -57,7 +60,7 @@ defineExpose({
|
|||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
._button {
|
||||
._button_modern {
|
||||
font-weight: 700;
|
||||
z-index: 5;
|
||||
> span {
|
||||
|
@ -118,4 +121,95 @@ defineExpose({
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
._button_alternative {
|
||||
font-weight: 700;
|
||||
z-index: 5;
|
||||
> span {
|
||||
background: var(--cwBg) !important;
|
||||
color: var(--cwFg);
|
||||
transition:
|
||||
background 0.2s,
|
||||
color 0.2s;
|
||||
> span {
|
||||
font-weight: 500;
|
||||
&::before {
|
||||
content: "(";
|
||||
}
|
||||
&::after {
|
||||
content: ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
&:hover > span,
|
||||
&:focus > span {
|
||||
background: var(--cwFg) !important;
|
||||
color: var(--cwBg) !important;
|
||||
}
|
||||
|
||||
&.fade {
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 1em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
}
|
||||
&:hover {
|
||||
> span {
|
||||
background: var(--panelHighlight);
|
||||
}
|
||||
}
|
||||
}
|
||||
&.showLess {
|
||||
width: 100%;
|
||||
position: sticky;
|
||||
bottom: calc(var(--stickyBottom) - 1em);
|
||||
padding: 20px;
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 6px 10px;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 0 7px 7px var(--bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
._button_classic {
|
||||
display: inline-block;
|
||||
padding: 4px 8px;
|
||||
font-size: 0.7em;
|
||||
color: var(--cwFg);
|
||||
background: var(--cwBg);
|
||||
border-radius: 2px;
|
||||
|
||||
&:hover {
|
||||
background: var(--cwHoverBg);
|
||||
}
|
||||
|
||||
> span.cw-toggle-text {
|
||||
font-weight: bold;
|
||||
|
||||
> span.cw-char-count {
|
||||
font-weight: normal;
|
||||
|
||||
&:before {
|
||||
content: '(';
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: ')';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<button
|
||||
ref="el"
|
||||
class="_button"
|
||||
:class="{ fade: modelValue, showLess: !modelValue }"
|
||||
:class="[cwButton, { fade: modelValue, showLess: !modelValue }]"
|
||||
@click.stop="toggle"
|
||||
>
|
||||
<span>{{ modelValue ? i18n.ts.showMore : i18n.ts.showLess }}</span>
|
||||
|
@ -10,7 +10,8 @@
|
|||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { i18n } from "@/i18n";
|
||||
import { ref } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import {defaultStore} from "@/store";
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
|
@ -22,6 +23,8 @@ const emit = defineEmits<{
|
|||
(ev: "update:modelValue", v: boolean): void;
|
||||
}>();
|
||||
|
||||
const cwButton = computed (() => `_button_${defaultStore.state.cwStyle}`);
|
||||
|
||||
const toggle = () => {
|
||||
emit("update:modelValue", !props.modelValue);
|
||||
};
|
||||
|
@ -44,13 +47,25 @@ defineExpose({
|
|||
padding: 20px;
|
||||
margin-bottom: -10px;
|
||||
z-index: 5;
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 3em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
&._button_modern {
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 3em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
}
|
||||
}
|
||||
&:not(._button_modern) {
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 1em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
> span {
|
||||
|
@ -65,13 +80,26 @@ defineExpose({
|
|||
padding: 20px;
|
||||
z-index: 5;
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 3em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
&._button_modern {
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 0.4em 3em;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(._button_modern) {
|
||||
> span {
|
||||
display: inline-block;
|
||||
background: var(--panel);
|
||||
padding: 6px 10px;
|
||||
font-size: 0.8em;
|
||||
border-radius: 999px;
|
||||
box-shadow: 0 0 7px 7px var(--bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<p v-if="note.cw != null" class="cw">
|
||||
<p v-if="note.cw != null" class="cw" :class="cwStyle">
|
||||
<MkA
|
||||
v-if="conversation && note.renoteId == parentId"
|
||||
:to="
|
||||
|
@ -34,24 +34,32 @@
|
|||
<i class="ph-lock ph-bold"></i>
|
||||
</span>
|
||||
<Mfm
|
||||
v-if="note.cw != '' && showContent"
|
||||
v-if="note.cw != '' && (showContent || defaultStore.state.cwStyle !== 'modern')"
|
||||
class="text"
|
||||
:text="note.cw"
|
||||
:author="note.user"
|
||||
:i="$i"
|
||||
:custom-emojis="note.emojis"
|
||||
/>
|
||||
<XCwButton
|
||||
ref="cwButton"
|
||||
v-if="note.cw && defaultStore.state.cwStyle === 'classic'"
|
||||
v-model="showContent"
|
||||
:note="note"
|
||||
v-on:keydown="focusFooter"
|
||||
v-on:update:model-value="(val) => emit('expanded', val)"
|
||||
/>
|
||||
</p>
|
||||
<div class="wrmlmaau">
|
||||
<div
|
||||
class="content"
|
||||
:class="{
|
||||
:class="[{
|
||||
collapsed,
|
||||
isLong,
|
||||
manyImages: note.files.length > 4,
|
||||
showContent: note.cw && !showContent,
|
||||
animatedMfm: !disableMfm,
|
||||
}"
|
||||
}, cwStyle]"
|
||||
>
|
||||
<XShowMoreButton
|
||||
ref="showMoreButton"
|
||||
|
@ -59,10 +67,10 @@
|
|||
v-model="collapsed"
|
||||
v-on:keydown="focusFooter"
|
||||
></XShowMoreButton>
|
||||
<Mfm v-if="note.cw && !showContent" class="hiddenNote" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
|
||||
<Mfm v-if="note.cw && ((!showContent && defaultStore.state.cwStyle === 'modern'))" class="hiddenNote" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
|
||||
<XCwButton
|
||||
ref="cwButton"
|
||||
v-if="note.cw && !showContent"
|
||||
v-if="note.cw && !showContent && defaultStore.state.cwStyle !== 'classic'"
|
||||
v-model="showContent"
|
||||
:note="note"
|
||||
v-on:keydown="focusFooter"
|
||||
|
@ -167,7 +175,7 @@
|
|||
v-model="collapsed"
|
||||
></XShowMoreButton>
|
||||
<XCwButton
|
||||
v-if="note.cw && showContent"
|
||||
v-if="note.cw && showContent && defaultStore.state.cwStyle !== 'classic'"
|
||||
v-model="showContent"
|
||||
:note="note"
|
||||
/>
|
||||
|
@ -193,7 +201,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import * as misskey from "iceshrimp-js";
|
||||
import * as mfm from "mfm-js";
|
||||
import * as os from "@/os";
|
||||
|
@ -240,6 +248,7 @@ const urls = props.note.text
|
|||
? extractUrlFromMfm(mfm.parse(props.note.text)).slice(0, 5)
|
||||
: null;
|
||||
|
||||
const cwStyle = computed (() => `_cw_style_${defaultStore.state.cwStyle}`);
|
||||
let _showContent = $ref(null);
|
||||
let showContent = $computed({
|
||||
set(val) { _showContent = val },
|
||||
|
@ -309,7 +318,9 @@ function focusFooter(ev) {
|
|||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
margin-bottom: 10px;
|
||||
&:not(._cw_style_classic) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
overflow-wrap: break-word;
|
||||
> .text {
|
||||
margin-right: 8px;
|
||||
|
@ -319,12 +330,23 @@ function focusFooter(ev) {
|
|||
.wrmlmaau {
|
||||
.content {
|
||||
overflow-wrap: break-word;
|
||||
> .hiddenNote {
|
||||
&._cw_style_modern {
|
||||
> .hiddenNote {
|
||||
display: block;
|
||||
padding: 0.5em 0 0.5em;
|
||||
font-weight: 700;
|
||||
font-size: 1.1em;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
&._cw_style_classic {
|
||||
overflow: clip;
|
||||
|
||||
cursor: default;
|
||||
display: block;
|
||||
padding: 0.5em 0 0.5em;
|
||||
font-weight: 700;
|
||||
font-size: 1.1em;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
> .body {
|
||||
transition: filter 0.1s;
|
||||
|
@ -375,7 +397,9 @@ function focusFooter(ev) {
|
|||
&.collapsed,
|
||||
&.showContent {
|
||||
position: relative;
|
||||
min-height: calc(1em + 100px);
|
||||
&._cw_style_modern {
|
||||
min-height: calc(1em + 100px);
|
||||
}
|
||||
max-height: calc(15em + 100px);
|
||||
> .body {
|
||||
max-height: inherit;
|
||||
|
@ -403,14 +427,39 @@ function focusFooter(ev) {
|
|||
}
|
||||
}
|
||||
&.showContent {
|
||||
> .body {
|
||||
min-height: 2em;
|
||||
max-height: 5em;
|
||||
visibility: hidden;
|
||||
&._cw_style_alternative {
|
||||
> .body {
|
||||
min-height: 2em;
|
||||
max-height: 5em;
|
||||
filter: blur(4px);
|
||||
:deep(span) {
|
||||
animation: none !important;
|
||||
transform: none !important;
|
||||
}
|
||||
:deep(img) {
|
||||
filter: blur(12px);
|
||||
}
|
||||
}
|
||||
:deep(.fade) {
|
||||
inset: 0;
|
||||
top: 90px;
|
||||
}
|
||||
}
|
||||
:deep(.fade) {
|
||||
inset: 0;
|
||||
top: 0;
|
||||
&._cw_style_modern {
|
||||
> .body {
|
||||
min-height: 2em;
|
||||
max-height: 5em;
|
||||
visibility: hidden;
|
||||
}
|
||||
:deep(.fade) {
|
||||
inset: 0;
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
&._cw_style_classic {
|
||||
> .body {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -200,6 +200,20 @@
|
|||
class="_formBlock"
|
||||
>{{ i18n.ts.showAdminUpdates }}</FormSwitch
|
||||
>
|
||||
|
||||
<FormSelect v-model="cwStyle" class="_formBlock">
|
||||
<template #label>{{ i18n.ts.cwStyle }}</template>
|
||||
<option value="modern">
|
||||
{{ i18n.ts._cwStyle.modern }}
|
||||
</option>
|
||||
<option value="classic">
|
||||
{{ i18n.ts._cwStyle.classic }}
|
||||
</option>
|
||||
<option value="alternative">
|
||||
{{ i18n.ts._cwStyle.alternative }}
|
||||
</option>
|
||||
</FormSelect>
|
||||
|
||||
<FormSelect v-model="instanceTicker" class="_formBlock">
|
||||
<template #label>{{ i18n.ts.instanceTicker }}</template>
|
||||
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
|
||||
|
@ -353,6 +367,9 @@ const showAdminUpdates = computed(
|
|||
const showTimelineReplies = computed(
|
||||
defaultStore.makeGetterSetter("showTimelineReplies"),
|
||||
);
|
||||
const cwStyle = computed(
|
||||
defaultStore.makeGetterSetter("cwStyle"),
|
||||
);
|
||||
|
||||
watch(swipeOnDesktop, () => {
|
||||
defaultStore.set("swipeOnMobile", true);
|
||||
|
@ -397,6 +414,7 @@ watch(
|
|||
advancedMfm,
|
||||
autoplayMfm,
|
||||
expandOnNoteClick,
|
||||
cwStyle
|
||||
],
|
||||
async () => {
|
||||
await reloadAsk();
|
||||
|
|
|
@ -334,6 +334,10 @@ export const defaultStore = markRaw(
|
|||
where: "device",
|
||||
default: false,
|
||||
},
|
||||
cwStyle: {
|
||||
where: "device",
|
||||
default: "modern" as "modern" | "classic" | "alternative",
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue