mirror of
https://activitypub.software/TransFem-org/Sharkey.git
synced 2025-08-31 22:50:43 +00:00
hide muted threads behind a CW
This commit is contained in:
parent
87582034b5
commit
9bebf7718f
11 changed files with 83 additions and 47 deletions
4
locales/index.d.ts
vendored
4
locales/index.d.ts
vendored
|
@ -11988,6 +11988,10 @@ export interface Locale extends ILocale {
|
|||
* Boosts muted
|
||||
*/
|
||||
"renoteMuted": string;
|
||||
/**
|
||||
* {name} said something in a muted thread
|
||||
*/
|
||||
"userSaysSomethingInMutedThread": ParameterizedString<"name">;
|
||||
/**
|
||||
* Mark all media from user as NSFW
|
||||
*/
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div
|
||||
v-if="!hardMuted && muted === false"
|
||||
v-if="!hardMuted && muted === false && !threadMuted"
|
||||
v-show="!isDeleted"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
|
@ -168,8 +168,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
|
||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
||||
<div v-else-if="!hardMuted" :class="$style.muted" @click.stop="muted = false">
|
||||
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||
</div>
|
||||
<div v-else>
|
||||
<!--
|
||||
|
@ -312,7 +312,7 @@ const isLong = shouldCollapsed(appearNote.value, urls.value);
|
|||
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
||||
const isDeleted = ref(false);
|
||||
const renoted = ref(false);
|
||||
const { muted, hardMuted } = checkMutes(appearNote.value, props.withHardMute);
|
||||
const { muted, hardMuted, threadMuted } = checkMutes(appearNote, computed(() => props.withHardMute));
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||
const translating = ref(false);
|
||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div
|
||||
v-if="!muted"
|
||||
v-if="!muted && !threadMuted"
|
||||
v-show="!isDeleted"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
|
@ -226,8 +226,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="_panel" :class="$style.muted" @click="muted = false">
|
||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
||||
<div v-else class="_panel" :class="$style.muted" @click.stop="muted = false">
|
||||
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -354,7 +354,7 @@ const mergedCW = computed(() => computeMergedCw(appearNote.value));
|
|||
|
||||
const renoteTooltip = computeRenoteTooltip(renoted);
|
||||
|
||||
const { muted } = checkMutes(appearNote.value);
|
||||
const { muted, threadMuted } = checkMutes(appearNote);
|
||||
|
||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||
|
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<div v-show="!isDeleted" v-if="!muted" ref="el" :class="[$style.root, { [$style.children]: depth > 1 }]">
|
||||
<div v-show="!isDeleted" v-if="!muted && !threadMuted" ref="el" :class="[$style.root, { [$style.children]: depth > 1 }]">
|
||||
<div :class="$style.main">
|
||||
<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
|
||||
<MkAvatar :class="$style.avatar" :user="note.user" link preview/>
|
||||
|
@ -78,8 +78,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkA class="_link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ti ti-chevron-double-right"></i></MkA>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else :class="$style.muted" @click="muted = false">
|
||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
||||
<div v-else :class="$style.muted" @click.stop="muted = false">
|
||||
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -172,7 +172,7 @@ async function removeReply(id: Misskey.entities.Note['id']) {
|
|||
}
|
||||
}
|
||||
|
||||
const { muted } = checkMutes(appearNote.value);
|
||||
const { muted, threadMuted } = checkMutes(appearNote);
|
||||
|
||||
useNoteCapture({
|
||||
rootEl: el,
|
||||
|
|
|
@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</MkA>
|
||||
</header>
|
||||
<div>
|
||||
<div v-if="muted" :class="[$style.text, $style.muted]">
|
||||
<SkMutedNote :muted="muted" :note="note"></SkMutedNote>
|
||||
<div v-if="muted || threadMuted" :class="[$style.text, $style.muted]">
|
||||
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="note"></SkMutedNote>
|
||||
</div>
|
||||
<Mfm v-else :class="$style.text" :text="getNoteSummary(note)" :isBlock="true" :plain="true" :nowrap="false" :isNote="true" nyaize="respect" :author="note.user"/>
|
||||
</div>
|
||||
|
@ -35,6 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<script lang="ts" setup>
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { computed } from 'vue';
|
||||
import { getNoteSummary } from '@/utility/get-note-summary.js';
|
||||
import { userPage } from '@/filters/user.js';
|
||||
import { notePage } from '@/filters/note.js';
|
||||
|
@ -49,8 +50,7 @@ defineEmits<{
|
|||
(event: 'select', user: Misskey.entities.UserLite): void
|
||||
}>();
|
||||
|
||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
||||
const { muted, hardMuted } = checkMutes(props.note);
|
||||
const { muted, hardMuted, threadMuted } = checkMutes(computed(() => props.note));
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
|
|
@ -4,24 +4,34 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
-->
|
||||
|
||||
<template>
|
||||
<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
|
||||
<I18n v-if="threadMuted" :src="i18n.ts.userSaysSomethingInMutedThread" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
</template>
|
||||
</I18n>
|
||||
<I18n v-else-if="!prefer.s.showSoftWordMutedWord" :src="i18n.ts.userSaysSomething" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
</template>
|
||||
</I18n>
|
||||
<I18n v-else :src="i18n.ts.userSaysSomethingAbout" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
</template>
|
||||
<template #word>
|
||||
{{ mutedWords }}
|
||||
</template>
|
||||
</I18n>
|
||||
|
||||
<br v-if="threadMuted && muted">
|
||||
|
||||
<template v-if="muted">
|
||||
<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
</template>
|
||||
</I18n>
|
||||
<I18n v-else-if="!prefer.s.showSoftWordMutedWord" :src="i18n.ts.userSaysSomething" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
</template>
|
||||
</I18n>
|
||||
<I18n v-else :src="i18n.ts.userSaysSomethingAbout" tag="small">
|
||||
<template #name>
|
||||
<MkUserName :user="note.user"/>
|
||||
</template>
|
||||
<template #word>
|
||||
{{ mutedWords }}
|
||||
</template>
|
||||
</I18n>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
@ -32,6 +42,7 @@ import { prefer } from '@/preferences.js';
|
|||
|
||||
const props = defineProps<{
|
||||
muted: false | 'sensitiveMute' | string[];
|
||||
threadMuted: boolean;
|
||||
note: Misskey.entities.Note;
|
||||
}>();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div
|
||||
v-if="!hardMuted && muted === false"
|
||||
v-if="!hardMuted && muted === false && !threadMuted"
|
||||
v-show="!isDeleted"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
|
@ -168,8 +168,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
|
||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
||||
<div v-else-if="!hardMuted" :class="$style.muted" @click.stop="muted = false">
|
||||
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||
</div>
|
||||
<div v-else>
|
||||
<!--
|
||||
|
@ -311,7 +311,7 @@ const isLong = shouldCollapsed(appearNote.value, urls.value);
|
|||
const collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
||||
const isDeleted = ref(false);
|
||||
const renoted = ref(false);
|
||||
const { muted, hardMuted } = checkMutes(appearNote.value, props.withHardMute);
|
||||
const { muted, hardMuted, threadMuted } = checkMutes(appearNote, computed(() => props.withHardMute));
|
||||
const translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||
const translating = ref(false);
|
||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
||||
|
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
<template>
|
||||
<div
|
||||
v-if="!muted"
|
||||
v-if="!muted && !threadMuted"
|
||||
v-show="!isDeleted"
|
||||
ref="rootEl"
|
||||
v-hotkey="keymap"
|
||||
|
@ -230,8 +230,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="_panel" :class="$style.muted" @click="muted = false">
|
||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
||||
<div v-else class="_panel" :class="$style.muted" @click.stop="muted = false">
|
||||
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -359,7 +359,7 @@ const mergedCW = computed(() => computeMergedCw(appearNote.value));
|
|||
|
||||
const renoteTooltip = computeRenoteTooltip(renoted);
|
||||
|
||||
const { muted } = checkMutes(appearNote.value);
|
||||
const { muted, threadMuted } = checkMutes(appearNote);
|
||||
|
||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||
|
|
|
@ -86,8 +86,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<MkA class="_link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ti ti-chevron-double-right"></i></MkA>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else :class="$style.muted" @click="muted = false">
|
||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
||||
<div v-else :class="$style.muted" @click.stop="muted = false">
|
||||
<SkMutedNote :muted="muted" :threadMuted="false" :note="appearNote"></SkMutedNote>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -186,7 +186,7 @@ async function removeReply(id: Misskey.entities.Note['id']) {
|
|||
}
|
||||
}
|
||||
|
||||
const { muted } = checkMutes(appearNote.value);
|
||||
const { muted } = checkMutes(appearNote);
|
||||
|
||||
useNoteCapture({
|
||||
rootEl: el,
|
||||
|
|
|
@ -3,14 +3,34 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { inject, ref } from 'vue';
|
||||
import type { Ref } from 'vue';
|
||||
import { computed, inject, ref } from 'vue';
|
||||
import type { Ref, ComputedRef } from 'vue';
|
||||
import { $i } from '@/i';
|
||||
|
||||
export function checkMutes(noteToCheck: Misskey.entities.Note, withHardMute = false) {
|
||||
const muted = ref(checkMute(noteToCheck, $i?.mutedWords));
|
||||
const hardMuted = ref(withHardMute && checkMute(noteToCheck, $i?.hardMutedWords, true));
|
||||
return { muted, hardMuted };
|
||||
export function checkMutes(noteToCheck: ComputedRef<Misskey.entities.Note>, withHardMute?: ComputedRef<boolean>) {
|
||||
const muteEnable = ref(true);
|
||||
|
||||
const muted = computed<false | string[], boolean>({
|
||||
get() {
|
||||
if (!muteEnable.value) return false;
|
||||
return checkMute(noteToCheck.value, $i?.mutedWords);
|
||||
},
|
||||
set(value: boolean) {
|
||||
muteEnable.value = value;
|
||||
},
|
||||
});
|
||||
|
||||
const threadMuted = computed(() => {
|
||||
if (!muteEnable.value) return false;
|
||||
return noteToCheck.value.isMuting;
|
||||
});
|
||||
|
||||
const hardMuted = computed(() => {
|
||||
if (!withHardMute?.value) return false;
|
||||
return checkMute(noteToCheck.value, $i?.hardMutedWords, true);
|
||||
});
|
||||
|
||||
return { muted, hardMuted, threadMuted };
|
||||
}
|
||||
|
||||
export function checkMute(note: Misskey.entities.Note, mutes: undefined | null): false;
|
||||
|
|
|
@ -29,6 +29,7 @@ muted: "Muted"
|
|||
renoteMute: "Mute Boosts"
|
||||
renoteMuted: "Boosts muted"
|
||||
renoteUnmute: "Unmute Boosts"
|
||||
userSaysSomethingInMutedThread: "{name} said something in a muted thread"
|
||||
markAsNSFW: "Mark all media from user as NSFW"
|
||||
markInstanceAsNSFW: "Mark as NSFW"
|
||||
nsfwConfirm: "Are you sure that you want to mark all media from this account as NSFW?"
|
||||
|
|
Loading…
Add table
Reference in a new issue