fix bulk expand mute

This commit is contained in:
Hazelnoot 2025-06-28 18:38:43 -04:00
parent 40695c7925
commit 4847257011
11 changed files with 201 additions and 73 deletions

View file

@ -14,7 +14,7 @@ Displays a note with either Misskey or Sharkey style, based on user preference.
:withHardMute="withHardMute"
@reaction="emoji => emit('reaction', emoji)"
@removeReaction="emoji => emit('removeReaction', emoji)"
@expandCW="n => emit('expandCW', n)"
@expandMute="n => emit('expandMute', n)"
/>
</template>
@ -45,6 +45,6 @@ defineProps<{
const emit = defineEmits<{
(ev: 'reaction', emoji: string): void;
(ev: 'removeReaction', emoji: string): void;
(ev: 'expandCW', note: Misskey.entities.Note): void;
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
</script>

View file

@ -11,30 +11,61 @@ Displays a note in the detailed view with either Misskey or Sharkey style, based
:note="note"
:initialTab="initialTab"
:expandAllCws="expandAllCws"
@expandMute="n => onExpandNote(n)"
/>
</template>
<script setup lang="ts">
import * as Misskey from 'misskey-js';
import { computed, defineAsyncComponent, useTemplateRef } from 'vue';
import { defineAsyncComponent, useTemplateRef } from 'vue';
import type { ComponentExposed } from 'vue-component-type-helpers';
import type MkNoteDetailed from '@/components/MkNoteDetailed.vue';
import type SkNoteDetailed from '@/components/SkNoteDetailed.vue';
import { prefer } from '@/preferences';
import { useMuteOverrides } from '@/utility/check-word-mute';
import { deepAssign } from '@/utility/merge';
const XNoteDetailed = defineAsyncComponent(() =>
prefer.s.noteDesign === 'misskey'
? import('@/components/MkNoteDetailed.vue')
: import('@/components/SkNoteDetailed.vue'),
);
? import('@/components/MkNoteDetailed.vue')
: import('@/components/SkNoteDetailed.vue'));
const rootEl = useTemplateRef<ComponentExposed<typeof MkNoteDetailed | typeof SkNoteDetailed>>('rootEl');
const muteOverrides = useMuteOverrides();
defineExpose({ rootEl });
defineProps<{
const props = defineProps<{
note: Misskey.entities.Note;
initialTab?: string;
expandAllCws?: boolean;
}>();
// TODO map to expand all CWs?
const emit = defineEmits<{
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
function onExpandNote(note: Misskey.entities.Note) {
// Since this is a Detailed note, note.props must point to the top of a thread.
// Go ahead and expand matching user/instance/thread mutes downstream, since the user is very likely to want them.
if (note.id === props.note.id) {
deepAssign(muteOverrides, {
user: {
[note.user.id]: {
userMandatoryCW: null,
instanceMandatoryCW: null,
},
},
thread: {
[note.threadId]: {
threadMuted: false,
},
},
});
}
emit('expandMute', note);
}
</script>

View file

@ -12,7 +12,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:withHardMute="withHardMute"
:class="[$style.root, { [$style.showActionsOnlyHover]: prefer.s.showNoteActionsOnlyHover, [$style.skipRender]: prefer.s.skipNoteRender }]"
:tabindex="isDeleted ? '-1' : '0'"
@expand="n => emit('expandCW', n)"
@expandMute="n => emit('expandMute', n)"
>
<div v-if="appearNote.reply && inReplyToCollapsed" :class="$style.collapsedInReplyTo">
<MkAvatar :class="$style.collapsedInReplyToAvatar" :user="appearNote.reply.user" link preview/>
@ -245,7 +245,7 @@ provide(DI.mock, props.mock);
const emit = defineEmits<{
(ev: 'reaction', emoji: string): void;
(ev: 'removeReaction', emoji: string): void;
(ev: 'expandCW', note: Misskey.entities.Note): void;
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
const router = useRouter();

View file

@ -11,6 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
:note="appearNote"
:class="$style.root"
:tabindex="isDeleted ? '-1' : '0'"
@expandMute="n => emit('expandMute', n)"
>
<div v-if="appearNote.reply && appearNote.reply.replyId">
<div v-if="!conversationLoaded" style="padding: 16px">
@ -292,6 +293,10 @@ const props = withDefaults(defineProps<{
initialTab: 'replies',
});
const emit = defineEmits<{
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
const inChannel = inject('inChannel', null);
const note = ref(deepClone(props.note));

View file

@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #default="{ items: notes }">
<div :class="[$style.root, { [$style.noGap]: noGap, '_gaps': !noGap, [$style.reverse]: pagination.reversed }]">
<template v-for="(note, i) in notes" :key="note.id">
<DynamicNote :class="$style.note" :note="note as Misskey.entities.Note" :withHardMute="true" :data-scroll-anchor="note.id"/>
<DynamicNote :class="$style.note" :note="note as Misskey.entities.Note" :withHardMute="true" :data-scroll-anchor="note.id" @expandMute="n => emit('expandMute', n)"/>
<MkAd v-if="note._shouldInsertAd_" :preferForms="['horizontal', 'horizontal-big']" :class="$style.ad"/>
</template>
</div>
@ -37,6 +37,10 @@ const pagingComponent = useTemplateRef('pagingComponent');
defineExpose({
pagingComponent,
});
const emit = defineEmits<{
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
</script>
<style lang="scss" module>

View file

@ -94,20 +94,19 @@ const props = withDefaults(defineProps<{
});
const emit = defineEmits<{
(type: 'expand', note: Misskey.entities.Note): void;
(type: 'expandMute', note: Misskey.entities.Note): void;
}>();
const expandNote = ref(false);
function expand() {
expandNote.value = true;
emit('expand', props.note);
emit('expandMute', props.note);
}
const mute = computed(() => checkMute(props.note, props.withHardMute));
const mute = checkMute(computed(() => props.note), computed(() => props.withHardMute));
const mutedWords = computed(() => mute.value.softMutedWords?.join(', '));
const isMuted = computed(() => mute.value.hardMuted || mutedWords.value || mute.value.noteMandatoryCW || mute.value.userMandatoryCW || mute.value.instanceMandatoryCW || mute.value.noteMuted || mute.value.threadMuted || mute.value.sensitiveMuted);
const isExpanded = computed(() => expandNote.value || !isMuted.value);
const isExpanded = computed(() => expandNote.value || !mute.value.hasMute);
const rootClass = computed(() => isExpanded.value ? props.expandedClass : undefined);
const rootEl = useTemplateRef('rootEl');

View file

@ -14,7 +14,7 @@ Displays a note in the Sharkey style. Used to show the "main" note in a given co
:withHardMute="withHardMute"
:class="[$style.root, { [$style.showActionsOnlyHover]: prefer.s.showNoteActionsOnlyHover, [$style.skipRender]: prefer.s.skipNoteRender }]"
:tabindex="isDeleted ? '-1' : '0'"
@expand="n => emit('expandCW', n)"
@expandMute="n => emit('expandMute', n)"
>
<SkNoteSub v-if="appearNote.reply" v-show="!renoteCollapsed && !inReplyToCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
<div v-if="appearNote.reply && inReplyToCollapsed && !renoteCollapsed" :class="$style.collapsedInReplyTo">
@ -246,7 +246,7 @@ provide(DI.mock, props.mock);
const emit = defineEmits<{
(ev: 'reaction', emoji: string): void;
(ev: 'removeReaction', emoji: string): void;
(ev: 'expandCW', note: Misskey.entities.Note): void;
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
const router = useRouter();

View file

@ -13,6 +13,7 @@ Detailed view of a note in the Sharkey style. Used when opening a note onto its
:note="appearNote"
:class="$style.root"
:tabindex="isDeleted ? '-1' : '0'"
@expandMute="n => emit('expandMute', n)"
>
<div v-if="appearNote.reply && appearNote.reply.replyId && !conversationLoaded" style="padding: 16px">
<MkButton style="margin: 0 auto;" primary rounded @click="loadConversation">{{ i18n.ts.loadConversation }}</MkButton>
@ -297,6 +298,10 @@ const props = withDefaults(defineProps<{
initialTab: 'replies',
});
const emit = defineEmits<{
(ev: 'expandMute', note: Misskey.entities.Note): void;
}>();
const inChannel = inject('inChannel', null);
const note = ref(deepClone(props.note));