enhance(frontend): re-organize settings page

This commit is contained in:
syuilo 2025-03-13 19:30:35 +09:00
parent 3280a3d661
commit 0126dba475
6 changed files with 568 additions and 597 deletions

View File

@ -140,11 +140,6 @@ const menuDef = computed<SuperMenuDef[]>(() => [{
text: i18n.ts.drive, text: i18n.ts.drive,
to: '/settings/drive', to: '/settings/drive',
active: currentPage.value?.route.name === 'drive', active: currentPage.value?.route.name === 'drive',
}, {
icon: 'ti ti-badges',
text: i18n.ts.roles,
to: '/settings/roles',
active: currentPage.value?.route.name === 'roles',
}, { }, {
icon: 'ti ti-ban', icon: 'ti ti-ban',
text: i18n.ts.muteAndBlock, text: i18n.ts.muteAndBlock,

View File

@ -33,10 +33,30 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #key>{{ i18n.ts.registeredDate }}</template> <template #key>{{ i18n.ts.registeredDate }}</template>
<template #value><MkTime :time="$i.createdAt" mode="detail"/></template> <template #value><MkTime :time="$i.createdAt" mode="detail"/></template>
</MkKeyValue> </MkKeyValue>
<MkFolder>
<template #icon><i class="ti ti-badges"></i></template>
<template #label><SearchLabel>{{ i18n.ts._role.policies }}</SearchLabel></template>
<div class="_gaps_s">
<div v-for="policy in Object.keys($i.policies)" :key="policy">
{{ policy }} ... {{ $i.policies[policy] }}
</div>
</div>
</MkFolder>
</div> </div>
</MkFolder> </MkFolder>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['roles']">
<MkFolder>
<template #icon><i class="ti ti-badges"></i></template>
<template #label><SearchLabel>{{ i18n.ts.rolesAssignedToMe }}</SearchLabel></template>
<MkRolePreview v-for="role in $i.roles" :key="role.id" :role="role" :forModeration="false"/>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['account', 'move', 'migration']"> <SearchMarker :keywords="['account', 'move', 'migration']">
<MkFolder> <MkFolder>
<template #icon><i class="ti ti-plane"></i></template> <template #icon><i class="ti ti-plane"></i></template>
@ -124,6 +144,7 @@ import { definePage } from '@/page.js';
import { reloadAsk } from '@/utility/reload-ask.js'; import { reloadAsk } from '@/utility/reload-ask.js';
import FormSection from '@/components/form/section.vue'; import FormSection from '@/components/form/section.vue';
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import MkRolePreview from '@/components/MkRolePreview.vue';
const $i = signinRequired(); const $i = signinRequired();

View File

@ -10,510 +10,512 @@ SPDX-License-Identifier: AGPL-3.0-only
<SearchKeyword>{{ i18n.ts._settings.preferencesBanner }}</SearchKeyword> <SearchKeyword>{{ i18n.ts._settings.preferencesBanner }}</SearchKeyword>
</MkFeatureBanner> </MkFeatureBanner>
<SearchMarker :keywords="['general']"> <div class="_gaps_s">
<MkFolder :defaultOpen="true"> <SearchMarker :keywords="['general']">
<template #label><SearchLabel>{{ i18n.ts.general }}</SearchLabel></template> <MkFolder>
<template #label><SearchLabel>{{ i18n.ts.general }}</SearchLabel></template>
<div class="_gaps_m"> <div class="_gaps_m">
<SearchMarker :keywords="['language']"> <SearchMarker :keywords="['language']">
<MkSelect v-model="lang"> <MkSelect v-model="lang">
<template #label><SearchLabel>{{ i18n.ts.uiLanguage }}</SearchLabel></template> <template #label><SearchLabel>{{ i18n.ts.uiLanguage }}</SearchLabel></template>
<option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option> <option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option>
<template #caption> <template #caption>
<I18n :src="i18n.ts.i18nInfo" tag="span"> <I18n :src="i18n.ts.i18nInfo" tag="span">
<template #link> <template #link>
<MkLink url="https://crowdin.com/project/misskey">Crowdin</MkLink> <MkLink url="https://crowdin.com/project/misskey">Crowdin</MkLink>
</template> </template>
</I18n> </I18n>
</template> </template>
</MkSelect>
</SearchMarker>
<SearchMarker :keywords="['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop']">
<MkRadios v-model="overridedDeviceKind">
<template #label><SearchLabel>{{ i18n.ts.overridedDeviceKind }}</SearchLabel></template>
<option :value="null">{{ i18n.ts.auto }}</option>
<option value="smartphone"><i class="ti ti-device-mobile"/> {{ i18n.ts.smartphone }}</option>
<option value="tablet"><i class="ti ti-device-tablet"/> {{ i18n.ts.tablet }}</option>
<option value="desktop"><i class="ti ti-device-desktop"/> {{ i18n.ts.desktop }}</option>
</MkRadios>
</SearchMarker>
<div class="_gaps_s">
<SearchMarker :keywords="['blur']">
<MkPreferenceContainer k="useBlurEffect">
<MkSwitch v-model="useBlurEffect">
<template #label><SearchLabel>{{ i18n.ts.useBlurEffect }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['blur', 'modal']">
<MkPreferenceContainer k="useBlurEffectForModal">
<MkSwitch v-model="useBlurEffectForModal">
<template #label><SearchLabel>{{ i18n.ts.useBlurEffectForModal }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['avatar', 'icon', 'decoration', 'show']">
<MkPreferenceContainer k="showAvatarDecorations">
<MkSwitch v-model="showAvatarDecorations">
<template #label><SearchLabel>{{ i18n.ts.showAvatarDecorations }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['follow', 'confirm', 'always']">
<MkPreferenceContainer k="alwaysConfirmFollow">
<MkSwitch v-model="alwaysConfirmFollow">
<template #label><SearchLabel>{{ i18n.ts.alwaysConfirmFollow }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail']">
<MkPreferenceContainer k="highlightSensitiveMedia">
<MkSwitch v-model="highlightSensitiveMedia">
<template #label><SearchLabel>{{ i18n.ts.highlightSensitiveMedia }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm']">
<MkPreferenceContainer k="confirmWhenRevealingSensitiveMedia">
<MkSwitch v-model="confirmWhenRevealingSensitiveMedia">
<template #label><SearchLabel>{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['emoji', 'style', 'native', 'system', 'fluent', 'twemoji']">
<MkPreferenceContainer k="emojiStyle">
<div>
<MkRadios v-model="emojiStyle">
<template #label><SearchLabel>{{ i18n.ts.emojiStyle }}</SearchLabel></template>
<option value="native">{{ i18n.ts.native }}</option>
<option value="fluentEmoji">Fluent Emoji</option>
<option value="twemoji">Twemoji</option>
</MkRadios>
<div style="margin: 8px 0 0 0; font-size: 1.5em;"><Mfm :key="emojiStyle" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
</div>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['pinned', 'list']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.pinnedList }}</SearchLabel></template>
<!-- 複数ピン止め管理できるようにしたいけどめんどいので一旦ひとつのみ -->
<MkButton v-if="prefer.r.pinnedUserLists.value.length === 0" @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
<MkButton v-else danger @click="removePinnedList()"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
</MkFolder>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['timeline']">
<MkFolder :defaultOpen="true">
<template #label><SearchLabel>{{ i18n.ts.timeline }}</SearchLabel></template>
<div class="_gaps_s">
<SearchMarker :keywords="['post', 'form', 'timeline']">
<MkPreferenceContainer k="showFixedPostForm">
<MkSwitch v-model="showFixedPostForm">
<template #label><SearchLabel>{{ i18n.ts.showFixedPostForm }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['post', 'form', 'timeline', 'channel']">
<MkPreferenceContainer k="showFixedPostFormInChannel">
<MkSwitch v-model="showFixedPostFormInChannel">
<template #label><SearchLabel>{{ i18n.ts.showFixedPostFormInChannel }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['renote']">
<MkPreferenceContainer k="collapseRenotes">
<MkSwitch v-model="collapseRenotes">
<template #label><SearchLabel>{{ i18n.ts.collapseRenotes }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.collapseRenotesDescription }}</SearchKeyword></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['note', 'timeline', 'gap']">
<MkPreferenceContainer k="showGapBetweenNotesInTimeline">
<MkSwitch v-model="showGapBetweenNotesInTimeline">
<template #label><SearchLabel>{{ i18n.ts.showGapBetweenNotesInTimeline }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['load', 'auto', 'more']">
<MkPreferenceContainer k="enableInfiniteScroll">
<MkSwitch v-model="enableInfiniteScroll">
<template #label><SearchLabel>{{ i18n.ts.enableInfiniteScroll }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['disable', 'streaming', 'timeline']">
<MkPreferenceContainer k="disableStreamingTimeline">
<MkSwitch v-model="disableStreamingTimeline">
<template #label><SearchLabel>{{ i18n.ts.disableStreamingTimeline }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['note']">
<MkFolder :defaultOpen="true">
<template #label><SearchLabel>{{ i18n.ts.note }}</SearchLabel></template>
<div class="_gaps_m">
<div class="_gaps_s">
<SearchMarker :keywords="['hover', 'show', 'footer', 'action']">
<MkPreferenceContainer k="showNoteActionsOnlyHover">
<MkSwitch v-model="showNoteActionsOnlyHover">
<template #label><SearchLabel>{{ i18n.ts.showNoteActionsOnlyHover }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['footer', 'action', 'clip', 'show']">
<MkPreferenceContainer k="showClipButtonInNoteFooter">
<MkSwitch v-model="showClipButtonInNoteFooter">
<template #label><SearchLabel>{{ i18n.ts.showClipButtonInNoteFooter }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['mfm', 'enable', 'show', 'advanced']">
<MkPreferenceContainer k="advancedMfm">
<MkSwitch v-model="advancedMfm">
<template #label><SearchLabel>{{ i18n.ts.enableAdvancedMfm }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'count', 'show']">
<MkPreferenceContainer k="showReactionsCount">
<MkSwitch v-model="showReactionsCount">
<template #label><SearchLabel>{{ i18n.ts.showReactionsCount }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'confirm']">
<MkPreferenceContainer k="confirmOnReact">
<MkSwitch v-model="confirmOnReact">
<template #label><SearchLabel>{{ i18n.ts.confirmOnReact }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment']">
<MkPreferenceContainer k="loadRawImages">
<MkSwitch v-model="loadRawImages">
<template #label><SearchLabel>{{ i18n.ts.loadRawImages }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'picker', 'contextmenu', 'open']">
<MkPreferenceContainer k="useReactionPickerForContextMenu">
<MkSwitch v-model="useReactionPickerForContextMenu">
<template #label><SearchLabel>{{ i18n.ts.useReactionPickerForContextMenu }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display']">
<MkPreferenceContainer k="reactionsDisplaySize">
<MkRadios v-model="reactionsDisplaySize">
<template #label><SearchLabel>{{ i18n.ts.reactionsDisplaySize }}</SearchLabel></template>
<option value="small">{{ i18n.ts.small }}</option>
<option value="medium">{{ i18n.ts.medium }}</option>
<option value="large">{{ i18n.ts.large }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display', 'width', 'limit']">
<MkPreferenceContainer k="limitWidthOfReaction">
<MkSwitch v-model="limitWidthOfReaction">
<template #label><SearchLabel>{{ i18n.ts.limitWidthOfReaction }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height']">
<MkPreferenceContainer k="mediaListWithOneImageAppearance">
<MkRadios v-model="mediaListWithOneImageAppearance">
<template #label><SearchLabel>{{ i18n.ts.mediaListWithOneImageAppearance }}</SearchLabel></template>
<option value="expand">{{ i18n.ts.default }}</option>
<option value="16_9">{{ i18n.tsx.limitTo({ x: '16:9' }) }}</option>
<option value="1_1">{{ i18n.tsx.limitTo({ x: '1:1' }) }}</option>
<option value="2_3">{{ i18n.tsx.limitTo({ x: '2:3' }) }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']">
<MkPreferenceContainer k="instanceTicker">
<MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker">
<template #label><SearchLabel>{{ i18n.ts.instanceTicker }}</SearchLabel></template>
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
<option value="remote">{{ i18n.ts._instanceTicker.remote }}</option>
<option value="always">{{ i18n.ts._instanceTicker.always }}</option>
</MkSelect> </MkSelect>
</MkPreferenceContainer> </SearchMarker>
</SearchMarker>
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility']"> <SearchMarker :keywords="['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop']">
<MkPreferenceContainer k="nsfw"> <MkRadios v-model="overridedDeviceKind">
<MkSelect v-model="nsfw"> <template #label><SearchLabel>{{ i18n.ts.overridedDeviceKind }}</SearchLabel></template>
<template #label><SearchLabel>{{ i18n.ts.displayOfSensitiveMedia }}</SearchLabel></template> <option :value="null">{{ i18n.ts.auto }}</option>
<option value="respect">{{ i18n.ts._displayOfSensitiveMedia.respect }}</option> <option value="smartphone"><i class="ti ti-device-mobile"/> {{ i18n.ts.smartphone }}</option>
<option value="ignore">{{ i18n.ts._displayOfSensitiveMedia.ignore }}</option> <option value="tablet"><i class="ti ti-device-tablet"/> {{ i18n.ts.tablet }}</option>
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option> <option value="desktop"><i class="ti ti-device-desktop"/> {{ i18n.ts.desktop }}</option>
</MkSelect> </MkRadios>
</MkPreferenceContainer> </SearchMarker>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['post', 'form']"> <div class="_gaps_s">
<MkFolder :defaultOpen="true"> <SearchMarker :keywords="['blur']">
<template #label><SearchLabel>{{ i18n.ts.postForm }}</SearchLabel></template> <MkPreferenceContainer k="useBlurEffect">
<MkSwitch v-model="useBlurEffect">
<template #label><SearchLabel>{{ i18n.ts.useBlurEffect }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<div class="_gaps_m"> <SearchMarker :keywords="['blur', 'modal']">
<div class="_gaps_s"> <MkPreferenceContainer k="useBlurEffectForModal">
<SearchMarker :keywords="['remember', 'keep', 'note', 'cw']"> <MkSwitch v-model="useBlurEffectForModal">
<MkPreferenceContainer k="keepCw"> <template #label><SearchLabel>{{ i18n.ts.useBlurEffectForModal }}</SearchLabel></template>
<MkSwitch v-model="keepCw"> </MkSwitch>
<template #label><SearchLabel>{{ i18n.ts.keepCw }}</SearchLabel></template> </MkPreferenceContainer>
</MkSwitch> </SearchMarker>
<SearchMarker :keywords="['avatar', 'icon', 'decoration', 'show']">
<MkPreferenceContainer k="showAvatarDecorations">
<MkSwitch v-model="showAvatarDecorations">
<template #label><SearchLabel>{{ i18n.ts.showAvatarDecorations }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['follow', 'confirm', 'always']">
<MkPreferenceContainer k="alwaysConfirmFollow">
<MkSwitch v-model="alwaysConfirmFollow">
<template #label><SearchLabel>{{ i18n.ts.alwaysConfirmFollow }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail']">
<MkPreferenceContainer k="highlightSensitiveMedia">
<MkSwitch v-model="highlightSensitiveMedia">
<template #label><SearchLabel>{{ i18n.ts.highlightSensitiveMedia }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm']">
<MkPreferenceContainer k="confirmWhenRevealingSensitiveMedia">
<MkSwitch v-model="confirmWhenRevealingSensitiveMedia">
<template #label><SearchLabel>{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['emoji', 'style', 'native', 'system', 'fluent', 'twemoji']">
<MkPreferenceContainer k="emojiStyle">
<div>
<MkRadios v-model="emojiStyle">
<template #label><SearchLabel>{{ i18n.ts.emojiStyle }}</SearchLabel></template>
<option value="native">{{ i18n.ts.native }}</option>
<option value="fluentEmoji">Fluent Emoji</option>
<option value="twemoji">Twemoji</option>
</MkRadios>
<div style="margin: 8px 0 0 0; font-size: 1.5em;"><Mfm :key="emojiStyle" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
</div>
</MkPreferenceContainer> </MkPreferenceContainer>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['remember', 'keep', 'note', 'visibility']"> <SearchMarker :keywords="['pinned', 'list']">
<MkPreferenceContainer k="rememberNoteVisibility">
<MkSwitch v-model="rememberNoteVisibility">
<template #label><SearchLabel>{{ i18n.ts.rememberNoteVisibility }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn']">
<MkPreferenceContainer k="enableQuickAddMfmFunction">
<MkSwitch v-model="enableQuickAddMfmFunction">
<template #label><SearchLabel>{{ i18n.ts.enableQuickAddMfmFunction }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['default', 'note', 'visibility']">
<MkDisableSection :disabled="rememberNoteVisibility">
<MkFolder> <MkFolder>
<template #label><SearchLabel>{{ i18n.ts.defaultNoteVisibility }}</SearchLabel></template> <template #label><SearchLabel>{{ i18n.ts.pinnedList }}</SearchLabel></template>
<template v-if="defaultNoteVisibility === 'public'" #suffix>{{ i18n.ts._visibility.public }}</template> <!-- 複数ピン止め管理できるようにしたいけどめんどいので一旦ひとつのみ -->
<template v-else-if="defaultNoteVisibility === 'home'" #suffix>{{ i18n.ts._visibility.home }}</template> <MkButton v-if="prefer.r.pinnedUserLists.value.length === 0" @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
<template v-else-if="defaultNoteVisibility === 'followers'" #suffix>{{ i18n.ts._visibility.followers }}</template> <MkButton v-else danger @click="removePinnedList()"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
<template v-else-if="defaultNoteVisibility === 'specified'" #suffix>{{ i18n.ts._visibility.specified }}</template> </MkFolder>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<div class="_gaps_m"> <SearchMarker :keywords="['timeline']">
<MkPreferenceContainer k="defaultNoteVisibility"> <MkFolder>
<MkSelect v-model="defaultNoteVisibility"> <template #label><SearchLabel>{{ i18n.ts.timeline }}</SearchLabel></template>
<option value="public">{{ i18n.ts._visibility.public }}</option>
<option value="home">{{ i18n.ts._visibility.home }}</option>
<option value="followers">{{ i18n.ts._visibility.followers }}</option>
<option value="specified">{{ i18n.ts._visibility.specified }}</option>
</MkSelect>
</MkPreferenceContainer>
<MkPreferenceContainer k="defaultNoteLocalOnly"> <div class="_gaps_s">
<MkSwitch v-model="defaultNoteLocalOnly">{{ i18n.ts._visibility.disableFederation }}</MkSwitch> <SearchMarker :keywords="['post', 'form', 'timeline']">
</MkPreferenceContainer> <MkPreferenceContainer k="showFixedPostForm">
<MkSwitch v-model="showFixedPostForm">
<template #label><SearchLabel>{{ i18n.ts.showFixedPostForm }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['post', 'form', 'timeline', 'channel']">
<MkPreferenceContainer k="showFixedPostFormInChannel">
<MkSwitch v-model="showFixedPostFormInChannel">
<template #label><SearchLabel>{{ i18n.ts.showFixedPostFormInChannel }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['renote']">
<MkPreferenceContainer k="collapseRenotes">
<MkSwitch v-model="collapseRenotes">
<template #label><SearchLabel>{{ i18n.ts.collapseRenotes }}</SearchLabel></template>
<template #caption><SearchKeyword>{{ i18n.ts.collapseRenotesDescription }}</SearchKeyword></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['note', 'timeline', 'gap']">
<MkPreferenceContainer k="showGapBetweenNotesInTimeline">
<MkSwitch v-model="showGapBetweenNotesInTimeline">
<template #label><SearchLabel>{{ i18n.ts.showGapBetweenNotesInTimeline }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['load', 'auto', 'more']">
<MkPreferenceContainer k="enableInfiniteScroll">
<MkSwitch v-model="enableInfiniteScroll">
<template #label><SearchLabel>{{ i18n.ts.enableInfiniteScroll }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['disable', 'streaming', 'timeline']">
<MkPreferenceContainer k="disableStreamingTimeline">
<MkSwitch v-model="disableStreamingTimeline">
<template #label><SearchLabel>{{ i18n.ts.disableStreamingTimeline }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['note']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.note }}</SearchLabel></template>
<div class="_gaps_m">
<div class="_gaps_s">
<SearchMarker :keywords="['hover', 'show', 'footer', 'action']">
<MkPreferenceContainer k="showNoteActionsOnlyHover">
<MkSwitch v-model="showNoteActionsOnlyHover">
<template #label><SearchLabel>{{ i18n.ts.showNoteActionsOnlyHover }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['footer', 'action', 'clip', 'show']">
<MkPreferenceContainer k="showClipButtonInNoteFooter">
<MkSwitch v-model="showClipButtonInNoteFooter">
<template #label><SearchLabel>{{ i18n.ts.showClipButtonInNoteFooter }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['mfm', 'enable', 'show', 'advanced']">
<MkPreferenceContainer k="advancedMfm">
<MkSwitch v-model="advancedMfm">
<template #label><SearchLabel>{{ i18n.ts.enableAdvancedMfm }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'count', 'show']">
<MkPreferenceContainer k="showReactionsCount">
<MkSwitch v-model="showReactionsCount">
<template #label><SearchLabel>{{ i18n.ts.showReactionsCount }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'confirm']">
<MkPreferenceContainer k="confirmOnReact">
<MkSwitch v-model="confirmOnReact">
<template #label><SearchLabel>{{ i18n.ts.confirmOnReact }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment']">
<MkPreferenceContainer k="loadRawImages">
<MkSwitch v-model="loadRawImages">
<template #label><SearchLabel>{{ i18n.ts.loadRawImages }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'picker', 'contextmenu', 'open']">
<MkPreferenceContainer k="useReactionPickerForContextMenu">
<MkSwitch v-model="useReactionPickerForContextMenu">
<template #label><SearchLabel>{{ i18n.ts.useReactionPickerForContextMenu }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display']">
<MkPreferenceContainer k="reactionsDisplaySize">
<MkRadios v-model="reactionsDisplaySize">
<template #label><SearchLabel>{{ i18n.ts.reactionsDisplaySize }}</SearchLabel></template>
<option value="small">{{ i18n.ts.small }}</option>
<option value="medium">{{ i18n.ts.medium }}</option>
<option value="large">{{ i18n.ts.large }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display', 'width', 'limit']">
<MkPreferenceContainer k="limitWidthOfReaction">
<MkSwitch v-model="limitWidthOfReaction">
<template #label><SearchLabel>{{ i18n.ts.limitWidthOfReaction }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height']">
<MkPreferenceContainer k="mediaListWithOneImageAppearance">
<MkRadios v-model="mediaListWithOneImageAppearance">
<template #label><SearchLabel>{{ i18n.ts.mediaListWithOneImageAppearance }}</SearchLabel></template>
<option value="expand">{{ i18n.ts.default }}</option>
<option value="16_9">{{ i18n.tsx.limitTo({ x: '16:9' }) }}</option>
<option value="1_1">{{ i18n.tsx.limitTo({ x: '1:1' }) }}</option>
<option value="2_3">{{ i18n.tsx.limitTo({ x: '2:3' }) }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation']">
<MkPreferenceContainer k="instanceTicker">
<MkSelect v-if="instance.federation !== 'none'" v-model="instanceTicker">
<template #label><SearchLabel>{{ i18n.ts.instanceTicker }}</SearchLabel></template>
<option value="none">{{ i18n.ts._instanceTicker.none }}</option>
<option value="remote">{{ i18n.ts._instanceTicker.remote }}</option>
<option value="always">{{ i18n.ts._instanceTicker.always }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility']">
<MkPreferenceContainer k="nsfw">
<MkSelect v-model="nsfw">
<template #label><SearchLabel>{{ i18n.ts.displayOfSensitiveMedia }}</SearchLabel></template>
<option value="respect">{{ i18n.ts._displayOfSensitiveMedia.respect }}</option>
<option value="ignore">{{ i18n.ts._displayOfSensitiveMedia.ignore }}</option>
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['post', 'form']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.postForm }}</SearchLabel></template>
<div class="_gaps_m">
<div class="_gaps_s">
<SearchMarker :keywords="['remember', 'keep', 'note', 'cw']">
<MkPreferenceContainer k="keepCw">
<MkSwitch v-model="keepCw">
<template #label><SearchLabel>{{ i18n.ts.keepCw }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['remember', 'keep', 'note', 'visibility']">
<MkPreferenceContainer k="rememberNoteVisibility">
<MkSwitch v-model="rememberNoteVisibility">
<template #label><SearchLabel>{{ i18n.ts.rememberNoteVisibility }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn']">
<MkPreferenceContainer k="enableQuickAddMfmFunction">
<MkSwitch v-model="enableQuickAddMfmFunction">
<template #label><SearchLabel>{{ i18n.ts.enableQuickAddMfmFunction }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['default', 'note', 'visibility']">
<MkDisableSection :disabled="rememberNoteVisibility">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.defaultNoteVisibility }}</SearchLabel></template>
<template v-if="defaultNoteVisibility === 'public'" #suffix>{{ i18n.ts._visibility.public }}</template>
<template v-else-if="defaultNoteVisibility === 'home'" #suffix>{{ i18n.ts._visibility.home }}</template>
<template v-else-if="defaultNoteVisibility === 'followers'" #suffix>{{ i18n.ts._visibility.followers }}</template>
<template v-else-if="defaultNoteVisibility === 'specified'" #suffix>{{ i18n.ts._visibility.specified }}</template>
<div class="_gaps_m">
<MkPreferenceContainer k="defaultNoteVisibility">
<MkSelect v-model="defaultNoteVisibility">
<option value="public">{{ i18n.ts._visibility.public }}</option>
<option value="home">{{ i18n.ts._visibility.home }}</option>
<option value="followers">{{ i18n.ts._visibility.followers }}</option>
<option value="specified">{{ i18n.ts._visibility.specified }}</option>
</MkSelect>
</MkPreferenceContainer>
<MkPreferenceContainer k="defaultNoteLocalOnly">
<MkSwitch v-model="defaultNoteLocalOnly">{{ i18n.ts._visibility.disableFederation }}</MkSwitch>
</MkPreferenceContainer>
</div>
</MkFolder>
</MkDisableSection>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['notification']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.notifications }}</SearchLabel></template>
<div class="_gaps_m">
<SearchMarker :keywords="['group']">
<MkPreferenceContainer k="useGroupedNotifications">
<MkSwitch v-model="useGroupedNotifications">
<template #label><SearchLabel>{{ i18n.ts.useGroupedNotifications }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['position']">
<MkPreferenceContainer k="notificationPosition">
<MkRadios v-model="notificationPosition">
<template #label><SearchLabel>{{ i18n.ts.position }}</SearchLabel></template>
<option value="leftTop"><i class="ti ti-align-box-left-top"></i> {{ i18n.ts.leftTop }}</option>
<option value="rightTop"><i class="ti ti-align-box-right-top"></i> {{ i18n.ts.rightTop }}</option>
<option value="leftBottom"><i class="ti ti-align-box-left-bottom"></i> {{ i18n.ts.leftBottom }}</option>
<option value="rightBottom"><i class="ti ti-align-box-right-bottom"></i> {{ i18n.ts.rightBottom }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['stack', 'axis', 'direction']">
<MkPreferenceContainer k="notificationStackAxis">
<MkRadios v-model="notificationStackAxis">
<template #label><SearchLabel>{{ i18n.ts.stackAxis }}</SearchLabel></template>
<option value="vertical"><i class="ti ti-carousel-vertical"></i> {{ i18n.ts.vertical }}</option>
<option value="horizontal"><i class="ti ti-carousel-horizontal"></i> {{ i18n.ts.horizontal }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<MkButton @click="testNotification">{{ i18n.ts._notification.checkNotificationBehavior }}</MkButton>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['other']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.other }}</SearchLabel></template>
<div class="_gaps_m">
<div class="_gaps_s">
<SearchMarker :keywords="['avatar', 'icon', 'square']">
<MkPreferenceContainer k="squareAvatars">
<MkSwitch v-model="squareAvatars">
<template #label><SearchLabel>{{ i18n.ts.squareAvatars }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['effect', 'show']">
<MkPreferenceContainer k="enableSeasonalScreenEffect">
<MkSwitch v-model="enableSeasonalScreenEffect">
<template #label><SearchLabel>{{ i18n.ts.seasonalScreenEffect }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab']">
<MkPreferenceContainer k="imageNewTab">
<MkSwitch v-model="imageNewTab">
<template #label><SearchLabel>{{ i18n.ts.openImageInNewTab }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['server', 'disconnect', 'reconnect', 'reload', 'streaming']">
<MkPreferenceContainer k="serverDisconnectedBehavior">
<MkSelect v-model="serverDisconnectedBehavior">
<template #label><SearchLabel>{{ i18n.ts.whenServerDisconnected }}</SearchLabel></template>
<option value="reload">{{ i18n.ts._serverDisconnectedBehavior.reload }}</option>
<option value="dialog">{{ i18n.ts._serverDisconnectedBehavior.dialog }}</option>
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['cache', 'page']">
<MkPreferenceContainer k="numberOfPageCache">
<MkRange v-model="numberOfPageCache" :min="1" :max="10" :step="1" easing>
<template #label><SearchLabel>{{ i18n.ts.numberOfPageCache }}</SearchLabel></template>
<template #caption>{{ i18n.ts.numberOfPageCacheDescription }}</template>
</MkRange>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['ad', 'show']">
<MkPreferenceContainer k="forceShowAds">
<MkSwitch v-model="forceShowAds">
<template #label><SearchLabel>{{ i18n.ts.forceShowAds }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker>
<MkPreferenceContainer k="hemisphere">
<MkRadios v-model="hemisphere">
<template #label><SearchLabel>{{ i18n.ts.hemisphere }}</SearchLabel></template>
<option value="N">{{ i18n.ts._hemisphere.N }}</option>
<option value="S">{{ i18n.ts._hemisphere.S }}</option>
<template #caption>{{ i18n.ts._hemisphere.caption }}</template>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['emoji', 'dictionary', 'additional', 'extra']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.additionalEmojiDictionary }}</SearchLabel></template>
<div class="_buttons">
<template v-for="lang in emojiIndexLangs" :key="lang">
<MkButton v-if="store.r.additionalUnicodeEmojiIndexes.value[lang]" danger @click="removeEmojiIndex(lang)"><i class="ti ti-trash"></i> {{ i18n.ts.remove }} ({{ getEmojiIndexLangName(lang) }})</MkButton>
<MkButton v-else @click="downloadEmojiIndex(lang)"><i class="ti ti-download"></i> {{ getEmojiIndexLangName(lang) }}{{ store.r.additionalUnicodeEmojiIndexes.value[lang] ? ` (${ i18n.ts.installed })` : '' }}</MkButton>
</template>
</div> </div>
</MkFolder> </MkFolder>
</MkDisableSection>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['notification']">
<MkFolder :defaultOpen="true">
<template #label><SearchLabel>{{ i18n.ts.notifications }}</SearchLabel></template>
<div class="_gaps_m">
<SearchMarker :keywords="['group']">
<MkPreferenceContainer k="useGroupedNotifications">
<MkSwitch v-model="useGroupedNotifications">
<template #label><SearchLabel>{{ i18n.ts.useGroupedNotifications }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['position']">
<MkPreferenceContainer k="notificationPosition">
<MkRadios v-model="notificationPosition">
<template #label><SearchLabel>{{ i18n.ts.position }}</SearchLabel></template>
<option value="leftTop"><i class="ti ti-align-box-left-top"></i> {{ i18n.ts.leftTop }}</option>
<option value="rightTop"><i class="ti ti-align-box-right-top"></i> {{ i18n.ts.rightTop }}</option>
<option value="leftBottom"><i class="ti ti-align-box-left-bottom"></i> {{ i18n.ts.leftBottom }}</option>
<option value="rightBottom"><i class="ti ti-align-box-right-bottom"></i> {{ i18n.ts.rightBottom }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['stack', 'axis', 'direction']">
<MkPreferenceContainer k="notificationStackAxis">
<MkRadios v-model="notificationStackAxis">
<template #label><SearchLabel>{{ i18n.ts.stackAxis }}</SearchLabel></template>
<option value="vertical"><i class="ti ti-carousel-vertical"></i> {{ i18n.ts.vertical }}</option>
<option value="horizontal"><i class="ti ti-carousel-horizontal"></i> {{ i18n.ts.horizontal }}</option>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<MkButton @click="testNotification">{{ i18n.ts._notification.checkNotificationBehavior }}</MkButton>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['other']">
<MkFolder :defaultOpen="true">
<template #label><SearchLabel>{{ i18n.ts.other }}</SearchLabel></template>
<div class="_gaps_m">
<div class="_gaps_s">
<SearchMarker :keywords="['avatar', 'icon', 'square']">
<MkPreferenceContainer k="squareAvatars">
<MkSwitch v-model="squareAvatars">
<template #label><SearchLabel>{{ i18n.ts.squareAvatars }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['effect', 'show']">
<MkPreferenceContainer k="enableSeasonalScreenEffect">
<MkSwitch v-model="enableSeasonalScreenEffect">
<template #label><SearchLabel>{{ i18n.ts.seasonalScreenEffect }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab']">
<MkPreferenceContainer k="imageNewTab">
<MkSwitch v-model="imageNewTab">
<template #label><SearchLabel>{{ i18n.ts.openImageInNewTab }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker> </SearchMarker>
</div> </div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['server', 'disconnect', 'reconnect', 'reload', 'streaming']"> <SearchMarker :keywords="['datasaver']">
<MkPreferenceContainer k="serverDisconnectedBehavior"> <MkFolder>
<MkSelect v-model="serverDisconnectedBehavior"> <template #label><SearchLabel>{{ i18n.ts.dataSaver }}</SearchLabel></template>
<template #label><SearchLabel>{{ i18n.ts.whenServerDisconnected }}</SearchLabel></template>
<option value="reload">{{ i18n.ts._serverDisconnectedBehavior.reload }}</option>
<option value="dialog">{{ i18n.ts._serverDisconnectedBehavior.dialog }}</option>
<option value="quiet">{{ i18n.ts._serverDisconnectedBehavior.quiet }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['cache', 'page']">
<MkPreferenceContainer k="numberOfPageCache">
<MkRange v-model="numberOfPageCache" :min="1" :max="10" :step="1" easing>
<template #label><SearchLabel>{{ i18n.ts.numberOfPageCache }}</SearchLabel></template>
<template #caption>{{ i18n.ts.numberOfPageCacheDescription }}</template>
</MkRange>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['ad', 'show']">
<MkPreferenceContainer k="forceShowAds">
<MkSwitch v-model="forceShowAds">
<template #label><SearchLabel>{{ i18n.ts.forceShowAds }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker>
<MkPreferenceContainer k="hemisphere">
<MkRadios v-model="hemisphere">
<template #label><SearchLabel>{{ i18n.ts.hemisphere }}</SearchLabel></template>
<option value="N">{{ i18n.ts._hemisphere.N }}</option>
<option value="S">{{ i18n.ts._hemisphere.S }}</option>
<template #caption>{{ i18n.ts._hemisphere.caption }}</template>
</MkRadios>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['emoji', 'dictionary', 'additional', 'extra']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.additionalEmojiDictionary }}</SearchLabel></template>
<div class="_buttons">
<template v-for="lang in emojiIndexLangs" :key="lang">
<MkButton v-if="store.r.additionalUnicodeEmojiIndexes.value[lang]" danger @click="removeEmojiIndex(lang)"><i class="ti ti-trash"></i> {{ i18n.ts.remove }} ({{ getEmojiIndexLangName(lang) }})</MkButton>
<MkButton v-else @click="downloadEmojiIndex(lang)"><i class="ti ti-download"></i> {{ getEmojiIndexLangName(lang) }}{{ store.r.additionalUnicodeEmojiIndexes.value[lang] ? ` (${ i18n.ts.installed })` : '' }}</MkButton>
</template>
</div>
</MkFolder>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['datasaver']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.dataSaver }}</SearchLabel></template>
<div class="_gaps_m">
<MkInfo>{{ i18n.ts.reloadRequiredToApplySettings }}</MkInfo>
<div class="_buttons">
<MkButton inline @click="enableAllDataSaver">{{ i18n.ts.enableAll }}</MkButton>
<MkButton inline @click="disableAllDataSaver">{{ i18n.ts.disableAll }}</MkButton>
</div>
<div class="_gaps_m"> <div class="_gaps_m">
<MkSwitch v-model="dataSaver.media"> <MkInfo>{{ i18n.ts.reloadRequiredToApplySettings }}</MkInfo>
{{ i18n.ts._dataSaver._media.title }}
<template #caption>{{ i18n.ts._dataSaver._media.description }}</template>
</MkSwitch>
<MkSwitch v-model="dataSaver.avatar">
{{ i18n.ts._dataSaver._avatar.title }}
<template #caption>{{ i18n.ts._dataSaver._avatar.description }}</template>
</MkSwitch>
<MkSwitch v-model="dataSaver.urlPreview">
{{ i18n.ts._dataSaver._urlPreview.title }}
<template #caption>{{ i18n.ts._dataSaver._urlPreview.description }}</template>
</MkSwitch>
<MkSwitch v-model="dataSaver.code">
{{ i18n.ts._dataSaver._code.title }}
<template #caption>{{ i18n.ts._dataSaver._code.description }}</template>
</MkSwitch>
</div>
</div>
</MkFolder>
</SearchMarker>
<FormLink to="/settings/navbar">{{ i18n.ts.navbar }}</FormLink> <div class="_buttons">
<FormLink to="/settings/statusbar">{{ i18n.ts.statusbar }}</FormLink> <MkButton inline @click="enableAllDataSaver">{{ i18n.ts.enableAll }}</MkButton>
<FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink> <MkButton inline @click="disableAllDataSaver">{{ i18n.ts.disableAll }}</MkButton>
<FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink> </div>
<div class="_gaps_m">
<MkSwitch v-model="dataSaver.media">
{{ i18n.ts._dataSaver._media.title }}
<template #caption>{{ i18n.ts._dataSaver._media.description }}</template>
</MkSwitch>
<MkSwitch v-model="dataSaver.avatar">
{{ i18n.ts._dataSaver._avatar.title }}
<template #caption>{{ i18n.ts._dataSaver._avatar.description }}</template>
</MkSwitch>
<MkSwitch v-model="dataSaver.urlPreview">
{{ i18n.ts._dataSaver._urlPreview.title }}
<template #caption>{{ i18n.ts._dataSaver._urlPreview.description }}</template>
</MkSwitch>
<MkSwitch v-model="dataSaver.code">
{{ i18n.ts._dataSaver._code.title }}
<template #caption>{{ i18n.ts._dataSaver._code.description }}</template>
</MkSwitch>
</div>
</div>
</MkFolder>
</SearchMarker>
<FormLink to="/settings/navbar">{{ i18n.ts.navbar }}</FormLink>
<FormLink to="/settings/statusbar">{{ i18n.ts.statusbar }}</FormLink>
<FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink>
<FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink>
</div>
</div> </div>
</SearchMarker> </SearchMarker>
</template> </template>

