Toggle between different CW styles

This commit is contained in:
Laura Hausmann 2023-08-20 19:33:07 +02:00
parent a112f77ae0
commit e3131e9b11
Signed by: zotan
GPG key ID: D044E84C5BE01605
6 changed files with 240 additions and 42 deletions

View file

@ -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)"

View file

@ -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>

View file

@ -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>

View file

@ -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;
}
}
}

View file

@ -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();

View file

@ -334,6 +334,10 @@ export const defaultStore = markRaw(
where: "device",
default: false,
},
cwStyle: {
where: "device",
default: "modern" as "modern" | "classic" | "alternative",
},
}),
);