enhance(frontend): organize settings page

This commit is contained in:
syuilo 2025-03-30 11:16:38 +09:00
parent aeda34e5e7
commit 4af49e8385
5 changed files with 219 additions and 260 deletions

View File

@ -1,173 +0,0 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<SearchMarker path="/settings/accessibility" :label="i18n.ts.accessibility" :keywords="['accessibility']" icon="ti ti-accessible">
<div class="_gaps_m">
<MkFeatureBanner icon="/client-assets/mens_room_3d.png" color="#0011ff">
<SearchKeyword>{{ i18n.ts._settings.accessibilityBanner }}</SearchKeyword>
</MkFeatureBanner>
<div class="_gaps_s">
<SearchMarker :keywords="['animation', 'motion', 'reduce']">
<MkPreferenceContainer k="animation">
<MkSwitch v-model="reduceAnimation">
<template #label><SearchLabel>{{ i18n.ts.reduceUiAnimation }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif']">
<MkPreferenceContainer k="disableShowingAnimatedImages">
<MkSwitch v-model="disableShowingAnimatedImages">
<template #label><SearchLabel>{{ i18n.ts.disableShowingAnimatedImages }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['mfm', 'enable', 'show', 'animated']">
<MkPreferenceContainer k="animatedMfm">
<MkSwitch v-model="animatedMfm">
<template #label><SearchLabel>{{ i18n.ts.enableAnimatedMfm }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['swipe', 'horizontal', 'tab']">
<MkPreferenceContainer k="enableHorizontalSwipe">
<MkSwitch v-model="enableHorizontalSwipe">
<template #label><SearchLabel>{{ i18n.ts.enableHorizontalSwipe }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['keep', 'screen', 'display', 'on']">
<MkPreferenceContainer k="keepScreenOn">
<MkSwitch v-model="keepScreenOn">
<template #label><SearchLabel>{{ i18n.ts.keepScreenOn }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['native', 'system', 'video', 'audio', 'player', 'media']">
<MkPreferenceContainer k="useNativeUiForVideoAudioPlayer">
<MkSwitch v-model="useNativeUiForVideoAudioPlayer">
<template #label><SearchLabel>{{ i18n.ts.useNativeUIForVideoAudioPlayer }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['text', 'selectable']">
<MkPreferenceContainer k="makeEveryTextElementsSelectable">
<MkSwitch v-model="makeEveryTextElementsSelectable">
<template #label><SearchLabel>{{ i18n.ts._settings.makeEveryTextElementsSelectable }}</SearchLabel></template>
<template #caption>{{ i18n.ts._settings.makeEveryTextElementsSelectable_description }}</template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['menu', 'style', 'popup', 'drawer']">
<MkPreferenceContainer k="menuStyle">
<MkSelect v-model="menuStyle">
<template #label><SearchLabel>{{ i18n.ts.menuStyle }}</SearchLabel></template>
<option value="auto">{{ i18n.ts.auto }}</option>
<option value="popup">{{ i18n.ts.popup }}</option>
<option value="drawer">{{ i18n.ts.drawer }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['contextmenu', 'system', 'native']">
<MkPreferenceContainer k="contextMenu">
<MkSelect v-model="contextMenu">
<template #label><SearchLabel>{{ i18n.ts._contextMenu.title }}</SearchLabel></template>
<option value="app">{{ i18n.ts._contextMenu.app }}</option>
<option value="appWithShift">{{ i18n.ts._contextMenu.appWithShift }}</option>
<option value="native">{{ i18n.ts._contextMenu.native }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['font', 'size']">
<MkRadios v-model="fontSize">
<template #label><SearchLabel>{{ i18n.ts.fontSize }}</SearchLabel></template>
<option :value="null"><span style="font-size: 14px;">Aa</span></option>
<option value="1"><span style="font-size: 15px;">Aa</span></option>
<option value="2"><span style="font-size: 16px;">Aa</span></option>
<option value="3"><span style="font-size: 17px;">Aa</span></option>
</MkRadios>
</SearchMarker>
<SearchMarker :keywords="['font', 'system', 'native']">
<MkSwitch v-model="useSystemFont">
<template #label><SearchLabel>{{ i18n.ts.useSystemFont }}</SearchLabel></template>
</MkSwitch>
</SearchMarker>
</div>
</SearchMarker>
</template>
<script lang="ts" setup>
import { computed, ref, watch } from 'vue';
import MkSwitch from '@/components/MkSwitch.vue';
import MkSelect from '@/components/MkSelect.vue';
import { prefer } from '@/preferences.js';
import { reloadAsk } from '@/utility/reload-ask.js';
import { i18n } from '@/i18n.js';
import { definePage } from '@/page.js';
import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
import { miLocalStorage } from '@/local-storage.js';
import MkRadios from '@/components/MkRadios.vue';
const reduceAnimation = prefer.model('animation', v => !v, v => !v);
const animatedMfm = prefer.model('animatedMfm');
const disableShowingAnimatedImages = prefer.model('disableShowingAnimatedImages');
const keepScreenOn = prefer.model('keepScreenOn');
const enableHorizontalSwipe = prefer.model('enableHorizontalSwipe');
const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPlayer');
const contextMenu = prefer.model('contextMenu');
const menuStyle = prefer.model('menuStyle');
const makeEveryTextElementsSelectable = prefer.model('makeEveryTextElementsSelectable');
const fontSize = ref(miLocalStorage.getItem('fontSize'));
const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null);
watch(fontSize, () => {
if (fontSize.value == null) {
miLocalStorage.removeItem('fontSize');
} else {
miLocalStorage.setItem('fontSize', fontSize.value);
}
});
watch(useSystemFont, () => {
if (useSystemFont.value) {
miLocalStorage.setItem('useSystemFont', 't');
} else {
miLocalStorage.removeItem('useSystemFont');
}
});
watch([
keepScreenOn,
contextMenu,
fontSize,
useSystemFont,
makeEveryTextElementsSelectable,
], async () => {
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
});
const headerActions = computed(() => []);
const headerTabs = computed(() => []);
definePage(() => ({
title: i18n.ts.accessibility,
icon: 'ti ti-accessible',
}));
</script>

View File

@ -122,11 +122,6 @@ const menuDef = computed<SuperMenuDef[]>(() => [{
text: i18n.ts.sounds,
to: '/settings/sounds',
active: currentPage.value?.route.name === 'sounds',
}, {
icon: 'ti ti-accessible',
text: i18n.ts.accessibility,
to: '/settings/accessibility',
active: currentPage.value?.route.name === 'accessibility',
}, {
icon: 'ti ti-plug',
text: i18n.ts.plugins,

View File

@ -418,6 +418,116 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['accessibility']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.accessibility }}</SearchLabel></template>
<template #icon><i class="ti ti-accessible"></i></template>
<div class="_gaps_m">
<MkFeatureBanner icon="/client-assets/mens_room_3d.png" color="#0011ff">
<SearchKeyword>{{ i18n.ts._settings.accessibilityBanner }}</SearchKeyword>
</MkFeatureBanner>
<div class="_gaps_s">
<SearchMarker :keywords="['animation', 'motion', 'reduce']">
<MkPreferenceContainer k="animation">
<MkSwitch v-model="reduceAnimation">
<template #label><SearchLabel>{{ i18n.ts.reduceUiAnimation }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif']">
<MkPreferenceContainer k="disableShowingAnimatedImages">
<MkSwitch v-model="disableShowingAnimatedImages">
<template #label><SearchLabel>{{ i18n.ts.disableShowingAnimatedImages }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['mfm', 'enable', 'show', 'animated']">
<MkPreferenceContainer k="animatedMfm">
<MkSwitch v-model="animatedMfm">
<template #label><SearchLabel>{{ i18n.ts.enableAnimatedMfm }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['swipe', 'horizontal', 'tab']">
<MkPreferenceContainer k="enableHorizontalSwipe">
<MkSwitch v-model="enableHorizontalSwipe">
<template #label><SearchLabel>{{ i18n.ts.enableHorizontalSwipe }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['keep', 'screen', 'display', 'on']">
<MkPreferenceContainer k="keepScreenOn">
<MkSwitch v-model="keepScreenOn">
<template #label><SearchLabel>{{ i18n.ts.keepScreenOn }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['native', 'system', 'video', 'audio', 'player', 'media']">
<MkPreferenceContainer k="useNativeUiForVideoAudioPlayer">
<MkSwitch v-model="useNativeUiForVideoAudioPlayer">
<template #label><SearchLabel>{{ i18n.ts.useNativeUIForVideoAudioPlayer }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['text', 'selectable']">
<MkPreferenceContainer k="makeEveryTextElementsSelectable">
<MkSwitch v-model="makeEveryTextElementsSelectable">
<template #label><SearchLabel>{{ i18n.ts._settings.makeEveryTextElementsSelectable }}</SearchLabel></template>
<template #caption>{{ i18n.ts._settings.makeEveryTextElementsSelectable_description }}</template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div>
<SearchMarker :keywords="['menu', 'style', 'popup', 'drawer']">
<MkPreferenceContainer k="menuStyle">
<MkSelect v-model="menuStyle">
<template #label><SearchLabel>{{ i18n.ts.menuStyle }}</SearchLabel></template>
<option value="auto">{{ i18n.ts.auto }}</option>
<option value="popup">{{ i18n.ts.popup }}</option>
<option value="drawer">{{ i18n.ts.drawer }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['contextmenu', 'system', 'native']">
<MkPreferenceContainer k="contextMenu">
<MkSelect v-model="contextMenu">
<template #label><SearchLabel>{{ i18n.ts._contextMenu.title }}</SearchLabel></template>
<option value="app">{{ i18n.ts._contextMenu.app }}</option>
<option value="appWithShift">{{ i18n.ts._contextMenu.appWithShift }}</option>
<option value="native">{{ i18n.ts._contextMenu.native }}</option>
</MkSelect>
</MkPreferenceContainer>
</SearchMarker>
<SearchMarker :keywords="['font', 'size']">
<MkRadios v-model="fontSize">
<template #label><SearchLabel>{{ i18n.ts.fontSize }}</SearchLabel></template>
<option :value="null"><span style="font-size: 14px;">Aa</span></option>
<option value="1"><span style="font-size: 15px;">Aa</span></option>
<option value="2"><span style="font-size: 16px;">Aa</span></option>
<option value="3"><span style="font-size: 17px;">Aa</span></option>
</MkRadios>
</SearchMarker>
<SearchMarker :keywords="['font', 'system', 'native']">
<MkSwitch v-model="useSystemFont">
<template #label><SearchLabel>{{ i18n.ts.useSystemFont }}</SearchLabel></template>
</MkSwitch>
</SearchMarker>
</div>
</MkFolder>
</SearchMarker>
<SearchMarker :keywords="['performance']">
<MkFolder>
<template #label><SearchLabel>{{ i18n.ts.performance }}</SearchLabel></template>
@ -671,6 +781,18 @@ const defaultFollowWithReplies = prefer.model('defaultFollowWithReplies');
const chatShowSenderName = prefer.model('chat.showSenderName');
const chatSendOnEnter = prefer.model('chat.sendOnEnter');
const useStickyIcons = prefer.model('useStickyIcons');
const reduceAnimation = prefer.model('animation', v => !v, v => !v);
const animatedMfm = prefer.model('animatedMfm');
const disableShowingAnimatedImages = prefer.model('disableShowingAnimatedImages');
const keepScreenOn = prefer.model('keepScreenOn');
const enableHorizontalSwipe = prefer.model('enableHorizontalSwipe');
const useNativeUiForVideoAudioPlayer = prefer.model('useNativeUiForVideoAudioPlayer');
const contextMenu = prefer.model('contextMenu');
const menuStyle = prefer.model('menuStyle');
const makeEveryTextElementsSelectable = prefer.model('makeEveryTextElementsSelectable');
const fontSize = ref(miLocalStorage.getItem('fontSize'));
const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null);
watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string);
@ -678,6 +800,22 @@ watch(lang, () => {
miLocalStorage.removeItem('localeVersion');
});
watch(fontSize, () => {
if (fontSize.value == null) {
miLocalStorage.removeItem('fontSize');
} else {
miLocalStorage.setItem('fontSize', fontSize.value);
}
});
watch(useSystemFont, () => {
if (useSystemFont.value) {
miLocalStorage.setItem('useSystemFont', 't');
} else {
miLocalStorage.removeItem('useSystemFont');
}
});
watch([
hemisphere,
lang,
@ -700,6 +838,11 @@ watch([
enableSeasonalScreenEffect,
chatShowSenderName,
useStickyIcons,
keepScreenOn,
contextMenu,
fontSize,
useSystemFont,
makeEveryTextElementsSelectable,
], async () => {
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
});

View File

@ -128,10 +128,6 @@ export const ROUTE_DEF = [{
path: '/sounds',
name: 'sounds',
component: page(() => import('@/pages/settings/sounds.vue')),
}, {
path: '/accessibility',
name: 'accessibility',
component: page(() => import('@/pages/settings/accessibility.vue')),
}, {
path: '/plugin/install',
name: 'plugin',

View File

@ -489,17 +489,79 @@ export const searchIndexes: SearchIndexItem[] = [
id: '96LnS1sxB',
children: [
{
id: '5h8vhCX1S',
id: 'vPQPvmntL',
label: i18n.ts.reduceUiAnimation,
keywords: ['animation', 'motion', 'reduce'],
},
{
id: 'wfJ91vwzq',
label: i18n.ts.disableShowingAnimatedImages,
keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'],
},
{
id: '42b1L4xdq',
label: i18n.ts.enableAnimatedMfm,
keywords: ['mfm', 'enable', 'show', 'animated'],
},
{
id: 'dLkRNHn3k',
label: i18n.ts.enableHorizontalSwipe,
keywords: ['swipe', 'horizontal', 'tab'],
},
{
id: 'BvooTWFW5',
label: i18n.ts.keepScreenOn,
keywords: ['keep', 'screen', 'display', 'on'],
},
{
id: 'yzbghkAq0',
label: i18n.ts.useNativeUIForVideoAudioPlayer,
keywords: ['native', 'system', 'video', 'audio', 'player', 'media'],
},
{
id: 'aSbKFHbOy',
label: i18n.ts._settings.makeEveryTextElementsSelectable,
keywords: ['text', 'selectable'],
},
{
id: 'bTcAsPvNz',
label: i18n.ts.menuStyle,
keywords: ['menu', 'style', 'popup', 'drawer'],
},
{
id: 'lSVBaLnyW',
label: i18n.ts._contextMenu.title,
keywords: ['contextmenu', 'system', 'native'],
},
{
id: 'pec0uMPq5',
label: i18n.ts.fontSize,
keywords: ['font', 'size'],
},
{
id: 'Eh7vTluDO',
label: i18n.ts.useSystemFont,
keywords: ['font', 'system', 'native'],
},
],
label: i18n.ts.accessibility,
keywords: ['accessibility', i18n.ts._settings.accessibilityBanner],
},
{
id: 'vTRSKf1JA',
children: [
{
id: '2VjlA02wB',
label: i18n.ts.turnOffToImprovePerformance,
keywords: ['blur'],
},
{
id: 'Cbjosj3TG',
id: 'f6J0lmg1g',
label: i18n.ts.turnOffToImprovePerformance,
keywords: ['blur', 'modal'],
},
{
id: 'BKndoHcCj',
id: 'hQqXhfNg8',
label: i18n.ts.turnOffToImprovePerformance,
keywords: ['sticky'],
},
@ -508,55 +570,55 @@ export const searchIndexes: SearchIndexItem[] = [
keywords: ['performance'],
},
{
id: '4yCgcFElF',
id: 'utM8dEobb',
label: i18n.ts.dataSaver,
keywords: ['datasaver'],
},
{
id: 'DILm2LlCn',
id: 'gOUvwkE9t',
children: [
{
id: 'Fd0rFTSry',
id: 'iUMUvFURf',
label: i18n.ts.squareAvatars,
keywords: ['avatar', 'icon', 'square'],
},
{
id: 'xNsLokqeA',
id: 'ceyPO9Ywi',
label: i18n.ts.seasonalScreenEffect,
keywords: ['effect', 'show'],
},
{
id: 'sZcalFBE8',
id: 'ztwIlsXhP',
label: i18n.ts.openImageInNewTab,
keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'],
},
{
id: 'Eh7vTluDO',
id: 'vLSsQbZEo',
label: i18n.ts.withRepliesByDefaultForNewlyFollowed,
keywords: ['follow', 'replies'],
},
{
id: 'vTRSKf1JA',
id: 'hQt85bBIX',
label: i18n.ts.whenServerDisconnected,
keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'],
},
{
id: 'zlO5cBZFH',
id: 'C9SyK2m0',
label: i18n.ts.numberOfPageCache,
keywords: ['cache', 'page'],
},
{
id: 'huQ8nc4iD',
id: '2U0iVUtfW',
label: i18n.ts.forceShowAds,
keywords: ['ad', 'show'],
},
{
id: 'nJWfqwQ4R',
id: '1rA7ADEXY',
label: i18n.ts.hemisphere,
keywords: [],
},
{
id: 'kwEEgTlwR',
id: 'vRayx89Rt',
label: i18n.ts.additionalEmojiDictionary,
keywords: ['emoji', 'dictionary', 'additional', 'extra'],
},
@ -906,70 +968,6 @@ export const searchIndexes: SearchIndexItem[] = [
path: '/settings/account-data',
icon: 'ti ti-package',
},
{
id: 'f08Mi1Uwn',
children: [
{
id: 'C5dRH2Ypy',
label: i18n.ts.reduceUiAnimation,
keywords: ['animation', 'motion', 'reduce'],
},
{
id: '5mZxz2cru',
label: i18n.ts.disableShowingAnimatedImages,
keywords: ['disable', 'animation', 'image', 'photo', 'picture', 'media', 'thumbnail', 'gif'],
},
{
id: 'c0Iy5hL5o',
label: i18n.ts.enableAnimatedMfm,
keywords: ['mfm', 'enable', 'show', 'animated'],
},
{
id: '4HYFjs2Nv',
label: i18n.ts.enableHorizontalSwipe,
keywords: ['swipe', 'horizontal', 'tab'],
},
{
id: 'kYVJ3SVNq',
label: i18n.ts.keepScreenOn,
keywords: ['keep', 'screen', 'display', 'on'],
},
{
id: 'w4Bv0meAt',
label: i18n.ts.useNativeUIForVideoAudioPlayer,
keywords: ['native', 'system', 'video', 'audio', 'player', 'media'],
},
{
id: 'b1GYEEJeh',
label: i18n.ts._settings.makeEveryTextElementsSelectable,
keywords: ['text', 'selectable'],
},
{
id: 'vVLxwINTJ',
label: i18n.ts.menuStyle,
keywords: ['menu', 'style', 'popup', 'drawer'],
},
{
id: '14cMhMLHL',
label: i18n.ts._contextMenu.title,
keywords: ['contextmenu', 'system', 'native'],
},
{
id: 'oSo4LXMX9',
label: i18n.ts.fontSize,
keywords: ['font', 'size'],
},
{
id: '7LQSAThST',
label: i18n.ts.useSystemFont,
keywords: ['font', 'system', 'native'],
},
],
label: i18n.ts.accessibility,
keywords: ['accessibility', i18n.ts._settings.accessibilityBanner],
path: '/settings/accessibility',
icon: 'ti ti-accessible',
},
] as const;
export type SearchIndex = typeof searchIndexes;