View File

@ -1,48 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div class="_gaps_m">
<FormSection first>
<template #label>{{ i18n.ts.rolesAssignedToMe }}</template>
<div class="_gaps_s">
<MkRolePreview v-for="role in $i.roles" :key="role.id" :role="role" :forModeration="false"/>
</div>
</FormSection>
<FormSection>
<template #label>{{ i18n.ts._role.policies }}</template>
<div class="_gaps_s">
<div v-for="policy in Object.keys($i.policies)" :key="policy">
{{ policy }} ... {{ $i.policies[policy] }}
</div>
</div>
</FormSection>
</div>
</template>
<script lang="ts" setup>
import { computed } from 'vue';
import FormSection from '@/components/form/section.vue';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { signinRequired } from '@/account.js';
import { definePage } from '@/page.js';
import MkRolePreview from '@/components/MkRolePreview.vue';
const $i = signinRequired();
const headerActions = computed(() => []);
const headerTabs = computed(() => []);
definePage(() => ({
title: i18n.ts.roles,
icon: 'ti ti-badges',
}));
</script>
<style lang="scss" module>
</style>

View File

@ -57,10 +57,6 @@ const routes: RouteDef[] = [{
path: '/avatar-decoration', path: '/avatar-decoration',
name: 'avatarDecoration', name: 'avatarDecoration',
component: page(() => import('@/pages/settings/avatar-decoration.vue')), component: page(() => import('@/pages/settings/avatar-decoration.vue')),
}, {
path: '/roles',
name: 'roles',
component: page(() => import('@/pages/settings/roles.vue')),
}, { }, {
path: '/privacy', path: '/privacy',
name: 'privacy', name: 'privacy',

View File

@ -271,55 +271,55 @@ export const searchIndexes: SearchIndexItem[] = [
id: '3yCAv0IsZ', id: '3yCAv0IsZ',
children: [ children: [
{ {
id: 'kMJ5laK3n', id: 'AKvDrxSj5',
children: [ children: [
{ {
id: 'EC8J177N8', id: 'cAszhShB0',
label: i18n.ts.uiLanguage, label: i18n.ts.uiLanguage,
keywords: ['language'], keywords: ['language'],
}, },
{ {
id: 'CHKy9gnrh', id: 'apz9AutPm',
label: i18n.ts.overridedDeviceKind, label: i18n.ts.overridedDeviceKind,
keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'], keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'],
}, },
{ {
id: 'snyCQ5oKE', id: 'nqRVtw1xw',
label: i18n.ts.useBlurEffect, label: i18n.ts.useBlurEffect,
keywords: ['blur'], keywords: ['blur'],
}, },
{ {
id: '8j36S4Ev6', id: 'EO5WHBeG8',
label: i18n.ts.useBlurEffectForModal, label: i18n.ts.useBlurEffectForModal,
keywords: ['blur', 'modal'], keywords: ['blur', 'modal'],
}, },
{ {
id: 'cytWLyF1V', id: 'CWpyT9vLK',
label: i18n.ts.showAvatarDecorations, label: i18n.ts.showAvatarDecorations,
keywords: ['avatar', 'icon', 'decoration', 'show'], keywords: ['avatar', 'icon', 'decoration', 'show'],
}, },
{ {
id: 'odi1d2SWy', id: '1wwACqQz1',
label: i18n.ts.alwaysConfirmFollow, label: i18n.ts.alwaysConfirmFollow,
keywords: ['follow', 'confirm', 'always'], keywords: ['follow', 'confirm', 'always'],
}, },
{ {
id: 'm43Eu3Ypg', id: '1x3JNXj8N',
label: i18n.ts.highlightSensitiveMedia, label: i18n.ts.highlightSensitiveMedia,
keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'], keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'],
}, },
{ {
id: 'cjfAtxMzP', id: 'CfAg0Qekq',
label: i18n.ts.confirmWhenRevealingSensitiveMedia, label: i18n.ts.confirmWhenRevealingSensitiveMedia,
keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'], keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'],
}, },
{ {
id: 'aefexW9fD', id: '4LxdiOMNh',
label: i18n.ts.emojiStyle, label: i18n.ts.emojiStyle,
keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'], keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'],
}, },
{ {
id: 'p7aiLj6A0', id: '67knC3FWp',
label: i18n.ts.pinnedList, label: i18n.ts.pinnedList,
keywords: ['pinned', 'list'], keywords: ['pinned', 'list'],
}, },
@ -328,35 +328,35 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['general'], keywords: ['general'],
}, },
{ {
id: 'khT3n6byY', id: 'hDdVkBFJP',
children: [ children: [
{ {
id: 'DftdlLbNu', id: 'igFN7RIUa',
label: i18n.ts.showFixedPostForm, label: i18n.ts.showFixedPostForm,
keywords: ['post', 'form', 'timeline'], keywords: ['post', 'form', 'timeline'],
}, },
{ {
id: 'FbhoeuRAD', id: '9uxocbLO0',
label: i18n.ts.showFixedPostFormInChannel, label: i18n.ts.showFixedPostFormInChannel,
keywords: ['post', 'form', 'timeline', 'channel'], keywords: ['post', 'form', 'timeline', 'channel'],
}, },
{ {
id: 'rq69GTeB4', id: 'eaT1O1Fao',
label: i18n.ts.collapseRenotes, label: i18n.ts.collapseRenotes,
keywords: ['renote', i18n.ts.collapseRenotesDescription], keywords: ['renote', i18n.ts.collapseRenotesDescription],
}, },
{ {
id: 'omxZk3eET', id: 'jC7LtTnmc',
label: i18n.ts.showGapBetweenNotesInTimeline, label: i18n.ts.showGapBetweenNotesInTimeline,
keywords: ['note', 'timeline', 'gap'], keywords: ['note', 'timeline', 'gap'],
}, },
{ {
id: 'epvi2Nv2G', id: 'p2wlrnwLo',
label: i18n.ts.enableInfiniteScroll, label: i18n.ts.enableInfiniteScroll,
keywords: ['load', 'auto', 'more'], keywords: ['load', 'auto', 'more'],
}, },
{ {
id: 'v26JSj9mH', id: 'eqMBMY6LU',
label: i18n.ts.disableStreamingTimeline, label: i18n.ts.disableStreamingTimeline,
keywords: ['disable', 'streaming', 'timeline'], keywords: ['disable', 'streaming', 'timeline'],
}, },
@ -365,65 +365,65 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['timeline'], keywords: ['timeline'],
}, },
{ {
id: '7Uf8ksn3q', id: '2LNjwv1cr',
children: [ children: [
{ {
id: 'tLGyaQagB', id: '6ylW3eIcD',
label: i18n.ts.showNoteActionsOnlyHover, label: i18n.ts.showNoteActionsOnlyHover,
keywords: ['hover', 'show', 'footer', 'action'], keywords: ['hover', 'show', 'footer', 'action'],
}, },
{ {
id: '7W6g8Dcqz', id: 'lBbtAg0Hm',
label: i18n.ts.showClipButtonInNoteFooter, label: i18n.ts.showClipButtonInNoteFooter,
keywords: ['footer', 'action', 'clip', 'show'], keywords: ['footer', 'action', 'clip', 'show'],
}, },
{ {
id: 'uAOoH3LFF', id: 'E9whefUtX',
label: i18n.ts.enableAdvancedMfm, label: i18n.ts.enableAdvancedMfm,
keywords: ['mfm', 'enable', 'show', 'advanced'], keywords: ['mfm', 'enable', 'show', 'advanced'],
}, },
{ {
id: 'eCiyZLC8n', id: 'iQaBbJBva',
label: i18n.ts.showReactionsCount, label: i18n.ts.showReactionsCount,
keywords: ['reaction', 'count', 'show'], keywords: ['reaction', 'count', 'show'],
}, },
{ {
id: '68u9uRmFP', id: 'hgEVGgJa1',
label: i18n.ts.confirmOnReact, label: i18n.ts.confirmOnReact,
keywords: ['reaction', 'confirm'], keywords: ['reaction', 'confirm'],
}, },
{ {
id: 'rHWm4sXIe', id: 'yxehrHZ6x',
label: i18n.ts.loadRawImages, label: i18n.ts.loadRawImages,
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment'], keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment'],
}, },
{ {
id: '9L2XGJw7e', id: 'DdoFLaSG8',
label: i18n.ts.useReactionPickerForContextMenu, label: i18n.ts.useReactionPickerForContextMenu,
keywords: ['reaction', 'picker', 'contextmenu', 'open'], keywords: ['reaction', 'picker', 'contextmenu', 'open'],
}, },
{ {
id: 'uIMCIK7kG', id: 'fyod6U3QX',
label: i18n.ts.reactionsDisplaySize, label: i18n.ts.reactionsDisplaySize,
keywords: ['reaction', 'size', 'scale', 'display'], keywords: ['reaction', 'size', 'scale', 'display'],
}, },
{ {
id: 'uMckjO9bz', id: 'kmdsnVIQX',
label: i18n.ts.limitWidthOfReaction, label: i18n.ts.limitWidthOfReaction,
keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'], keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'],
}, },
{ {
id: 'yeghU4qiH', id: 'hacQ9br20',
label: i18n.ts.mediaListWithOneImageAppearance, label: i18n.ts.mediaListWithOneImageAppearance,
keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'], keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'],
}, },
{ {
id: 'yYSOPoAKE', id: 'vE7KeV4U4',
label: i18n.ts.instanceTicker, label: i18n.ts.instanceTicker,
keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'], keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'],
}, },
{ {
id: 'iOHiIu32L', id: '3reoOxO26',
label: i18n.ts.displayOfSensitiveMedia, label: i18n.ts.displayOfSensitiveMedia,
keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'], keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'],
}, },
@ -432,25 +432,25 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['note'], keywords: ['note'],
}, },
{ {
id: 'zrJicawH9', id: 'eROFRMtXv',
children: [ children: [
{ {
id: 'iuEuPe6pa', id: 'bezWaWd6M',
label: i18n.ts.keepCw, label: i18n.ts.keepCw,
keywords: ['remember', 'keep', 'note', 'cw'], keywords: ['remember', 'keep', 'note', 'cw'],
}, },
{ {
id: '9WrGgANqN', id: '90ngq28Nx',
label: i18n.ts.rememberNoteVisibility, label: i18n.ts.rememberNoteVisibility,
keywords: ['remember', 'keep', 'note', 'visibility'], keywords: ['remember', 'keep', 'note', 'visibility'],
}, },
{ {
id: 'Cu7ErCM7C', id: 'ERGQVw6ml',
label: i18n.ts.enableQuickAddMfmFunction, label: i18n.ts.enableQuickAddMfmFunction,
keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'], keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'],
}, },
{ {
id: 'oQl8xwiyI', id: 'g0otcvWv3',
label: i18n.ts.defaultNoteVisibility, label: i18n.ts.defaultNoteVisibility,
keywords: ['default', 'note', 'visibility'], keywords: ['default', 'note', 'visibility'],
}, },
@ -459,20 +459,20 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['post', 'form'], keywords: ['post', 'form'],
}, },
{ {
id: 'xFmAg2tDe', id: 'AWLIP02IT',
children: [ children: [
{ {
id: 'mepqKL5Ow', id: 'rDLJRu99',
label: i18n.ts.useGroupedNotifications, label: i18n.ts.useGroupedNotifications,
keywords: ['group'], keywords: ['group'],
}, },
{ {
id: 'wUuUOEO1g', id: '70WDijfPH',
label: i18n.ts.position, label: i18n.ts.position,
keywords: ['position'], keywords: ['position'],
}, },
{ {
id: '27em8eC8R', id: 'xKUzsSrKy',
label: i18n.ts.stackAxis, label: i18n.ts.stackAxis,
keywords: ['stack', 'axis', 'direction'], keywords: ['stack', 'axis', 'direction'],
}, },
@ -481,45 +481,45 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['notification'], keywords: ['notification'],
}, },
{ {
id: 'AzymHsnrp', id: '2E7vdIUQd',
children: [ children: [
{ {
id: 'DFUrEO2DI', id: 'C2iXtZKb3',
label: i18n.ts.squareAvatars, label: i18n.ts.squareAvatars,
keywords: ['avatar', 'icon', 'square'], keywords: ['avatar', 'icon', 'square'],
}, },
{ {
id: 'r9DX60AxL', id: 'DCfJg0bva',
label: i18n.ts.seasonalScreenEffect, label: i18n.ts.seasonalScreenEffect,
keywords: ['effect', 'show'], keywords: ['effect', 'show'],
}, },
{ {
id: 'sJ3fqncSD', id: 'AV0iGW0vg',
label: i18n.ts.openImageInNewTab, label: i18n.ts.openImageInNewTab,
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'], keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'],
}, },
{ {
id: 'p7s0hwZ8A', id: '5h8vhCX1S',
label: i18n.ts.whenServerDisconnected, label: i18n.ts.whenServerDisconnected,
keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'], keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'],
}, },
{ {
id: 'yCleENWNf', id: 'zZxyXHk3A',
label: i18n.ts.numberOfPageCache, label: i18n.ts.numberOfPageCache,
keywords: ['cache', 'page'], keywords: ['cache', 'page'],
}, },
{ {
id: 'omEy5Q3Ev', id: '7ix3kvMyU',
label: i18n.ts.forceShowAds, label: i18n.ts.forceShowAds,
keywords: ['ad', 'show'], keywords: ['ad', 'show'],
}, },
{ {
id: 'aWitQSBtD', id: '6RxgjmMLN',
label: i18n.ts.hemisphere, label: i18n.ts.hemisphere,
keywords: [], keywords: [],
}, },
{ {
id: 'hUQAXl1H4', id: '5iMpm5rES',
label: i18n.ts.additionalEmojiDictionary, label: i18n.ts.additionalEmojiDictionary,
keywords: ['emoji', 'dictionary', 'additional', 'extra'], keywords: ['emoji', 'dictionary', 'additional', 'extra'],
}, },
@ -528,7 +528,7 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['other'], keywords: ['other'],
}, },
{ {
id: 'aSbKFHbOy', id: 'fnR7PRww5',
label: i18n.ts.dataSaver, label: i18n.ts.dataSaver,
keywords: ['datasaver'], keywords: ['datasaver'],
}, },
@ -550,26 +550,31 @@ export const searchIndexes: SearchIndexItem[] = [
children: [ children: [
{ {
id: 'msAcN6u3S', id: 'msAcN6u3S',
label: i18n.ts.accountInfo, label: i18n.ts._role.policies,
keywords: ['account', 'info'], keywords: ['account', 'info'],
}, },
{ {
id: 'ts8DgdnZV', id: 'pbTLsgRO7',
label: i18n.ts.rolesAssignedToMe,
keywords: ['roles'],
},
{
id: 'fQpvZyfLK',
label: i18n.ts.accountMigration, label: i18n.ts.accountMigration,
keywords: ['account', 'move', 'migration'], keywords: ['account', 'move', 'migration'],
}, },
{ {
id: '4BG7nBECm', id: 'xhfur5m2z',
label: i18n.ts.closeAccount, label: i18n.ts.closeAccount,
keywords: ['account', 'close', 'delete', i18n.ts._accountDelete.requestAccountDelete], keywords: ['account', 'close', 'delete', i18n.ts._accountDelete.requestAccountDelete],
}, },
{ {
id: '2qI6ruPgi', id: 'oAXB8zm2U',
label: i18n.ts.experimentalFeatures, label: i18n.ts.experimentalFeatures,
keywords: ['experimental', 'feature', 'flags'], keywords: ['experimental', 'feature', 'flags'],
}, },
{ {
id: 'cIeaax47o', id: '95OjjGSo7',
label: i18n.ts.developer, label: i18n.ts.developer,
keywords: ['developer', 'mode', 'debug'], keywords: ['developer', 'mode', 'debug'],
}, },