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
|
* Boosts muted
|
||||||
*/
|
*/
|
||||||
"renoteMuted": string;
|
"renoteMuted": string;
|
||||||
|
/**
|
||||||
|
* {name} said something in a muted thread
|
||||||
|
*/
|
||||||
|
"userSaysSomethingInMutedThread": ParameterizedString<"name">;
|
||||||
/**
|
/**
|
||||||
* Mark all media from user as NSFW
|
* Mark all media from user as NSFW
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="!hardMuted && muted === false"
|
v-if="!hardMuted && muted === false && !threadMuted"
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="rootEl"
|
ref="rootEl"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
|
|
@ -168,8 +168,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
|
<div v-else-if="!hardMuted" :class="$style.muted" @click.stop="muted = false">
|
||||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<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 collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const renoted = 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 translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
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>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="!muted"
|
v-if="!muted && !threadMuted"
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="rootEl"
|
ref="rootEl"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
|
|
@ -226,8 +226,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_panel" :class="$style.muted" @click="muted = false">
|
<div v-else class="_panel" :class="$style.muted" @click.stop="muted = false">
|
||||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -354,7 +354,7 @@ const mergedCW = computed(() => computeMergedCw(appearNote.value));
|
||||||
|
|
||||||
const renoteTooltip = computeRenoteTooltip(renoted);
|
const renoteTooltip = computeRenoteTooltip(renoted);
|
||||||
|
|
||||||
const { muted } = checkMutes(appearNote.value);
|
const { muted, threadMuted } = checkMutes(appearNote);
|
||||||
|
|
||||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||||
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
if (expandAllCws !== showContent.value) showContent.value = expandAllCws;
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<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 :class="$style.main">
|
||||||
<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
|
<div v-if="note.channel" :class="$style.colorBar" :style="{ background: note.channel.color }"></div>
|
||||||
<MkAvatar :class="$style.avatar" :user="note.user" link preview/>
|
<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>
|
<MkA class="_link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ti ti-chevron-double-right"></i></MkA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else :class="$style.muted" @click="muted = false">
|
<div v-else :class="$style.muted" @click.stop="muted = false">
|
||||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ async function removeReply(id: Misskey.entities.Note['id']) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { muted } = checkMutes(appearNote.value);
|
const { muted, threadMuted } = checkMutes(appearNote);
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</MkA>
|
</MkA>
|
||||||
</header>
|
</header>
|
||||||
<div>
|
<div>
|
||||||
<div v-if="muted" :class="[$style.text, $style.muted]">
|
<div v-if="muted || threadMuted" :class="[$style.text, $style.muted]">
|
||||||
<SkMutedNote :muted="muted" :note="note"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="note"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
<Mfm v-else :class="$style.text" :text="getNoteSummary(note)" :isBlock="true" :plain="true" :nowrap="false" :isNote="true" nyaize="respect" :author="note.user"/>
|
<Mfm v-else :class="$style.text" :text="getNoteSummary(note)" :isBlock="true" :plain="true" :nowrap="false" :isNote="true" nyaize="respect" :author="note.user"/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -35,6 +35,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { computed } from 'vue';
|
||||||
import { getNoteSummary } from '@/utility/get-note-summary.js';
|
import { getNoteSummary } from '@/utility/get-note-summary.js';
|
||||||
import { userPage } from '@/filters/user.js';
|
import { userPage } from '@/filters/user.js';
|
||||||
import { notePage } from '@/filters/note.js';
|
import { notePage } from '@/filters/note.js';
|
||||||
|
|
@ -49,8 +50,7 @@ defineEmits<{
|
||||||
(event: 'select', user: Misskey.entities.UserLite): void
|
(event: 'select', user: Misskey.entities.UserLite): void
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
|
const { muted, hardMuted, threadMuted } = checkMutes(computed(() => props.note));
|
||||||
const { muted, hardMuted } = checkMutes(props.note);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" module>
|
<style lang="scss" module>
|
||||||
|
|
|
||||||
|
|
@ -4,24 +4,34 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
|
<I18n v-if="threadMuted" :src="i18n.ts.userSaysSomethingInMutedThread" tag="small">
|
||||||
<template #name>
|
<template #name>
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
<I18n v-else-if="!prefer.s.showSoftWordMutedWord" :src="i18n.ts.userSaysSomething" tag="small">
|
|
||||||
|
<br v-if="threadMuted && muted">
|
||||||
|
|
||||||
|
<template v-if="muted">
|
||||||
|
<I18n v-if="muted === 'sensitiveMute'" :src="i18n.ts.userSaysSomethingSensitive" tag="small">
|
||||||
<template #name>
|
<template #name>
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
<I18n v-else :src="i18n.ts.userSaysSomethingAbout" tag="small">
|
<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>
|
<template #name>
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</template>
|
</template>
|
||||||
<template #word>
|
<template #word>
|
||||||
{{ mutedWords }}
|
{{ mutedWords }}
|
||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
@ -32,6 +42,7 @@ import { prefer } from '@/preferences.js';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
muted: false | 'sensitiveMute' | string[];
|
muted: false | 'sensitiveMute' | string[];
|
||||||
|
threadMuted: boolean;
|
||||||
note: Misskey.entities.Note;
|
note: Misskey.entities.Note;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="!hardMuted && muted === false"
|
v-if="!hardMuted && muted === false && !threadMuted"
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="rootEl"
|
ref="rootEl"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
|
|
@ -168,8 +168,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="!hardMuted" :class="$style.muted" @click="muted = false">
|
<div v-else-if="!hardMuted" :class="$style.muted" @click.stop="muted = false">
|
||||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<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 collapsed = ref(prefer.s.expandLongNote && appearNote.value.cw == null && isLong ? false : appearNote.value.cw == null && isLong);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const renoted = 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 translation = ref<Misskey.entities.NotesTranslateResponse | false | null>(null);
|
||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const showTicker = (prefer.s.instanceTicker === 'always') || (prefer.s.instanceTicker === 'remote' && appearNote.value.user.instance);
|
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>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="!muted"
|
v-if="!muted && !threadMuted"
|
||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="rootEl"
|
ref="rootEl"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
|
|
@ -230,8 +230,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_panel" :class="$style.muted" @click="muted = false">
|
<div v-else class="_panel" :class="$style.muted" @click.stop="muted = false">
|
||||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="threadMuted" :note="appearNote"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -359,7 +359,7 @@ const mergedCW = computed(() => computeMergedCw(appearNote.value));
|
||||||
|
|
||||||
const renoteTooltip = computeRenoteTooltip(renoted);
|
const renoteTooltip = computeRenoteTooltip(renoted);
|
||||||
|
|
||||||
const { muted } = checkMutes(appearNote.value);
|
const { muted, threadMuted } = checkMutes(appearNote);
|
||||||
|
|
||||||
watch(() => props.expandAllCws, (expandAllCws) => {
|
watch(() => props.expandAllCws, (expandAllCws) => {
|
||||||
if (expandAllCws !== showContent.value) showContent.value = 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>
|
<MkA class="_link" :to="notePage(note)">{{ i18n.ts.continueThread }} <i class="ti ti-chevron-double-right"></i></MkA>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else :class="$style.muted" @click="muted = false">
|
<div v-else :class="$style.muted" @click.stop="muted = false">
|
||||||
<SkMutedNote :muted="muted" :note="appearNote"></SkMutedNote>
|
<SkMutedNote :muted="muted" :threadMuted="false" :note="appearNote"></SkMutedNote>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -186,7 +186,7 @@ async function removeReply(id: Misskey.entities.Note['id']) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { muted } = checkMutes(appearNote.value);
|
const { muted } = checkMutes(appearNote);
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,34 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import { inject, ref } from 'vue';
|
import { computed, inject, ref } from 'vue';
|
||||||
import type { Ref } from 'vue';
|
import type { Ref, ComputedRef } from 'vue';
|
||||||
import { $i } from '@/i';
|
import { $i } from '@/i';
|
||||||
|
|
||||||
export function checkMutes(noteToCheck: Misskey.entities.Note, withHardMute = false) {
|
export function checkMutes(noteToCheck: ComputedRef<Misskey.entities.Note>, withHardMute?: ComputedRef<boolean>) {
|
||||||
const muted = ref(checkMute(noteToCheck, $i?.mutedWords));
|
const muteEnable = ref(true);
|
||||||
const hardMuted = ref(withHardMute && checkMute(noteToCheck, $i?.hardMutedWords, true));
|
|
||||||
return { muted, hardMuted };
|
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;
|
export function checkMute(note: Misskey.entities.Note, mutes: undefined | null): false;
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ muted: "Muted"
|
||||||
renoteMute: "Mute Boosts"
|
renoteMute: "Mute Boosts"
|
||||||
renoteMuted: "Boosts muted"
|
renoteMuted: "Boosts muted"
|
||||||
renoteUnmute: "Unmute Boosts"
|
renoteUnmute: "Unmute Boosts"
|
||||||
|
userSaysSomethingInMutedThread: "{name} said something in a muted thread"
|
||||||
markAsNSFW: "Mark all media from user as NSFW"
|
markAsNSFW: "Mark all media from user as NSFW"
|
||||||
markInstanceAsNSFW: "Mark as NSFW"
|
markInstanceAsNSFW: "Mark as NSFW"
|
||||||
nsfwConfirm: "Are you sure that you want to mark all media from this account as NSFW?"
|
nsfwConfirm: "Are you sure that you want to mark all media from this account as NSFW?"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue