From 5d228fb0f32aca9337c8b8a9ea9544f28d981f34 Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Thu, 13 Mar 2025 17:39:53 +0900
Subject: [PATCH] enhance(frontend): re-organize settings page

---
 locales/index.d.ts                            |   4 +
 locales/ja-JP.yml                             |   1 +
 .../src/pages/settings/accessibility.vue      |  51 ++
 .../src/pages/settings/appearance.vue         | 325 ---------
 .../frontend/src/pages/settings/index.vue     |   5 -
 .../src/pages/settings/preferences.vue        | 668 ++++++++++++------
 packages/frontend/src/router/definition.ts    |   4 -
 .../utility/autogen/settings-search-index.ts  | 423 ++++++-----
 8 files changed, 702 insertions(+), 779 deletions(-)
 delete mode 100644 packages/frontend/src/pages/settings/appearance.vue

diff --git a/locales/index.d.ts b/locales/index.d.ts
index b814bb70e1..f579aadb5d 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5342,6 +5342,10 @@ export interface Locale extends ILocale {
      * 絵文字パレット
      */
     "emojiPalette": string;
+    /**
+     * 投稿フォーム
+     */
+    "postForm": string;
     "_emojiPalette": {
         /**
          * パレット
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index b51a839715..2151a06611 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1331,6 +1331,7 @@ preferenceSyncConflictChoiceDevice: "デバイスの設定値"
 preferenceSyncConflictChoiceCancel: "同期の有効化をキャンセル"
 paste: "ペースト"
 emojiPalette: "絵文字パレット"
+postForm: "投稿フォーム"
 
 _emojiPalette:
   palettes: "パレット"
diff --git a/packages/frontend/src/pages/settings/accessibility.vue b/packages/frontend/src/pages/settings/accessibility.vue
index 3dbb039a17..f7b1e7d2a0 100644
--- a/packages/frontend/src/pages/settings/accessibility.vue
+++ b/packages/frontend/src/pages/settings/accessibility.vue
@@ -60,6 +60,17 @@ SPDX-License-Identifier: AGPL-3.0-only
 			</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">
@@ -70,6 +81,22 @@ SPDX-License-Identifier: AGPL-3.0-only
 				</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>
@@ -84,6 +111,8 @@ 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');
@@ -92,10 +121,32 @@ 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 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,
 ], async () => {
 	await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
 });
diff --git a/packages/frontend/src/pages/settings/appearance.vue b/packages/frontend/src/pages/settings/appearance.vue
deleted file mode 100644
index 3fda5bc4c8..0000000000
--- a/packages/frontend/src/pages/settings/appearance.vue
+++ /dev/null
@@ -1,325 +0,0 @@
-<!--
-SPDX-FileCopyrightText: syuilo and misskey-project
-SPDX-License-Identifier: AGPL-3.0-only
--->
-
-<template>
-<SearchMarker path="/settings/appearance" :label="i18n.ts.appearance" :keywords="['appearance']" icon="ti ti-device-desktop">
-	<div class="_gaps_m">
-		<MkFeatureBanner icon="/client-assets/desktop_computer_3d.png" color="#eaff00">
-			<SearchKeyword>{{ i18n.ts._settings.appearanceBanner }}</SearchKeyword>
-		</MkFeatureBanner>
-
-		<FormSection first>
-			<div class="_gaps_m">
-				<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="['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="['avatar', 'icon', 'square']">
-						<MkPreferenceContainer k="squareAvatars">
-							<MkSwitch v-model="squareAvatars">
-								<template #label><SearchLabel>{{ i18n.ts.squareAvatars }}</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="['note', 'timeline', 'gap']">
-						<MkPreferenceContainer k="showGapBetweenNotesInTimeline">
-							<MkSwitch v-model="showGapBetweenNotesInTimeline">
-								<template #label><SearchLabel>{{ i18n.ts.showGapBetweenNotesInTimeline }}</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>
-				</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="['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="['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>
-		</FormSection>
-
-		<SearchMarker :keywords="['note', 'display']">
-			<FormSection>
-				<template #label><SearchLabel>{{ i18n.ts.displayOfNote }}</SearchLabel></template>
-
-				<div class="_gaps_m">
-					<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>
-			</FormSection>
-		</SearchMarker>
-
-		<SearchMarker :keywords="['notification', 'display']">
-			<FormSection>
-				<template #label><SearchLabel>{{ i18n.ts.notificationDisplay }}</SearchLabel></template>
-
-				<div class="_gaps_m">
-					<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>
-			</FormSection>
-		</SearchMarker>
-
-		<FormSection>
-			<FormLink to="/settings/custom-css"><template #icon><i class="ti ti-code"></i></template>{{ i18n.ts.customCss }}</FormLink>
-		</FormSection>
-	</div>
-</SearchMarker>
-</template>
-
-<script lang="ts" setup>
-import { computed, ref, watch } from 'vue';
-import * as Misskey from 'misskey-js';
-import MkSwitch from '@/components/MkSwitch.vue';
-import MkSelect from '@/components/MkSelect.vue';
-import MkRadios from '@/components/MkRadios.vue';
-import { prefer } from '@/preferences.js';
-import { reloadAsk } from '@/utility/reload-ask.js';
-import { i18n } from '@/i18n.js';
-import { definePage } from '@/page.js';
-import { miLocalStorage } from '@/local-storage.js';
-import FormLink from '@/components/form/link.vue';
-import { globalEvents } from '@/events.js';
-import { claimAchievement } from '@/utility/achievements.js';
-import MkButton from '@/components/MkButton.vue';
-import FormSection from '@/components/form/section.vue';
-import { instance } from '@/instance.js';
-import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
-import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
-
-const fontSize = ref(miLocalStorage.getItem('fontSize'));
-const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null);
-
-const showAvatarDecorations = prefer.model('showAvatarDecorations');
-const emojiStyle = prefer.model('emojiStyle');
-const menuStyle = prefer.model('menuStyle');
-const useBlurEffectForModal = prefer.model('useBlurEffectForModal');
-const useBlurEffect = prefer.model('useBlurEffect');
-const highlightSensitiveMedia = prefer.model('highlightSensitiveMedia');
-const squareAvatars = prefer.model('squareAvatars');
-const enableSeasonalScreenEffect = prefer.model('enableSeasonalScreenEffect');
-const showGapBetweenNotesInTimeline = prefer.model('showGapBetweenNotesInTimeline');
-const mediaListWithOneImageAppearance = prefer.model('mediaListWithOneImageAppearance');
-const reactionsDisplaySize = prefer.model('reactionsDisplaySize');
-const limitWidthOfReaction = prefer.model('limitWidthOfReaction');
-const notificationPosition = prefer.model('notificationPosition');
-const notificationStackAxis = prefer.model('notificationStackAxis');
-const nsfw = prefer.model('nsfw');
-const instanceTicker = prefer.model('instanceTicker');
-
-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([
-	fontSize,
-	useSystemFont,
-	squareAvatars,
-	highlightSensitiveMedia,
-	enableSeasonalScreenEffect,
-	showGapBetweenNotesInTimeline,
-	mediaListWithOneImageAppearance,
-	reactionsDisplaySize,
-	limitWidthOfReaction,
-	mediaListWithOneImageAppearance,
-	reactionsDisplaySize,
-	limitWidthOfReaction,
-	instanceTicker,
-], async () => {
-	await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
-});
-
-let smashCount = 0;
-let smashTimer: number | null = null;
-
-function testNotification(): void {
-	const notification: Misskey.entities.Notification = {
-		id: Math.random().toString(),
-		createdAt: new Date().toUTCString(),
-		isRead: false,
-		type: 'test',
-	};
-
-	globalEvents.emit('clientNotification', notification);
-
-	// セルフ通知破壊 実績関連
-	smashCount++;
-	if (smashCount >= 10) {
-		claimAchievement('smashTestNotificationButton');
-		smashCount = 0;
-	}
-	if (smashTimer) {
-		clearTimeout(smashTimer);
-	}
-	smashTimer = window.setTimeout(() => {
-		smashCount = 0;
-	}, 300);
-}
-
-const headerActions = computed(() => []);
-
-const headerTabs = computed(() => []);
-
-definePage(() => ({
-	title: i18n.ts.appearance,
-	icon: 'ti ti-device-desktop',
-}));
-</script>
diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue
index debcd4bd3e..3b7c44fbfe 100644
--- a/packages/frontend/src/pages/settings/index.vue
+++ b/packages/frontend/src/pages/settings/index.vue
@@ -118,11 +118,6 @@ const menuDef = computed<SuperMenuDef[]>(() => [{
 		text: i18n.ts.emojiPalette,
 		to: '/settings/emoji-palette',
 		active: currentPage.value?.route.name === 'emoji-palette',
-	}, {
-		icon: 'ti ti-device-desktop',
-		text: i18n.ts.appearance,
-		to: '/settings/appearance',
-		active: currentPage.value?.route.name === 'appearance',
 	}, {
 		icon: 'ti ti-music',
 		text: i18n.ts.sounds,
diff --git a/packages/frontend/src/pages/settings/preferences.vue b/packages/frontend/src/pages/settings/preferences.vue
index 374477c510..b9a596067c 100644
--- a/packages/frontend/src/pages/settings/preferences.vue
+++ b/packages/frontend/src/pages/settings/preferences.vue
@@ -10,121 +10,174 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<SearchKeyword>{{ i18n.ts._settings.preferencesBanner }}</SearchKeyword>
 		</MkFeatureBanner>
 
-		<SearchMarker :keywords="['language']">
-			<MkSelect v-model="lang">
-				<template #label><SearchLabel>{{ i18n.ts.uiLanguage }}</SearchLabel></template>
-				<option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option>
-				<template #caption>
-					<I18n :src="i18n.ts.i18nInfo" tag="span">
-						<template #link>
-							<MkLink url="https://crowdin.com/project/misskey">Crowdin</MkLink>
-						</template>
-					</I18n>
-				</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>
-
-		<FormSection>
-			<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="['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>
-
-				<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>
-		</FormSection>
-
-		<FormSection>
-			<div class="_gaps_m">
-				<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="['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>
-		</FormSection>
-
-		<SearchMarker :keywords="['note']">
-			<FormSection>
-				<template #label><SearchLabel>{{ i18n.ts.note }}</SearchLabel></template>
+		<SearchMarker :keywords="['general']">
+			<MkFolder :defaultOpen="true">
+				<template #label><SearchLabel>{{ i18n.ts.general }}</SearchLabel></template>
 
 				<div class="_gaps_m">
+					<SearchMarker :keywords="['language']">
+						<MkSelect v-model="lang">
+							<template #label><SearchLabel>{{ i18n.ts.uiLanguage }}</SearchLabel></template>
+							<option v-for="x in langs" :key="x[0]" :value="x[0]">{{ x[1] }}</option>
+							<template #caption>
+								<I18n :src="i18n.ts.i18nInfo" tag="span">
+									<template #link>
+										<MkLink url="https://crowdin.com/project/misskey">Crowdin</MkLink>
+									</template>
+								</I18n>
+							</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="['renote']">
-							<MkPreferenceContainer k="collapseRenotes">
-								<MkSwitch v-model="collapseRenotes">
-									<template #label><SearchLabel>{{ i18n.ts.collapseRenotes }}</SearchLabel></template>
-									<template #caption><SearchKeyword>{{ i18n.ts.collapseRenotesDescription }}</SearchKeyword></template>
+						<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">
@@ -157,6 +210,14 @@ SPDX-License-Identifier: AGPL-3.0-only
 							</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">
@@ -164,40 +225,6 @@ SPDX-License-Identifier: AGPL-3.0-only
 								</MkSwitch>
 							</MkPreferenceContainer>
 						</SearchMarker>
-					</div>
-				</div>
-			</FormSection>
-		</SearchMarker>
-
-		<SearchMarker :keywords="['notification']">
-			<FormSection>
-				<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>
-				</div>
-			</FormSection>
-		</SearchMarker>
-
-		<SearchMarker :keywords="['behavior']">
-			<FormSection>
-				<template #label><SearchLabel>{{ i18n.ts.behavior }}</SearchLabel></template>
-
-				<div class="_gaps_m">
-					<div class="_gaps_s">
-						<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 :keywords="['reaction', 'picker', 'contextmenu', 'open']">
 							<MkPreferenceContainer k="useReactionPickerForContextMenu">
@@ -206,47 +233,70 @@ SPDX-License-Identifier: AGPL-3.0-only
 								</MkSwitch>
 							</MkPreferenceContainer>
 						</SearchMarker>
+					</div>
 
-						<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="['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="['disable', 'streaming', 'timeline']">
-							<MkPreferenceContainer k="disableStreamingTimeline">
-								<MkSwitch v-model="disableStreamingTimeline">
-									<template #label><SearchLabel>{{ i18n.ts.disableStreamingTimeline }}</SearchLabel></template>
-								</MkSwitch>
-							</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="['follow', 'confirm', 'always']">
-							<MkPreferenceContainer k="alwaysConfirmFollow">
-								<MkSwitch v-model="alwaysConfirmFollow">
-									<template #label><SearchLabel>{{ i18n.ts.alwaysConfirmFollow }}</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="['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>
+					<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="['reaction', 'confirm']">
-							<MkPreferenceContainer k="confirmOnReact">
-								<MkSwitch v-model="confirmOnReact">
-									<template #label><SearchLabel>{{ i18n.ts.confirmOnReact }}</SearchLabel></template>
-								</MkSwitch>
-							</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 :defaultOpen="true">
+				<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">
@@ -254,6 +304,123 @@ SPDX-License-Identifier: AGPL-3.0-only
 								</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 :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>
 					</div>
 
 					<SearchMarker :keywords="['server', 'disconnect', 'reconnect', 'reload', 'streaming']">
@@ -276,47 +443,6 @@ SPDX-License-Identifier: AGPL-3.0-only
 						</MkPreferenceContainer>
 					</SearchMarker>
 
-					<SearchMarker :label="i18n.ts.dataSaver" :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">
-									<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>
-				</div>
-			</FormSection>
-		</SearchMarker>
-
-		<SearchMarker>
-			<FormSection>
-				<template #label><SearchLabel>{{ i18n.ts.other }}</SearchLabel></template>
-
-				<div class="_gaps">
 					<SearchMarker :keywords="['ad', 'show']">
 						<MkPreferenceContainer k="forceShowAds">
 							<MkSwitch v-model="forceShowAds">
@@ -347,18 +473,47 @@ SPDX-License-Identifier: AGPL-3.0-only
 							</div>
 						</MkFolder>
 					</SearchMarker>
-
-					<FormLink to="/settings/navbar">{{ i18n.ts.navbar }}</FormLink>
-					<FormLink to="/settings/statusbar">{{ i18n.ts.statusbar }}</FormLink>
 				</div>
-			</FormSection>
+			</MkFolder>
 		</SearchMarker>
 
-		<FormSection>
-			<div class="_gaps">
-				<FormLink to="/settings/deck">{{ i18n.ts.deck }}</FormLink>
-			</div>
-		</FormSection>
+		<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">
+						<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>
 </SearchMarker>
 </template>
@@ -366,6 +521,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 <script lang="ts" setup>
 import { computed, ref, watch } from 'vue';
 import { langs } from '@@/js/config.js';
+import * as Misskey from 'misskey-js';
 import MkSwitch from '@/components/MkSwitch.vue';
 import MkSelect from '@/components/MkSelect.vue';
 import MkRadios from '@/components/MkRadios.vue';
@@ -386,6 +542,9 @@ import { miLocalStorage } from '@/local-storage.js';
 import { prefer } from '@/preferences.js';
 import MkPreferenceContainer from '@/components/MkPreferenceContainer.vue';
 import MkFeatureBanner from '@/components/MkFeatureBanner.vue';
+import { globalEvents } from '@/events.js';
+import { claimAchievement } from '@/utility/achievements.js';
+import { instance } from '@/instance.js';
 
 const lang = ref(miLocalStorage.getItem('lang'));
 const dataSaver = ref(prefer.s.dataSaver);
@@ -413,10 +572,24 @@ const useGroupedNotifications = prefer.model('useGroupedNotifications');
 const alwaysConfirmFollow = prefer.model('alwaysConfirmFollow');
 const confirmWhenRevealingSensitiveMedia = prefer.model('confirmWhenRevealingSensitiveMedia');
 const confirmOnReact = prefer.model('confirmOnReact');
-const contextMenu = prefer.model('contextMenu');
 const defaultNoteVisibility = prefer.model('defaultNoteVisibility');
 const defaultNoteLocalOnly = prefer.model('defaultNoteLocalOnly');
 const rememberNoteVisibility = prefer.model('rememberNoteVisibility');
+const showGapBetweenNotesInTimeline = prefer.model('showGapBetweenNotesInTimeline');
+const notificationPosition = prefer.model('notificationPosition');
+const notificationStackAxis = prefer.model('notificationStackAxis');
+const instanceTicker = prefer.model('instanceTicker');
+const highlightSensitiveMedia = prefer.model('highlightSensitiveMedia');
+const mediaListWithOneImageAppearance = prefer.model('mediaListWithOneImageAppearance');
+const reactionsDisplaySize = prefer.model('reactionsDisplaySize');
+const limitWidthOfReaction = prefer.model('limitWidthOfReaction');
+const squareAvatars = prefer.model('squareAvatars');
+const enableSeasonalScreenEffect = prefer.model('enableSeasonalScreenEffect');
+const showAvatarDecorations = prefer.model('showAvatarDecorations');
+const nsfw = prefer.model('nsfw');
+const emojiStyle = prefer.model('emojiStyle');
+const useBlurEffectForModal = prefer.model('useBlurEffectForModal');
+const useBlurEffect = prefer.model('useBlurEffect');
 
 watch(lang, () => {
 	miLocalStorage.setItem('lang', lang.value as string);
@@ -433,7 +606,17 @@ watch([
 	disableStreamingTimeline,
 	alwaysConfirmFollow,
 	confirmWhenRevealingSensitiveMedia,
-	contextMenu,
+	showGapBetweenNotesInTimeline,
+	mediaListWithOneImageAppearance,
+	reactionsDisplaySize,
+	limitWidthOfReaction,
+	mediaListWithOneImageAppearance,
+	reactionsDisplaySize,
+	limitWidthOfReaction,
+	instanceTicker,
+	squareAvatars,
+	highlightSensitiveMedia,
+	enableSeasonalScreenEffect,
 ], async () => {
 	await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
 });
@@ -522,6 +705,33 @@ watch(dataSaver, (to) => {
 	deep: true,
 });
 
+let smashCount = 0;
+let smashTimer: number | null = null;
+
+function testNotification(): void {
+	const notification: Misskey.entities.Notification = {
+		id: Math.random().toString(),
+		createdAt: new Date().toUTCString(),
+		isRead: false,
+		type: 'test',
+	};
+
+	globalEvents.emit('clientNotification', notification);
+
+	// セルフ通知破壊 実績関連
+	smashCount++;
+	if (smashCount >= 10) {
+		claimAchievement('smashTestNotificationButton');
+		smashCount = 0;
+	}
+	if (smashTimer) {
+		clearTimeout(smashTimer);
+	}
+	smashTimer = window.setTimeout(() => {
+		smashCount = 0;
+	}, 300);
+}
+
 const headerActions = computed(() => []);
 
 const headerTabs = computed(() => []);
diff --git a/packages/frontend/src/router/definition.ts b/packages/frontend/src/router/definition.ts
index 752356497e..62b13d22be 100644
--- a/packages/frontend/src/router/definition.ts
+++ b/packages/frontend/src/router/definition.ts
@@ -105,10 +105,6 @@ const routes: RouteDef[] = [{
 		path: '/theme',
 		name: 'theme',
 		component: page(() => import('@/pages/settings/theme.vue')),
-	}, {
-		path: '/appearance',
-		name: 'appearance',
-		component: page(() => import('@/pages/settings/appearance.vue')),
 	}, {
 		path: '/navbar',
 		name: 'navbar',
diff --git a/packages/frontend/src/utility/autogen/settings-search-index.ts b/packages/frontend/src/utility/autogen/settings-search-index.ts
index 4f1a94f266..734dc0c99c 100644
--- a/packages/frontend/src/utility/autogen/settings-search-index.ts
+++ b/packages/frontend/src/utility/autogen/settings-search-index.ts
@@ -272,176 +272,265 @@ export const searchIndexes: SearchIndexItem[] = [
 		children: [
 			{
 				id: 'kMJ5laK3n',
-				label: i18n.ts.uiLanguage,
-				keywords: ['language'],
-			},
-			{
-				id: 'dlKebHH6k',
-				label: i18n.ts.overridedDeviceKind,
-				keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'],
-			},
-			{
-				id: 'nxvMUir3T',
-				label: i18n.ts.showFixedPostForm,
-				keywords: ['post', 'form', 'timeline'],
-			},
-			{
-				id: '84MdeDWL1',
-				label: i18n.ts.showFixedPostFormInChannel,
-				keywords: ['post', 'form', 'timeline', 'channel'],
-			},
-			{
-				id: 'dOig3ye4Z',
-				label: i18n.ts.pinnedList,
-				keywords: ['pinned', 'list'],
-			},
-			{
-				id: '4huRldNp5',
-				label: i18n.ts.enableQuickAddMfmFunction,
-				keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'],
-			},
-			{
-				id: '1x3JNXj8N',
-				label: i18n.ts.rememberNoteVisibility,
-				keywords: ['remember', 'keep', 'note', 'visibility'],
-			},
-			{
-				id: 'CfAg0Qekq',
-				label: i18n.ts.defaultNoteVisibility,
-				keywords: ['default', 'note', 'visibility'],
-			},
-			{
-				id: 'tMm9kH9gy',
 				children: [
 					{
-						id: 'hDdVkBFJP',
+						id: 'EC8J177N8',
+						label: i18n.ts.uiLanguage,
+						keywords: ['language'],
+					},
+					{
+						id: 'CHKy9gnrh',
+						label: i18n.ts.overridedDeviceKind,
+						keywords: ['device', 'type', 'kind', 'smartphone', 'tablet', 'desktop'],
+					},
+					{
+						id: 'snyCQ5oKE',
+						label: i18n.ts.useBlurEffect,
+						keywords: ['blur'],
+					},
+					{
+						id: '8j36S4Ev6',
+						label: i18n.ts.useBlurEffectForModal,
+						keywords: ['blur', 'modal'],
+					},
+					{
+						id: 'cytWLyF1V',
+						label: i18n.ts.showAvatarDecorations,
+						keywords: ['avatar', 'icon', 'decoration', 'show'],
+					},
+					{
+						id: 'odi1d2SWy',
+						label: i18n.ts.alwaysConfirmFollow,
+						keywords: ['follow', 'confirm', 'always'],
+					},
+					{
+						id: 'm43Eu3Ypg',
+						label: i18n.ts.highlightSensitiveMedia,
+						keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'],
+					},
+					{
+						id: 'cjfAtxMzP',
+						label: i18n.ts.confirmWhenRevealingSensitiveMedia,
+						keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'],
+					},
+					{
+						id: 'aefexW9fD',
+						label: i18n.ts.emojiStyle,
+						keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'],
+					},
+					{
+						id: 'p7aiLj6A0',
+						label: i18n.ts.pinnedList,
+						keywords: ['pinned', 'list'],
+					},
+				],
+				label: i18n.ts.general,
+				keywords: ['general'],
+			},
+			{
+				id: 'khT3n6byY',
+				children: [
+					{
+						id: 'DftdlLbNu',
+						label: i18n.ts.showFixedPostForm,
+						keywords: ['post', 'form', 'timeline'],
+					},
+					{
+						id: 'FbhoeuRAD',
+						label: i18n.ts.showFixedPostFormInChannel,
+						keywords: ['post', 'form', 'timeline', 'channel'],
+					},
+					{
+						id: 'rq69GTeB4',
 						label: i18n.ts.collapseRenotes,
 						keywords: ['renote', i18n.ts.collapseRenotesDescription],
 					},
 					{
-						id: 'uJJyDABGu',
+						id: 'omxZk3eET',
+						label: i18n.ts.showGapBetweenNotesInTimeline,
+						keywords: ['note', 'timeline', 'gap'],
+					},
+					{
+						id: 'epvi2Nv2G',
+						label: i18n.ts.enableInfiniteScroll,
+						keywords: ['load', 'auto', 'more'],
+					},
+					{
+						id: 'v26JSj9mH',
+						label: i18n.ts.disableStreamingTimeline,
+						keywords: ['disable', 'streaming', 'timeline'],
+					},
+				],
+				label: i18n.ts.timeline,
+				keywords: ['timeline'],
+			},
+			{
+				id: '7Uf8ksn3q',
+				children: [
+					{
+						id: 'tLGyaQagB',
 						label: i18n.ts.showNoteActionsOnlyHover,
 						keywords: ['hover', 'show', 'footer', 'action'],
 					},
 					{
-						id: 'ufc2X9voy',
+						id: '7W6g8Dcqz',
 						label: i18n.ts.showClipButtonInNoteFooter,
 						keywords: ['footer', 'action', 'clip', 'show'],
 					},
 					{
-						id: '7Jwvu8bK6',
+						id: 'uAOoH3LFF',
 						label: i18n.ts.enableAdvancedMfm,
 						keywords: ['mfm', 'enable', 'show', 'advanced'],
 					},
 					{
-						id: 'yb11lSY1G',
+						id: 'eCiyZLC8n',
 						label: i18n.ts.showReactionsCount,
 						keywords: ['reaction', 'count', 'show'],
 					},
 					{
-						id: 'fL49Zxe9i',
+						id: '68u9uRmFP',
+						label: i18n.ts.confirmOnReact,
+						keywords: ['reaction', 'confirm'],
+					},
+					{
+						id: 'rHWm4sXIe',
 						label: i18n.ts.loadRawImages,
 						keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'quality', 'raw', 'attachment'],
 					},
+					{
+						id: '9L2XGJw7e',
+						label: i18n.ts.useReactionPickerForContextMenu,
+						keywords: ['reaction', 'picker', 'contextmenu', 'open'],
+					},
+					{
+						id: 'uIMCIK7kG',
+						label: i18n.ts.reactionsDisplaySize,
+						keywords: ['reaction', 'size', 'scale', 'display'],
+					},
+					{
+						id: 'uMckjO9bz',
+						label: i18n.ts.limitWidthOfReaction,
+						keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'],
+					},
+					{
+						id: 'yeghU4qiH',
+						label: i18n.ts.mediaListWithOneImageAppearance,
+						keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'],
+					},
+					{
+						id: 'yYSOPoAKE',
+						label: i18n.ts.instanceTicker,
+						keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'],
+					},
+					{
+						id: 'iOHiIu32L',
+						label: i18n.ts.displayOfSensitiveMedia,
+						keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'],
+					},
 				],
 				label: i18n.ts.note,
 				keywords: ['note'],
 			},
 			{
-				id: 'bUOs2UKY4',
+				id: 'zrJicawH9',
 				children: [
 					{
-						id: 'c8gA9Xj2a',
+						id: 'iuEuPe6pa',
+						label: i18n.ts.keepCw,
+						keywords: ['remember', 'keep', 'note', 'cw'],
+					},
+					{
+						id: '9WrGgANqN',
+						label: i18n.ts.rememberNoteVisibility,
+						keywords: ['remember', 'keep', 'note', 'visibility'],
+					},
+					{
+						id: 'Cu7ErCM7C',
+						label: i18n.ts.enableQuickAddMfmFunction,
+						keywords: ['mfm', 'enable', 'show', 'advanced', 'picker', 'form', 'function', 'fn'],
+					},
+					{
+						id: 'oQl8xwiyI',
+						label: i18n.ts.defaultNoteVisibility,
+						keywords: ['default', 'note', 'visibility'],
+					},
+				],
+				label: i18n.ts.postForm,
+				keywords: ['post', 'form'],
+			},
+			{
+				id: 'xFmAg2tDe',
+				children: [
+					{
+						id: 'mepqKL5Ow',
 						label: i18n.ts.useGroupedNotifications,
 						keywords: ['group'],
 					},
+					{
+						id: 'wUuUOEO1g',
+						label: i18n.ts.position,
+						keywords: ['position'],
+					},
+					{
+						id: '27em8eC8R',
+						label: i18n.ts.stackAxis,
+						keywords: ['stack', 'axis', 'direction'],
+					},
 				],
 				label: i18n.ts.notifications,
 				keywords: ['notification'],
 			},
 			{
-				id: 'tjGzqy3qa',
+				id: 'AzymHsnrp',
 				children: [
 					{
-						id: '3OeHscv45',
+						id: 'DFUrEO2DI',
+						label: i18n.ts.squareAvatars,
+						keywords: ['avatar', 'icon', 'square'],
+					},
+					{
+						id: 'r9DX60AxL',
+						label: i18n.ts.seasonalScreenEffect,
+						keywords: ['effect', 'show'],
+					},
+					{
+						id: 'sJ3fqncSD',
 						label: i18n.ts.openImageInNewTab,
 						keywords: ['image', 'photo', 'picture', 'media', 'thumbnail', 'new', 'tab'],
 					},
 					{
-						id: 'bFsNusspF',
-						label: i18n.ts.useReactionPickerForContextMenu,
-						keywords: ['reaction', 'picker', 'contextmenu', 'open'],
-					},
-					{
-						id: '2h3rY1izt',
-						label: i18n.ts.enableInfiniteScroll,
-						keywords: ['load', 'auto', 'more'],
-					},
-					{
-						id: 'pkK3eeFKm',
-						label: i18n.ts.disableStreamingTimeline,
-						keywords: ['disable', 'streaming', 'timeline'],
-					},
-					{
-						id: 'y2v7CV9zs',
-						label: i18n.ts.alwaysConfirmFollow,
-						keywords: ['follow', 'confirm', 'always'],
-					},
-					{
-						id: 'A8a5hcLce',
-						label: i18n.ts.confirmWhenRevealingSensitiveMedia,
-						keywords: ['sensitive', 'nsfw', 'media', 'image', 'photo', 'picture', 'attachment', 'confirm'],
-					},
-					{
-						id: 'utFrfuW7X',
-						label: i18n.ts.confirmOnReact,
-						keywords: ['reaction', 'confirm'],
-					},
-					{
-						id: 'kmdsnVIQX',
-						label: i18n.ts.keepCw,
-						keywords: ['remember', 'keep', 'note', 'cw'],
-					},
-					{
-						id: 'mNRK0pt8L',
+						id: 'p7s0hwZ8A',
 						label: i18n.ts.whenServerDisconnected,
 						keywords: ['server', 'disconnect', 'reconnect', 'reload', 'streaming'],
 					},
 					{
-						id: 'vE7KeV4U4',
+						id: 'yCleENWNf',
 						label: i18n.ts.numberOfPageCache,
 						keywords: ['cache', 'page'],
 					},
 					{
-						id: 'eJ2jme16W',
-						label: i18n.ts.dataSaver,
-						keywords: ['datasaver'],
-					},
-				],
-				label: i18n.ts.behavior,
-				keywords: ['behavior'],
-			},
-			{
-				id: 'F3kpUNvSQ',
-				children: [
-					{
-						id: '4bfFRM0UD',
+						id: 'omEy5Q3Ev',
 						label: i18n.ts.forceShowAds,
 						keywords: ['ad', 'show'],
 					},
 					{
-						id: '2pB0jWBHo',
+						id: 'aWitQSBtD',
 						label: i18n.ts.hemisphere,
 						keywords: [],
 					},
 					{
-						id: 'eIvnR6Xxo',
+						id: 'hUQAXl1H4',
 						label: i18n.ts.additionalEmojiDictionary,
 						keywords: ['emoji', 'dictionary', 'additional', 'extra'],
 					},
 				],
 				label: i18n.ts.other,
-				keywords: [],
+				keywords: ['other'],
+			},
+			{
+				id: 'aSbKFHbOy',
+				label: i18n.ts.dataSaver,
+				keywords: ['datasaver'],
 			},
 		],
 		label: i18n.ts.preferences,
@@ -715,119 +804,6 @@ export const searchIndexes: SearchIndexItem[] = [
 		path: '/settings/avatar-decoration',
 		icon: 'ti ti-sparkles',
 	},
-	{
-		id: 'AqPvMgn3A',
-		children: [
-			{
-				id: '1wtOIwAdm',
-				label: i18n.ts.useBlurEffect,
-				keywords: ['blur'],
-			},
-			{
-				id: '6fLNMTwNt',
-				label: i18n.ts.useBlurEffectForModal,
-				keywords: ['blur', 'modal'],
-			},
-			{
-				id: 'E0WXhhRB1',
-				label: i18n.ts.highlightSensitiveMedia,
-				keywords: ['highlight', 'sensitive', 'nsfw', 'image', 'photo', 'picture', 'media', 'thumbnail'],
-			},
-			{
-				id: '7iZsGkplG',
-				label: i18n.ts.squareAvatars,
-				keywords: ['avatar', 'icon', 'square'],
-			},
-			{
-				id: 'AfRMcC6IM',
-				label: i18n.ts.showAvatarDecorations,
-				keywords: ['avatar', 'icon', 'decoration', 'show'],
-			},
-			{
-				id: 'i7aSaEWaT',
-				label: i18n.ts.showGapBetweenNotesInTimeline,
-				keywords: ['note', 'timeline', 'gap'],
-			},
-			{
-				id: 'knj98Mx84',
-				label: i18n.ts.seasonalScreenEffect,
-				keywords: ['effect', 'show'],
-			},
-			{
-				id: 'Bzg77rYNd',
-				label: i18n.ts.menuStyle,
-				keywords: ['menu', 'style', 'popup', 'drawer'],
-			},
-			{
-				id: '7AOZ1ZgDv',
-				label: i18n.ts.emojiStyle,
-				keywords: ['emoji', 'style', 'native', 'system', 'fluent', 'twemoji'],
-			},
-			{
-				id: 'fDelHUrBi',
-				label: i18n.ts.fontSize,
-				keywords: ['font', 'size'],
-			},
-			{
-				id: 'siOW5aSwp',
-				label: i18n.ts.useSystemFont,
-				keywords: ['font', 'system', 'native'],
-			},
-			{
-				id: 's05dHQ1dW',
-				children: [
-					{
-						id: 'zoMbYCvP0',
-						label: i18n.ts.reactionsDisplaySize,
-						keywords: ['reaction', 'size', 'scale', 'display'],
-					},
-					{
-						id: 'lGFzLnWfB',
-						label: i18n.ts.limitWidthOfReaction,
-						keywords: ['reaction', 'size', 'scale', 'display', 'width', 'limit'],
-					},
-					{
-						id: '9E0v8VKIY',
-						label: i18n.ts.mediaListWithOneImageAppearance,
-						keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'list', 'size', 'height'],
-					},
-					{
-						id: 'xB7MPEF4Q',
-						label: i18n.ts.instanceTicker,
-						keywords: ['ticker', 'information', 'label', 'instance', 'server', 'host', 'federation'],
-					},
-					{
-						id: '7siYCSodm',
-						label: i18n.ts.displayOfSensitiveMedia,
-						keywords: ['attachment', 'image', 'photo', 'picture', 'media', 'thumbnail', 'nsfw', 'sensitive', 'display', 'show', 'hide', 'visibility'],
-					},
-				],
-				label: i18n.ts.displayOfNote,
-				keywords: ['note', 'display'],
-			},
-			{
-				id: 'uQfyiHMSs',
-				children: [
-					{
-						id: 'y3uTXsSQ6',
-						label: i18n.ts.position,
-						keywords: ['position'],
-					},
-					{
-						id: 'PILAdkVM',
-						label: i18n.ts.stackAxis,
-						keywords: ['stack', 'axis', 'direction'],
-					},
-				],
-				label: i18n.ts.notificationDisplay,
-				keywords: ['notification', 'display'],
-			},
-		],
-		label: i18n.ts.appearance,
-		keywords: ['appearance', i18n.ts._settings.appearanceBanner],
-		path: '/settings/appearance',
-		icon: 'ti ti-device-desktop',
-	},
 	{
 		id: '330Q4mf8E',
 		children: [
@@ -912,9 +888,24 @@ export const searchIndexes: SearchIndexItem[] = [
 			},
 			{
 				id: '1fV9WINCQ',
+				label: i18n.ts.menuStyle,
+				keywords: ['menu', 'style', 'popup', 'drawer'],
+			},
+			{
+				id: 'mLQzlKUNu',
 				label: i18n.ts._contextMenu.title,
 				keywords: ['contextmenu', 'system', 'native'],
 			},
+			{
+				id: 'yP96aA3j9',
+				label: i18n.ts.fontSize,
+				keywords: ['font', 'size'],
+			},
+			{
+				id: 'jQeiMopFE',
+				label: i18n.ts.useSystemFont,
+				keywords: ['font', 'system', 'native'],
+			},
 		],
 		label: i18n.ts.accessibility,
 		keywords: ['accessibility', i18n.ts._settings.accessibilityBanner],