fix: Fix settings page (#8508)
* Fix settings page * nanka iroiro * clean up * clean up * インデックスに戻ってもタイトルが残ってしまうのを修正
This commit is contained in:
		
							parent
							
								
									c2cae877ce
								
							
						
					
					
						commit
						eac71ae1d7
					
				
					 3 changed files with 105 additions and 59 deletions
				
			
		|  | @ -5,14 +5,13 @@ | |||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { inject } from 'vue'; | ||||
| import * as os from '@/os'; | ||||
| import copyToClipboard from '@/scripts/copy-to-clipboard'; | ||||
| import { router } from '@/router'; | ||||
| import { url } from '@/config'; | ||||
| import { popout as popout_ } from '@/scripts/popout'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { MisskeyNavigator } from '@/scripts/navigate'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	to: string; | ||||
|  | @ -23,9 +22,7 @@ const props = withDefaults(defineProps<{ | |||
| 	behavior: null, | ||||
| }); | ||||
| 
 | ||||
| type Navigate = (path: string, record?: boolean) => void; | ||||
| const navHook = inject<null | Navigate>('navHook', null); | ||||
| const sideViewHook = inject<null | Navigate>('sideViewHook', null); | ||||
| const mkNav = new MisskeyNavigator(); | ||||
| 
 | ||||
| const active = $computed(() => { | ||||
| 	if (props.activeClass == null) return false; | ||||
|  | @ -48,11 +45,11 @@ function onContextmenu(ev) { | |||
| 		action: () => { | ||||
| 			os.pageWindow(props.to); | ||||
| 		} | ||||
| 	}, sideViewHook ? { | ||||
| 	}, mkNav.sideViewHook ? { | ||||
| 		icon: 'fas fa-columns', | ||||
| 		text: i18n.ts.openInSideView, | ||||
| 		action: () => { | ||||
| 			sideViewHook(props.to); | ||||
| 			if (mkNav.sideViewHook) mkNav.sideViewHook(props.to); | ||||
| 		} | ||||
| 	} : undefined, { | ||||
| 		icon: 'fas fa-expand-alt', | ||||
|  | @ -101,18 +98,6 @@ function nav() { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (navHook) { | ||||
| 		navHook(props.to); | ||||
| 	} else { | ||||
| 		if (defaultStore.state.defaultSideView && sideViewHook && props.to !== '/') { | ||||
| 			return sideViewHook(props.to); | ||||
| 		} | ||||
| 
 | ||||
| 		if (router.currentRoute.value.path === props.to) { | ||||
| 			window.scroll({ top: 0, behavior: 'smooth' }); | ||||
| 		} else { | ||||
| 			router.push(props.to); | ||||
| 		} | ||||
| 	} | ||||
| 	mkNav.push(props.to); | ||||
| } | ||||
| </script> | ||||
|  |  | |||
|  | @ -2,19 +2,22 @@ | |||
| <MkSpacer :content-max="900" :margin-min="20" :margin-max="32"> | ||||
| 	<div ref="el" class="vvcocwet" :class="{ wide: !narrow }"> | ||||
| 		<div class="header"> | ||||
| 			<div class="title">{{ $ts.settings }}</div> | ||||
| 			<div class="title"> | ||||
| 				<MkA v-if="narrow" to="/settings">{{ $ts.settings }}</MkA> | ||||
| 				<template v-else>{{ $ts.settings }}</template> | ||||
| 			</div> | ||||
| 			<div v-if="childInfo" class="subtitle">{{ childInfo.title }}</div> | ||||
| 		</div> | ||||
| 		<div class="body"> | ||||
| 			<div v-if="!narrow || page == null" class="nav"> | ||||
| 			<div v-if="!narrow || initialPage == null" class="nav"> | ||||
| 				<div class="baaadecd"> | ||||
| 					<MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo> | ||||
| 					<MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> | ||||
| 					<MkSuperMenu :def="menuDef" :grid="initialPage == null"></MkSuperMenu> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 			<div class="main"> | ||||
| 			<div v-if="!(narrow && initialPage == null)" class="main"> | ||||
| 				<div class="bkzroven"> | ||||
| 					<component :is="component" :ref="el => pageChanged(el)" :key="page" v-bind="pageProps"/> | ||||
| 					<component :is="component" :ref="el => pageChanged(el)" :key="initialPage" v-bind="pageProps"/> | ||||
| 				</div> | ||||
| 			</div> | ||||
| 		</div> | ||||
|  | @ -23,7 +26,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { computed, defineAsyncComponent, nextTick, onMounted, ref, watch } from 'vue'; | ||||
| import { computed, defineAsyncComponent, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import MkInfo from '@/components/ui/info.vue'; | ||||
| import MkSuperMenu from '@/components/ui/super-menu.vue'; | ||||
|  | @ -33,6 +36,7 @@ import { unisonReload } from '@/scripts/unison-reload'; | |||
| import * as symbols from '@/symbols'; | ||||
| import { instance } from '@/instance'; | ||||
| import { $i } from '@/account'; | ||||
| import { MisskeyNavigator } from '@/scripts/navigate'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
|   initialPage?: string | ||||
|  | @ -45,53 +49,61 @@ const indexInfo = { | |||
| 	hideHeader: true, | ||||
| }; | ||||
| const INFO = ref(indexInfo); | ||||
| const page = ref(props.initialPage); | ||||
| const narrow = ref(false); | ||||
| const view = ref(null); | ||||
| const el = ref<HTMLElement | null>(null); | ||||
| const childInfo = ref(null); | ||||
| 
 | ||||
| const nav = new MisskeyNavigator(); | ||||
| 
 | ||||
| const narrow = ref(false); | ||||
| const NARROW_THRESHOLD = 600; | ||||
| 
 | ||||
| const ro = new ResizeObserver((entries, observer) => { | ||||
| 	if (entries.length === 0) return; | ||||
| 	narrow.value = entries[0].borderBoxSize[0].inlineSize < NARROW_THRESHOLD; | ||||
| }); | ||||
| 
 | ||||
| const menuDef = computed(() => [{ | ||||
| 	title: i18n.ts.basicSettings, | ||||
| 	items: [{ | ||||
| 		icon: 'fas fa-user', | ||||
| 		text: i18n.ts.profile, | ||||
| 		to: '/settings/profile', | ||||
| 		active: page.value === 'profile', | ||||
| 		active: props.initialPage === 'profile', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-lock-open', | ||||
| 		text: i18n.ts.privacy, | ||||
| 		to: '/settings/privacy', | ||||
| 		active: page.value === 'privacy', | ||||
| 		active: props.initialPage === 'privacy', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-laugh', | ||||
| 		text: i18n.ts.reaction, | ||||
| 		to: '/settings/reaction', | ||||
| 		active: page.value === 'reaction', | ||||
| 		active: props.initialPage === 'reaction', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-cloud', | ||||
| 		text: i18n.ts.drive, | ||||
| 		to: '/settings/drive', | ||||
| 		active: page.value === 'drive', | ||||
| 		active: props.initialPage === 'drive', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-bell', | ||||
| 		text: i18n.ts.notifications, | ||||
| 		to: '/settings/notifications', | ||||
| 		active: page.value === 'notifications', | ||||
| 		active: props.initialPage === 'notifications', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-envelope', | ||||
| 		text: i18n.ts.email, | ||||
| 		to: '/settings/email', | ||||
| 		active: page.value === 'email', | ||||
| 		active: props.initialPage === 'email', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-share-alt', | ||||
| 		text: i18n.ts.integration, | ||||
| 		to: '/settings/integration', | ||||
| 		active: page.value === 'integration', | ||||
| 		active: props.initialPage === 'integration', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-lock', | ||||
| 		text: i18n.ts.security, | ||||
| 		to: '/settings/security', | ||||
| 		active: page.value === 'security', | ||||
| 		active: props.initialPage === 'security', | ||||
| 	}], | ||||
| }, { | ||||
| 	title: i18n.ts.clientSettings, | ||||
|  | @ -99,27 +111,27 @@ const menuDef = computed(() => [{ | |||
| 		icon: 'fas fa-cogs', | ||||
| 		text: i18n.ts.general, | ||||
| 		to: '/settings/general', | ||||
| 		active: page.value === 'general', | ||||
| 		active: props.initialPage === 'general', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-palette', | ||||
| 		text: i18n.ts.theme, | ||||
| 		to: '/settings/theme', | ||||
| 		active: page.value === 'theme', | ||||
| 		active: props.initialPage === 'theme', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-list-ul', | ||||
| 		text: i18n.ts.menu, | ||||
| 		to: '/settings/menu', | ||||
| 		active: page.value === 'menu', | ||||
| 		active: props.initialPage === 'menu', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-music', | ||||
| 		text: i18n.ts.sounds, | ||||
| 		to: '/settings/sounds', | ||||
| 		active: page.value === 'sounds', | ||||
| 		active: props.initialPage === 'sounds', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-plug', | ||||
| 		text: i18n.ts.plugins, | ||||
| 		to: '/settings/plugin', | ||||
| 		active: page.value === 'plugin', | ||||
| 		active: props.initialPage === 'plugin', | ||||
| 	}], | ||||
| }, { | ||||
| 	title: i18n.ts.otherSettings, | ||||
|  | @ -127,37 +139,37 @@ const menuDef = computed(() => [{ | |||
| 		icon: 'fas fa-boxes', | ||||
| 		text: i18n.ts.importAndExport, | ||||
| 		to: '/settings/import-export', | ||||
| 		active: page.value === 'import-export', | ||||
| 		active: props.initialPage === 'import-export', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-volume-mute', | ||||
| 		text: i18n.ts.instanceMute, | ||||
| 		to: '/settings/instance-mute', | ||||
| 		active: page.value === 'instance-mute', | ||||
| 		active: props.initialPage === 'instance-mute', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-ban', | ||||
| 		text: i18n.ts.muteAndBlock, | ||||
| 		to: '/settings/mute-block', | ||||
| 		active: page.value === 'mute-block', | ||||
| 		active: props.initialPage === 'mute-block', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-comment-slash', | ||||
| 		text: i18n.ts.wordMute, | ||||
| 		to: '/settings/word-mute', | ||||
| 		active: page.value === 'word-mute', | ||||
| 		active: props.initialPage === 'word-mute', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-key', | ||||
| 		text: 'API', | ||||
| 		to: '/settings/api', | ||||
| 		active: page.value === 'api', | ||||
| 		active: props.initialPage === 'api', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-bolt', | ||||
| 		text: 'Webhook', | ||||
| 		to: '/settings/webhook', | ||||
| 		active: page.value === 'webhook', | ||||
| 		active: props.initialPage === 'webhook', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-ellipsis-h', | ||||
| 		text: i18n.ts.other, | ||||
| 		to: '/settings/other', | ||||
| 		active: page.value === 'other', | ||||
| 		active: props.initialPage === 'other', | ||||
| 	}], | ||||
| }, { | ||||
| 	items: [{ | ||||
|  | @ -182,8 +194,8 @@ const menuDef = computed(() => [{ | |||
| 
 | ||||
| const pageProps = ref({}); | ||||
| const component = computed(() => { | ||||
| 	if (page.value == null) return null; | ||||
| 	switch (page.value) { | ||||
| 	if (props.initialPage == null) return null; | ||||
| 	switch (props.initialPage) { | ||||
| 		case 'accounts': return defineAsyncComponent(() => import('./accounts.vue')); | ||||
| 		case 'profile': return defineAsyncComponent(() => import('./profile.vue')); | ||||
| 		case 'privacy': return defineAsyncComponent(() => import('./privacy.vue')); | ||||
|  | @ -230,27 +242,41 @@ watch(component, () => { | |||
| 
 | ||||
| watch(() => props.initialPage, () => { | ||||
| 	if (props.initialPage == null && !narrow.value) { | ||||
| 		page.value = 'profile'; | ||||
| 		nav.push('/settings/profile'); | ||||
| 	} else { | ||||
| 		page.value = props.initialPage; | ||||
| 		if (props.initialPage == null) { | ||||
| 			INFO.value = indexInfo; | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
| 	narrow.value = el.value.offsetWidth < 800; | ||||
| 	if (!narrow.value) { | ||||
| 		page.value = 'profile'; | ||||
| watch(narrow, () => { | ||||
| 	if (props.initialPage == null && !narrow.value) { | ||||
| 		nav.push('/settings/profile'); | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
| 	ro.observe(el.value); | ||||
| 
 | ||||
| 	narrow.value = el.value.offsetWidth < NARROW_THRESHOLD; | ||||
| 	if (props.initialPage == null && !narrow.value) { | ||||
| 		nav.push('/settings/profile'); | ||||
| 	} | ||||
| }); | ||||
| 
 | ||||
| onUnmounted(() => { | ||||
| 	ro.disconnect(); | ||||
| }); | ||||
| 
 | ||||
| const emailNotConfigured = computed(() => instance.enableEmail && ($i.email == null || !$i.emailVerified)); | ||||
| 
 | ||||
| const pageChanged = (page) => { | ||||
| 	if (page == null) return; | ||||
| 	childInfo.value = page[symbols.PAGE_INFO]; | ||||
| 	if (page == null) { | ||||
| 		childInfo.value = null; | ||||
| 	} else { | ||||
| 		childInfo.value = page[symbols.PAGE_INFO]; | ||||
| 	} | ||||
| }; | ||||
| 
 | ||||
| defineExpose({ | ||||
|  | @ -267,6 +293,7 @@ defineExpose({ | |||
| 		font-weight: bold; | ||||
| 
 | ||||
| 		> .title { | ||||
| 			display: block; | ||||
| 			width: 34%; | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										34
									
								
								packages/client/src/scripts/navigate.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/client/src/scripts/navigate.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | |||
| import { inject } from 'vue'; | ||||
| import { router } from '@/router'; | ||||
| import { defaultStore } from '@/store'; | ||||
| 
 | ||||
| export type Navigate = (path: string, record?: boolean) => void; | ||||
| 
 | ||||
| export class MisskeyNavigator { | ||||
| 	public readonly navHook: Navigate | null = null; | ||||
| 	public readonly sideViewHook: Navigate | null = null; | ||||
| 
 | ||||
| 	// It should be constructed during vue creating in order for inject function to work
 | ||||
| 	constructor() { | ||||
| 		this.navHook = inject<Navigate | null>('navHook', null); | ||||
| 		this.sideViewHook = inject<Navigate | null>('sideViewHook', null); | ||||
| 	} | ||||
| 
 | ||||
| 	// Use this method instead of router.push()
 | ||||
| 	public push(path: string, record = true) { | ||||
| 		if (this.navHook) { | ||||
| 			this.navHook(path, record); | ||||
| 		} else { | ||||
| 			if (defaultStore.state.defaultSideView && this.sideViewHook && path !== '/') { | ||||
| 				return this.sideViewHook(path, record); | ||||
| 			} | ||||
| 	 | ||||
| 			if (router.currentRoute.value.path === path) { | ||||
| 				window.scroll({ top: 0, behavior: 'smooth' }); | ||||
| 			} else { | ||||
| 				if (record) router.push(path); | ||||
| 				else router.replace(path); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue