This commit is contained in:
FineArchs 2025-04-24 11:55:56 +09:00
parent 51ec1914f9
commit 2d4c0880bb
8 changed files with 86 additions and 48 deletions

20
locales/index.d.ts vendored
View File

@ -2158,6 +2158,26 @@ export interface Locale extends ILocale {
* {x} * {x}
*/ */
"limitTo": ParameterizedString<"x">; "limitTo": ParameterizedString<"x">;
/**
*
*/
"collapsingNoteSize": string;
/**
*
*/
"collapsingNoteCondition": string;
/**
*
*/
"detailedCalculation": string;
/**
*
*/
"legacyCalculation": string;
/**
*
*/
"seeRenderedSize": string;
/** /**
* *
*/ */

View File

@ -125,7 +125,6 @@ import EmUserName from '@/components/EmUserName.vue';
import EmTime from '@/components/EmTime.vue'; import EmTime from '@/components/EmTime.vue';
import { userPage } from '@/utils.js'; import { userPage } from '@/utils.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { shouldCollapsed } from '@@/js/collapsed.js';
function getAppearNote(note: Misskey.entities.Note) { function getAppearNote(note: Misskey.entities.Note) {
return Misskey.note.isPureRenote(note) ? note.renote : note; return Misskey.note.isPureRenote(note) ? note.renote : note;

View File

@ -84,6 +84,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" class="_selectable"/> <Mfm :text="translation.text" :author="appearNote.user" :nyaize="'respect'" :emojiUrls="appearNote.emojis" class="_selectable"/>
</div> </div>
</div> </div>
</div>
<div v-if="appearNote.files && appearNote.files.length > 0"> <div v-if="appearNote.files && appearNote.files.length > 0">
<MkMediaList ref="galleryEl" :mediaList="appearNote.files"/> <MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
</div> </div>
@ -181,7 +182,7 @@ import { computed, inject, onMounted, ref, useTemplateRef, watch, provide } from
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { isLink } from '@@/js/is-link.js'; import { isLink } from '@@/js/is-link.js';
import { shouldCollapsed } from '@@/js/collapsed.js'; import { shouldCollapsedLegacy, shouldCollapsed } from '@@/js/collapsed.js';
import { host } from '@@/js/config.js'; import { host } from '@@/js/config.js';
import type { Ref } from 'vue'; import type { Ref } from 'vue';
import type { MenuItem } from '@/types/menu.js'; import type { MenuItem } from '@/types/menu.js';
@ -218,7 +219,6 @@ import { claimAchievement } from '@/utility/achievements.js';
import { getNoteSummary } from '@/utility/get-note-summary.js'; import { getNoteSummary } from '@/utility/get-note-summary.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue'; import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { showMovedDialog } from '@/utility/show-moved-dialog.js'; import { showMovedDialog } from '@/utility/show-moved-dialog.js';
import { shouldCollapsedLegacy, shouldCollapsed } from '@@/js/collapsed.js';
import { isEnabledUrlPreview } from '@/instance.js'; import { isEnabledUrlPreview } from '@/instance.js';
import { focusPrev, focusNext } from '@/utility/focus.js'; import { focusPrev, focusNext } from '@/utility/focus.js';
import { getAppearNote } from '@/utility/get-appear-note.js'; import { getAppearNote } from '@/utility/get-appear-note.js';
@ -249,17 +249,6 @@ const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', nul
const note = ref(deepClone(props.note)); const note = ref(deepClone(props.note));
// used later
const collapsingNoteCondition = defaultStore.state.collapsingNoteCondition;
if (collapsingNoteCondition === 'seeRenderedSize') {
onMounted(() => {
const current = collapsibleArea.value.clientHeight;
const limit = collapseSize * parseFloat(getComputedStyle(collapsibleArea.value).fontSize);
isLong.value = current > limit;
collapsed.value &&= isLong.value;
});
}
// plugin // plugin
const noteViewInterruptors = getPluginHandlers('note_view_interruptor'); const noteViewInterruptors = getPluginHandlers('note_view_interruptor');
if (noteViewInterruptors.length > 0) { if (noteViewInterruptors.length > 0) {
@ -310,8 +299,9 @@ const renoteCollapsed = ref(
); );
// oversized note collapsing // oversized note collapsing
const collapsibleArea = ref(null); const collapsibleArea = useTemplateRef('collapsibleArea');
const collapseSize = defaultStore.state.collapsingNoteSize; const collapsingNoteCondition = prefer.s.collapsingNoteCondition;
const collapseSize = prefer.s.collapsingNoteSize;
const isLong = ref(true); const isLong = ref(true);
switch (collapsingNoteCondition) { switch (collapsingNoteCondition) {
case 'detailedCalculation': case 'detailedCalculation':
@ -326,6 +316,15 @@ switch (collapsingNoteCondition) {
break; break;
} }
const collapsed = ref(appearNote.value.cw == null && isLong.value); const collapsed = ref(appearNote.value.cw == null && isLong.value);
// v-size使
if (collapsingNoteCondition === 'seeRenderedSize') {
onMounted(() => {
const current = collapsibleArea.value.clientHeight;
const limit = collapseSize * parseFloat(getComputedStyle(collapsibleArea.value).fontSize);
isLong.value = current > limit;
collapsed.value &&= isLong.value;
});
}
const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({ const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
type: 'lookup', type: 'lookup',

View File

@ -32,14 +32,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted } from 'vue'; import { ref, computed, onMounted, useTemplateRef } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import * as mfm from 'mfm-js'; import * as mfm from 'mfm-js';
import { shouldCollapsedLegacy, shouldCollapsed } from '@@/js/collapsed.js'; import { shouldCollapsedLegacy, shouldCollapsed } from '@@/js/collapsed.js';
import MkMediaList from '@/components/MkMediaList.vue'; import MkMediaList from '@/components/MkMediaList.vue';
import MkPoll from '@/components/MkPoll.vue'; import MkPoll from '@/components/MkPoll.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js'; // prefer import { prefer } from '@/preferences.js';
const props = defineProps<{ const props = defineProps<{
note: Misskey.entities.Note; note: Misskey.entities.Note;
@ -48,9 +48,24 @@ const props = defineProps<{
const ast = computed(() => props.note.text ? mfm.parse(props.note.text) : []); const ast = computed(() => props.note.text ? mfm.parse(props.note.text) : []);
// oversized note collapsing // oversized note collapsing
const collapsingNoteCondition = defaultStore.state.collapsingNoteCondition; const collapsibleArea = useTemplateRef('collapsibleArea');
const collapseSize = defaultStore.state.collapsingNoteSize; const collapsingNoteCondition = prefer.s.collapsingNoteCondition;
const collapsibleArea = ref(null); const collapseSize = prefer.s.collapsingNoteSize;
const isLong = ref(true);
switch (collapsingNoteCondition) {
case 'detailedCalculation':
isLong.value = shouldCollapsed(props.note, collapseSize, ast.value);
break;
case 'seeRenderedSize':
break;
// fail safe
case 'legacyCalculation':
default:
isLong.value = shouldCollapsedLegacy(props.note, []);
break;
}
const collapsed = ref(isLong.value);
// v-size使
if (collapsingNoteCondition === 'seeRenderedSize') { if (collapsingNoteCondition === 'seeRenderedSize') {
onMounted(() => { onMounted(() => {
const current = collapsibleArea.value.clientHeight; const current = collapsibleArea.value.clientHeight;
@ -59,22 +74,6 @@ if (collapsingNoteCondition === 'seeRenderedSize') {
collapsed.value &&= isLong.value; collapsed.value &&= isLong.value;
}); });
} }
const isLong = ref(true);
switch (collapsingNoteCondition) {
case 'detailedCalculation':
// eslint-disable-next-line vue/no-setup-props-destructure
isLong.value = shouldCollapsed(props.note, collapseSize, ast.value);
break;
case 'seeRenderedSize':
break;
// fail safe
case 'legacyCalculation':
default:
// eslint-disable-next-line vue/no-setup-props-destructure
isLong.value = shouldCollapsedLegacy(props.note, []);
break;
}
const collapsed = ref(isLong.value);
</script> </script>
<style lang="scss" module> <style lang="scss" module>

View File

@ -250,6 +250,27 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkPreferenceContainer> </MkPreferenceContainer>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['size', 'height']">
<MkPreferenceContainer k="collapsingNoteCondition">
<MkRadios v-model="collapsingNoteCondition">
<template #label><SearchLabel>{{ i18n.ts.collapsingNoteCondition }}</SearchLabel></template>
<option value="detailedCalculation">{{ i18n.ts.detailedCalculation }}</option>
<option value="legacyCalculation">{{ i18n.ts.legacyCalculation }}</option>
<option value="seeRenderedSize">{{ i18n.ts.seeRenderedSize }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<!-- collapsingNoteConditionの付属条件として扱いこれ自体は検索で出ないようにする -->
<MkPreferenceContainer v-if="collapsingNoteCondition !== 'legacyCalculation'" k="collapsingNoteSize">
<MkRadios v-model="collapsingNoteSize">
<template #label>{{ i18n.ts.collapsingNoteSize }}</template>
<option value="9">{{ i18n.ts.small }}</option>
<option value="13.5">{{ i18n.ts.medium }}</option>
<option value="18">{{ i18n.ts.large }}</option>
</MkRadios>
</MkPreferenceContainer>
<SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']"> <SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']">
<MkPreferenceContainer k="instanceTicker"> <MkPreferenceContainer k="instanceTicker">
<MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker"> <MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker">
@ -773,6 +794,8 @@ const notificationStackAxis = prefer.model('notificationStackAxis');
const instanceTicker = prefer.model('instanceTicker'); const instanceTicker = prefer.model('instanceTicker');
const highlightSensitiveMedia = prefer.model('highlightSensitiveMedia'); const highlightSensitiveMedia = prefer.model('highlightSensitiveMedia');
const mediaListWithOneImageAppearance = prefer.model('mediaListWithOneImageAppearance'); const mediaListWithOneImageAppearance = prefer.model('mediaListWithOneImageAppearance');
const collapsingNoteCondition = prefer.model('collapsingNoteCondition');
const collapsingNoteSize = prefer.model('collapsingNoteSize');
const reactionsDisplaySize = prefer.model('reactionsDisplaySize'); const reactionsDisplaySize = prefer.model('reactionsDisplaySize');
const limitWidthOfReaction = prefer.model('limitWidthOfReaction'); const limitWidthOfReaction = prefer.model('limitWidthOfReaction');
const squareAvatars = prefer.model('squareAvatars'); const squareAvatars = prefer.model('squareAvatars');

View File

@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
</div> </div>
</div> </div>
<div v-else ref="noteTextEl" :class="[$style.text, { [$style.collapsed]: shouldCollapsed }]"> <div v-else ref="noteTextEl" :class="[$style.text, { [$style.collapsed]: shouldCollapse }]">
<MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA> <MkA v-if="note.replyId" class="reply" :to="`/notes/${note.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
<Mfm v-if="note.text" :text="note.text" :author="note.user"/> <Mfm v-if="note.text" :text="note.text" :author="note.user"/>
<MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA> <MkA v-if="note.renoteId" class="rp" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
@ -46,14 +46,14 @@ defineProps<{
}>(); }>();
const noteTextEl = useTemplateRef('noteTextEl'); const noteTextEl = useTemplateRef('noteTextEl');
const shouldCollapsed = ref(false); const shouldCollapse = ref(false);
const showContent = ref(false); const showContent = ref(false);
function calcCollapse() { function calcCollapse() {
if (noteTextEl.value) { if (noteTextEl.value) {
const height = noteTextEl.value.scrollHeight; const height = noteTextEl.value.scrollHeight;
if (height > 200) { if (height > 200) {
shouldCollapsed.value = true; shouldCollapse.value = true;
} }
} }
} }

View File

@ -265,6 +265,12 @@ export const PREF_DEF = {
mediaListWithOneImageAppearance: { mediaListWithOneImageAppearance: {
default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3', default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3',
}, },
collapsingNoteCondition: {
default: 'detailedCalculation' as 'detailedCalculation' | 'legacyCalculation' | 'seeRenderedSize',
},
collapsingNoteSize: {
default: 13.5,
},
notificationPosition: { notificationPosition: {
default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom', default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom',
}, },

View File

@ -358,14 +358,6 @@ export const store = markRaw(new Pizzax('base', {
where: 'device', where: 'device',
default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3', default: 'expand' as 'expand' | '16_9' | '1_1' | '2_3',
}, },
collapsingNoteSize: {
where: 'device',
default: 13.5,
},
collapsingNoteCondition: {
where: 'device',
default: 'detailedCalculation' as 'detailedCalculation' | 'legacyCalculation' | 'seeRenderedSize',
},
notificationPosition: { notificationPosition: {
where: 'device', where: 'device',
default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom', default: 'rightBottom' as 'leftTop' | 'leftBottom' | 'rightTop' | 'rightBottom',