Merge branch 'develop' into toggle-ads
This commit is contained in:
		
						commit
						a8de112fe0
					
				
					 25 changed files with 183 additions and 169 deletions
				
			
		|  | @ -9,6 +9,13 @@ | |||
| You should also include the user name that made the change. | ||||
| --> | ||||
| 
 | ||||
| ## 12.x.x (unreleased) | ||||
| 
 | ||||
| ### Improvements | ||||
| 
 | ||||
| ### Bugfixes | ||||
| - クライアントが起動しなくなることがある問題を修正 @syuilo | ||||
| 
 | ||||
| ## 12.113.0 (2022/07/13) | ||||
| 
 | ||||
| ### Improvements | ||||
|  |  | |||
|  | @ -888,6 +888,7 @@ enableAutoSensitive: "自動NSFW判定" | |||
| enableAutoSensitiveDescription: "利用可能な場合は、機械学習を利用して自動でメディアにNSFWフラグを設定します。この機能をオフにしても、インスタンスによっては自動で設定されることがあります。" | ||||
| activeEmailValidationDescription: "ユーザーのメールアドレスのバリデーションを、捨てアドかどうかや実際に通信可能かどうかなどを判定しより積極的に行います。オフにすると単に文字列として正しいかどうかのみチェックされます。" | ||||
| showAds: "広告を表示する" | ||||
| navbar: "ナビゲーションバー" | ||||
| 
 | ||||
| _sensitiveMediaDetection: | ||||
|   description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。" | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| { | ||||
| 	"name": "misskey", | ||||
| 	"version": "12.113.0", | ||||
| 	"version": "12.114.0-beta.6", | ||||
| 	"codename": "indigo", | ||||
| 	"repository": { | ||||
| 		"type": "git", | ||||
|  |  | |||
|  | @ -14,9 +14,11 @@ | |||
| // ブロックの中に入れないと、定義した変数がブラウザのグローバルスコープに登録されてしまい邪魔なので
 | ||||
| (async () => { | ||||
| 	window.onerror = (e) => { | ||||
| 		console.error(e); | ||||
| 		renderError('SOMETHING_HAPPENED', e); | ||||
| 	}; | ||||
| 	window.onunhandledrejection = (e) => { | ||||
| 		console.error(e); | ||||
| 		renderError('SOMETHING_HAPPENED_IN_PROMISE', e); | ||||
| 	}; | ||||
| 
 | ||||
|  | @ -47,18 +49,30 @@ | |||
| 			localStorage.setItem('localeVersion', v); | ||||
| 		} else { | ||||
| 			await checkUpdate(); | ||||
| 			renderError('LOCALE_FETCH_FAILED'); | ||||
| 			renderError('LOCALE_FETCH'); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
| 	//#endregion
 | ||||
| 
 | ||||
| 	//#region Script
 | ||||
| 	import(`/assets/${CLIENT_ENTRY}`) | ||||
| 		.catch(async e => { | ||||
| 			await checkUpdate(); | ||||
| 			renderError('APP_FETCH_FAILED', e); | ||||
| 		}) | ||||
| 	function importAppScript() { | ||||
| 		import(`/assets/${CLIENT_ENTRY}`) | ||||
| 			.catch(async e => { | ||||
| 				await checkUpdate(); | ||||
| 				console.error(e); | ||||
| 				renderError('APP_IMPORT', e); | ||||
| 			}); | ||||
| 	} | ||||
| 
 | ||||
| 	// タイミングによっては、この時点でDOMの構築が済んでいる場合とそうでない場合とがある
 | ||||
| 	if (document.readyState !== 'loading') { | ||||
| 		importAppScript(); | ||||
| 	} else { | ||||
| 		window.addEventListener('DOMContentLoaded', () => { | ||||
| 			importAppScript(); | ||||
| 		}); | ||||
| 	} | ||||
| 	//#endregion
 | ||||
| 
 | ||||
| 	//#region Theme
 | ||||
|  | @ -112,35 +126,35 @@ | |||
| 		let errorsElement = document.getElementById('errors'); | ||||
| 
 | ||||
| 		if (!errorsElement) { | ||||
| 			document.documentElement.innerHTML = ` | ||||
| 			document.body.innerHTML = ` | ||||
| 			<svg class="icon-warning" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-alert-triangle" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"> | ||||
|    			<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> | ||||
|    			<path d="M12 9v2m0 4v.01"></path> | ||||
|    			<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path> | ||||
| 				<path stroke="none" d="M0 0h24v24H0z" fill="none"></path> | ||||
| 				<path d="M12 9v2m0 4v.01"></path> | ||||
| 				<path d="M5 19h14a2 2 0 0 0 1.84 -2.75l-7.1 -12.25a2 2 0 0 0 -3.5 0l-7.1 12.25a2 2 0 0 0 1.75 2.75"></path> | ||||
| 			</svg> | ||||
| 			<h1>An error has occurred!</h1> | ||||
| 			<button class="button-big" onclick="location.reload(true);"> | ||||
| 				<span class="button-label-big">Refresh</span> | ||||
| 			</button> | ||||
|       <p class="dont-worry">Don't worry, it's (probably) not your fault.</p> | ||||
| 			<p class="dont-worry">Don't worry, it's (probably) not your fault.</p> | ||||
| 			<p>If the problem persists after refreshing, please contact your instance's administrator.<br>You may also try the following options:</p> | ||||
|       <a href="/flush"> | ||||
|       <button class="button-small"> | ||||
|         <span class="button-label-small">Clear preferences and cache</span> | ||||
|       </button> | ||||
|       </a> | ||||
| 			<a href="/flush"> | ||||
| 				<button class="button-small"> | ||||
| 					<span class="button-label-small">Clear preferences and cache</span> | ||||
| 				</button> | ||||
| 			</a> | ||||
| 			<br> | ||||
|       <a href="/cli"> | ||||
|         <button class="button-small"> | ||||
|           <span class="button-label-small">Start the simple client</span> | ||||
|         </button> | ||||
|       </a> | ||||
| 			<a href="/cli"> | ||||
| 				<button class="button-small"> | ||||
| 					<span class="button-label-small">Start the simple client</span> | ||||
| 				</button> | ||||
| 			</a> | ||||
| 			<br> | ||||
|       <a href="/bios"> | ||||
|         <button class="button-small"> | ||||
|           <span class="button-label-small">Start the repair tool</span> | ||||
|         </button> | ||||
|       </a> | ||||
| 			<a href="/bios"> | ||||
| 				<button class="button-small"> | ||||
| 					<span class="button-label-small">Start the repair tool</span> | ||||
| 				</button> | ||||
| 			</a> | ||||
| 			<br> | ||||
| 			<div id="errors"></div> | ||||
| 			`;
 | ||||
|  | @ -269,17 +283,22 @@ | |||
| 
 | ||||
| 	// eslint-disable-next-line no-inner-declarations
 | ||||
| 	async function checkUpdate() { | ||||
| 		// TODO: サーバーが落ちている場合などのエラーハンドリング
 | ||||
| 		const res = await fetch('/api/meta', { | ||||
| 			method: 'POST', | ||||
| 			cache: 'no-cache' | ||||
| 		}); | ||||
| 		try { | ||||
| 			const res = await fetch('/api/meta', { | ||||
| 				method: 'POST', | ||||
| 				cache: 'no-cache' | ||||
| 			}); | ||||
| 
 | ||||
| 		const meta = await res.json(); | ||||
| 			const meta = await res.json(); | ||||
| 
 | ||||
| 		if (meta.version != v) { | ||||
| 			localStorage.setItem('v', meta.version); | ||||
| 			refresh(); | ||||
| 			if (meta.version != v) { | ||||
| 				localStorage.setItem('v', meta.version); | ||||
| 				refresh(); | ||||
| 			} | ||||
| 		} catch (e) { | ||||
| 			console.error(e); | ||||
| 			renderError('UPDATE_CHECK', e); | ||||
| 			throw e; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -56,7 +56,6 @@ | |||
| 		"random-seed": "0.3.0", | ||||
| 		"reflect-metadata": "0.1.13", | ||||
| 		"rndstr": "1.0.0", | ||||
| 		"rollup": "2.76.0", | ||||
| 		"s-age": "1.1.2", | ||||
| 		"sass": "1.53.0", | ||||
| 		"seedrandom": "3.0.5", | ||||
|  | @ -102,6 +101,7 @@ | |||
| 		"@types/ws": "8.5.3", | ||||
| 		"@typescript-eslint/eslint-plugin": "5.30.6", | ||||
| 		"@typescript-eslint/parser": "5.30.6", | ||||
| 		"rollup": "2.76.0", | ||||
| 		"cross-env": "7.0.3", | ||||
| 		"cypress": "10.3.0", | ||||
| 		"eslint": "8.19.0", | ||||
|  |  | |||
|  | @ -16,9 +16,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { useCssModule } from 'vue'; | ||||
| 
 | ||||
| useCssModule(); | ||||
| import { } from 'vue'; | ||||
| 
 | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	inline?: boolean; | ||||
|  |  | |||
|  | @ -36,7 +36,7 @@ | |||
| <script lang="ts" setup> | ||||
| import { } from 'vue'; | ||||
| import MkModal from '@/components/ui/modal.vue'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { instanceName } from '@/config'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { i18n } from '@/i18n'; | ||||
|  | @ -62,7 +62,7 @@ const modal = $ref<InstanceType<typeof MkModal>>(); | |||
| 
 | ||||
| const menu = defaultStore.state.menu; | ||||
| 
 | ||||
| const items = Object.keys(menuDef).filter(k => !menu.includes(k)).map(k => menuDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({ | ||||
| const items = Object.keys(navbarItemDef).filter(k => !menu.includes(k)).map(k => navbarItemDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({ | ||||
| 	type: def.to ? 'link' : 'button', | ||||
| 	text: i18n.ts[def.title], | ||||
| 	icon: def.icon, | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ | |||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { toUnicode } from 'punycode'; | ||||
| import { useCssModule } from 'vue'; | ||||
| import { } from 'vue'; | ||||
| import tinycolor from 'tinycolor2'; | ||||
| import { host as localHost } from '@/config'; | ||||
| import { $i } from '@/account'; | ||||
|  | @ -37,8 +37,6 @@ const isMe = $i && ( | |||
| const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention')); | ||||
| bg.setAlpha(0.1); | ||||
| const bgCss = bg.toRgbString(); | ||||
| 
 | ||||
| useCssModule(); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ const setPosition = () => { | |||
| 		let top: number; | ||||
| 
 | ||||
| 		if (props.targetElement) { | ||||
| 			left = (rect.left + window.pageXOffset) + props.innerMargin; | ||||
| 			left = (rect.left + props.targetElement.offsetWidth + window.pageXOffset) + props.innerMargin; | ||||
| 			top = rect.top + window.pageYOffset + (props.targetElement.offsetHeight / 2); | ||||
| 		} else { | ||||
| 			left = props.x + props.innerMargin; | ||||
|  |  | |||
|  | @ -8,7 +8,6 @@ import tooltip from './tooltip'; | |||
| import hotkey from './hotkey'; | ||||
| import appear from './appear'; | ||||
| import anim from './anim'; | ||||
| import stickyContainer from './sticky-container'; | ||||
| import clickAnime from './click-anime'; | ||||
| import panel from './panel'; | ||||
| import adaptiveBorder from './adaptive-border'; | ||||
|  | @ -24,7 +23,6 @@ export default function(app: App) { | |||
| 	app.directive('appear', appear); | ||||
| 	app.directive('anim', anim); | ||||
| 	app.directive('click-anime', clickAnime); | ||||
| 	app.directive('sticky-container', stickyContainer); | ||||
| 	app.directive('panel', panel); | ||||
| 	app.directive('adaptive-border', adaptiveBorder); | ||||
| } | ||||
|  |  | |||
|  | @ -1,17 +0,0 @@ | |||
| import { Directive } from 'vue'; | ||||
| 
 | ||||
| export default { | ||||
| 	mounted(src, binding, vn) { | ||||
| 		//const query = binding.value;
 | ||||
| 
 | ||||
| 		const header = src.children[0]; | ||||
| 		const body = src.children[1]; | ||||
| 		const currentStickyTop = getComputedStyle(src).getPropertyValue('--stickyTop') || '0px'; | ||||
| 		src.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`); | ||||
| 		if (body) body.dataset.stickyContainerHeaderHeight = header.offsetHeight.toString(); | ||||
| 		header.style.setProperty('--stickyTop', currentStickyTop); | ||||
| 		header.style.position = 'sticky'; | ||||
| 		header.style.top = 'var(--stickyTop)'; | ||||
| 		header.style.zIndex = '1'; | ||||
| 	}, | ||||
| } as Directive; | ||||
|  | @ -6,7 +6,7 @@ import { i18n } from '@/i18n'; | |||
| import { ui } from '@/config'; | ||||
| import { unisonReload } from '@/scripts/unison-reload'; | ||||
| 
 | ||||
| export const menuDef = reactive({ | ||||
| export const navbarItemDef = reactive({ | ||||
| 	notifications: { | ||||
| 		title: 'notifications', | ||||
| 		icon: 'fas fa-bell', | ||||
|  | @ -114,15 +114,15 @@ const menuDef = computed(() => [{ | |||
| 		to: '/settings/theme', | ||||
| 		active: props.initialPage === 'theme', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-list-ul', | ||||
| 		icon: 'fas fa-bars', | ||||
| 		text: i18n.ts.navbar, | ||||
| 		to: '/settings/navbar', | ||||
| 		active: props.initialPage === 'navbar', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-bars-progress', | ||||
| 		text: i18n.ts.statusbar, | ||||
| 		to: '/settings/statusbars', | ||||
| 		active: props.initialPage === 'statusbars', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-list-ul', | ||||
| 		text: i18n.ts.menu, | ||||
| 		to: '/settings/menu', | ||||
| 		active: props.initialPage === 'menu', | ||||
| 	}, { | ||||
| 		icon: 'fas fa-music', | ||||
| 		text: i18n.ts.sounds, | ||||
|  | @ -225,7 +225,7 @@ const component = computed(() => { | |||
| 		case 'theme': return defineAsyncComponent(() => import('./theme.vue')); | ||||
| 		case 'theme/install': return defineAsyncComponent(() => import('./theme.install.vue')); | ||||
| 		case 'theme/manage': return defineAsyncComponent(() => import('./theme.manage.vue')); | ||||
| 		case 'menu': return defineAsyncComponent(() => import('./menu.vue')); | ||||
| 		case 'navbar': return defineAsyncComponent(() => import('./navbar.vue')); | ||||
| 		case 'statusbars': return defineAsyncComponent(() => import('./statusbars.vue')); | ||||
| 		case 'sounds': return defineAsyncComponent(() => import('./sounds.vue')); | ||||
| 		case 'custom-css': return defineAsyncComponent(() => import('./custom-css.vue')); | ||||
|  | @ -291,6 +291,8 @@ const headerActions = $computed(() => []); | |||
| const headerTabs = $computed(() => []); | ||||
| 
 | ||||
| definePageMetadata(INFO); | ||||
| // w 890 | ||||
| // h 700 | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| <template> | ||||
| <div class="_formRoot"> | ||||
| 	<FormTextarea v-model="items" tall manual-save class="_formBlock"> | ||||
| 		<template #label>{{ i18n.ts.menu }}</template> | ||||
| 		<template #label>{{ i18n.ts.navbar }}</template> | ||||
| 		<template #caption><button class="_textButton" @click="addItem">{{ i18n.ts.addItem }}</button></template> | ||||
| 	</FormTextarea> | ||||
| 
 | ||||
|  | @ -23,7 +23,7 @@ import FormTextarea from '@/components/form/textarea.vue'; | |||
| import FormRadios from '@/components/form/radios.vue'; | ||||
| import FormButton from '@/components/ui/button.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { unisonReload } from '@/scripts/unison-reload'; | ||||
| import { i18n } from '@/i18n'; | ||||
|  | @ -45,11 +45,11 @@ async function reloadAsk() { | |||
| } | ||||
| 
 | ||||
| async function addItem() { | ||||
| 	const menu = Object.keys(menuDef).filter(k => !defaultStore.state.menu.includes(k)); | ||||
| 	const menu = Object.keys(navbarItemDef).filter(k => !defaultStore.state.menu.includes(k)); | ||||
| 	const { canceled, result: item } = await os.select({ | ||||
| 		title: i18n.ts.addItem, | ||||
| 		items: [...menu.map(k => ({ | ||||
| 			value: k, text: i18n.ts[menuDef[k].title], | ||||
| 			value: k, text: i18n.ts[navbarItemDef[k].title], | ||||
| 		})), { | ||||
| 			value: '-', text: i18n.ts.divider, | ||||
| 		}], | ||||
|  | @ -81,7 +81,7 @@ const headerActions = $computed(() => []); | |||
| const headerTabs = $computed(() => []); | ||||
| 
 | ||||
| definePageMetadata({ | ||||
| 	title: i18n.ts.menu, | ||||
| 	title: i18n.ts.navbar, | ||||
| 	icon: 'fas fa-list-ul', | ||||
| }); | ||||
| </script> | ||||
|  | @ -12,7 +12,7 @@ | |||
| 	 | ||||
| 	<FormSection> | ||||
| 		<template #label>{{ i18n.ts.signinHistory }}</template> | ||||
| 		<MkPagination :pagination="pagination"> | ||||
| 		<MkPagination :pagination="pagination" disable-auto-load> | ||||
| 			<template #default="{items}"> | ||||
| 				<div> | ||||
| 					<div v-for="item in items" :key="item.id" v-panel class="timnmucd"> | ||||
|  |  | |||
|  | @ -86,7 +86,6 @@ import FormRadios from '@/components/form/radios.vue'; | |||
| import FormButton from '@/components/ui/button.vue'; | ||||
| import FormRange from '@/components/form/range.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { i18n } from '@/i18n'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,12 +1,14 @@ | |||
| <template> | ||||
| <div v-sticky-container class="yrzkoczt"> | ||||
| 	<MkTab v-model="include" class="tab"> | ||||
| 		<option :value="null">{{ $ts.notes }}</option> | ||||
| 		<option value="replies">{{ $ts.notesAndReplies }}</option> | ||||
| 		<option value="files">{{ $ts.withFiles }}</option> | ||||
| 	</MkTab> | ||||
| <MkStickyContainer> | ||||
| 	<template #header> | ||||
| 		<MkTab v-model="include" :class="$style.tab"> | ||||
| 			<option :value="null">{{ $ts.notes }}</option> | ||||
| 			<option value="replies">{{ $ts.notesAndReplies }}</option> | ||||
| 			<option value="files">{{ $ts.withFiles }}</option> | ||||
| 		</MkTab> | ||||
| 	</template> | ||||
| 	<XNotes :no-gap="true" :pagination="pagination"/> | ||||
| </div> | ||||
| </MkStickyContainer> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
|  | @ -33,12 +35,10 @@ const pagination = { | |||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" scoped> | ||||
| .yrzkoczt { | ||||
| 	> .tab { | ||||
| 		margin: calc(var(--margin) / 2) 0; | ||||
| 		padding: calc(var(--margin) / 2) 0; | ||||
| 		background: var(--bg); | ||||
| 	} | ||||
| <style lang="scss" module> | ||||
| .tab { | ||||
| 	margin: calc(var(--margin) / 2) 0; | ||||
| 	padding: calc(var(--margin) / 2) 0; | ||||
| 	background: var(--bg); | ||||
| } | ||||
| </style> | ||||
|  |  | |||
|  | @ -9,9 +9,9 @@ | |||
| 		</MkA> | ||||
| 		<template v-for="item in menu"> | ||||
| 			<div v-if="item === '-'" class="divider"></div> | ||||
| 			<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: menuDef[item].active }]" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> | ||||
| 				<i class="icon fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span> | ||||
| 				<span v-if="menuDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> | ||||
| 			<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: navbarItemDef[item].active }]" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> | ||||
| 				<i class="icon fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ $ts[navbarItemDef[item].title] }}</span> | ||||
| 				<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> | ||||
| 			</component> | ||||
| 		</template> | ||||
| 		<div class="divider"></div> | ||||
|  | @ -37,7 +37,7 @@ import { computed, defineAsyncComponent, defineComponent, ref, toRef, watch } fr | |||
| import { host } from '@/config'; | ||||
| import { search } from '@/scripts/search'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { openAccountMenu } from '@/account'; | ||||
| import { defaultStore } from '@/store'; | ||||
| 
 | ||||
|  | @ -45,9 +45,9 @@ export default defineComponent({ | |||
| 	setup(props, context) { | ||||
| 		const menu = toRef(defaultStore.state, 'menu'); | ||||
| 		const otherMenuItemIndicated = computed(() => { | ||||
| 			for (const def in menuDef) { | ||||
| 			for (const def in navbarItemDef) { | ||||
| 				if (menu.value.includes(def)) continue; | ||||
| 				if (menuDef[def].indicated) return true; | ||||
| 				if (navbarItemDef[def].indicated) return true; | ||||
| 			} | ||||
| 			return false; | ||||
| 		}); | ||||
|  | @ -57,7 +57,7 @@ export default defineComponent({ | |||
| 			accounts: [], | ||||
| 			connection: null, | ||||
| 			menu, | ||||
| 			menuDef: menuDef, | ||||
| 			navbarItemDef: navbarItemDef, | ||||
| 			otherMenuItemIndicated, | ||||
| 			post: os.post, | ||||
| 			search, | ||||
|  | @ -4,29 +4,38 @@ | |||
| 		<button v-click-anime class="item _button account" @click="openAccountMenu"> | ||||
| 			<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/> | ||||
| 		</button> | ||||
| 		<MkA v-click-anime class="item index" active-class="active" to="/" exact> | ||||
| 			<i class="icon fas fa-home fa-fw"></i><span class="text">{{ $ts.timeline }}</span> | ||||
| 		<MkA v-click-anime v-tooltip.right="i18n.ts.timeline" class="item index" active-class="active" to="/" exact> | ||||
| 			<i class="icon fas fa-home fa-fw"></i><span class="text">{{ i18n.ts.timeline }}</span> | ||||
| 		</MkA> | ||||
| 		<template v-for="item in menu"> | ||||
| 			<div v-if="item === '-'" class="divider"></div> | ||||
| 			<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime class="item _button" :class="[item, { active: menuDef[item].active }]" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> | ||||
| 				<i class="icon fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span> | ||||
| 				<span v-if="menuDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> | ||||
| 			<component | ||||
| 				:is="navbarItemDef[item].to ? 'MkA' : 'button'" | ||||
| 				v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" | ||||
| 				v-click-anime v-tooltip.right="i18n.ts[navbarItemDef[item].title]" | ||||
| 				class="item _button" | ||||
| 				:class="[item, { active: navbarItemDef[item].active }]" | ||||
| 				active-class="active" | ||||
| 				:to="navbarItemDef[item].to" | ||||
| 				v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}" | ||||
| 			> | ||||
| 				<i class="icon fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ i18n.ts[navbarItemDef[item].title] }}</span> | ||||
| 				<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="icon fas fa-circle"></i></span> | ||||
| 			</component> | ||||
| 		</template> | ||||
| 		<div class="divider"></div> | ||||
| 		<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime class="item" active-class="active" to="/admin"> | ||||
| 			<i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span> | ||||
| 		<MkA v-if="$i.isAdmin || $i.isModerator" v-click-anime v-tooltip.right="i18n.ts.controlPanel" class="item" active-class="active" to="/admin"> | ||||
| 			<i class="icon fas fa-door-open fa-fw"></i><span class="text">{{ i18n.ts.controlPanel }}</span> | ||||
| 		</MkA> | ||||
| 		<button v-click-anime class="item _button" @click="more"> | ||||
| 			<i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> | ||||
| 			<i class="icon fa fa-ellipsis-h fa-fw"></i><span class="text">{{ i18n.ts.more }}</span> | ||||
| 			<span v-if="otherMenuItemIndicated" class="indicator"><i class="icon fas fa-circle"></i></span> | ||||
| 		</button> | ||||
| 		<MkA v-click-anime class="item" active-class="active" to="/settings"> | ||||
| 			<i class="icon fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span> | ||||
| 		<MkA v-click-anime v-tooltip.right="i18n.ts.settings" class="item" active-class="active" to="/settings"> | ||||
| 			<i class="icon fas fa-cog fa-fw"></i><span class="text">{{ i18n.ts.settings }}</span> | ||||
| 		</MkA> | ||||
| 		<button class="item _button post" data-cy-open-post-form @click="os.post"> | ||||
| 			<i class="icon fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span> | ||||
| 			<i class="icon fas fa-pencil-alt fa-fw"></i><span class="text">{{ i18n.ts.note }}</span> | ||||
| 		</button> | ||||
| 	</div> | ||||
| </div> | ||||
|  | @ -35,17 +44,18 @@ | |||
| <script lang="ts" setup> | ||||
| import { computed, defineAsyncComponent, ref, watch } from 'vue'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { $i, openAccountMenu as openAccountMenu_ } from '@/account'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { i18n } from '@/i18n'; | ||||
| 
 | ||||
| const iconOnly = ref(false); | ||||
| 
 | ||||
| const menu = computed(() => defaultStore.state.menu); | ||||
| const otherMenuItemIndicated = computed(() => { | ||||
| 	for (const def in menuDef) { | ||||
| 	for (const def in navbarItemDef) { | ||||
| 		if (menu.value.includes(def)) continue; | ||||
| 		if (menuDef[def].indicated) return true; | ||||
| 		if (navbarItemDef[def].indicated) return true; | ||||
| 	} | ||||
| 	return false; | ||||
| }); | ||||
|  | @ -244,7 +254,7 @@ function more(ev: MouseEvent) { | |||
| 				padding: 18px 0; | ||||
| 				width: 100%; | ||||
| 				text-align: center; | ||||
| 				font-size: $ui-font-size * 1.1; | ||||
| 				font-size: $ui-font-size; | ||||
| 				line-height: initial; | ||||
| 
 | ||||
| 				> .icon, | ||||
|  | @ -7,9 +7,9 @@ | |||
| 			</MkA> | ||||
| 			<template v-for="item in menu"> | ||||
| 				<div v-if="item === '-'" class="divider"></div> | ||||
| 				<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime v-tooltip="$ts[menuDef[item].title]" class="item _button" :class="item" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> | ||||
| 					<i class="fa-fw" :class="menuDef[item].icon"></i> | ||||
| 					<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span> | ||||
| 				<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime v-tooltip="$ts[navbarItemDef[item].title]" class="item _button" :class="item" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> | ||||
| 					<i class="fa-fw" :class="navbarItemDef[item].icon"></i> | ||||
| 					<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span> | ||||
| 				</component> | ||||
| 			</template> | ||||
| 			<div class="divider"></div> | ||||
|  | @ -43,7 +43,7 @@ import { defineAsyncComponent, defineComponent } from 'vue'; | |||
| import { host } from '@/config'; | ||||
| import { search } from '@/scripts/search'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { openAccountMenu } from '@/account'; | ||||
| import MkButton from '@/components/ui/button.vue'; | ||||
| 
 | ||||
|  | @ -57,7 +57,7 @@ export default defineComponent({ | |||
| 			host: host, | ||||
| 			accounts: [], | ||||
| 			connection: null, | ||||
| 			menuDef: menuDef, | ||||
| 			navbarItemDef: navbarItemDef, | ||||
| 			settingsWindowed: false, | ||||
| 		}; | ||||
| 	}, | ||||
|  | @ -68,9 +68,9 @@ export default defineComponent({ | |||
| 		}, | ||||
| 
 | ||||
| 		otherNavItemIndicated(): boolean { | ||||
| 			for (const def in this.menuDef) { | ||||
| 			for (const def in this.navbarItemDef) { | ||||
| 				if (this.menu.includes(def)) continue; | ||||
| 				if (this.menuDef[def].indicated) return true; | ||||
| 				if (this.navbarItemDef[def].indicated) return true; | ||||
| 			} | ||||
| 			return false; | ||||
| 		}, | ||||
|  | @ -113,7 +113,7 @@ export default defineComponent({ | |||
| 				withExtraOperation: true, | ||||
| 			}, ev); | ||||
| 		}, | ||||
| 	} | ||||
| 	}, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  |  | |||
|  | @ -14,9 +14,9 @@ | |||
| 	</MkA> | ||||
| 	<template v-for="item in menu"> | ||||
| 		<div v-if="item === '-'" class="divider"></div> | ||||
| 		<component :is="menuDef[item].to ? 'MkA' : 'button'" v-else-if="menuDef[item] && (menuDef[item].show !== false)" v-click-anime class="item _button" :class="item" active-class="active" :to="menuDef[item].to" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}"> | ||||
| 			<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span> | ||||
| 			<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span> | ||||
| 		<component :is="navbarItemDef[item].to ? 'MkA' : 'button'" v-else-if="navbarItemDef[item] && (navbarItemDef[item].show !== false)" v-click-anime class="item _button" :class="item" active-class="active" :to="navbarItemDef[item].to" v-on="navbarItemDef[item].action ? { click: navbarItemDef[item].action } : {}"> | ||||
| 			<i class="fa-fw" :class="navbarItemDef[item].icon"></i><span class="text">{{ $ts[navbarItemDef[item].title] }}</span> | ||||
| 			<span v-if="navbarItemDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span> | ||||
| 		</component> | ||||
| 	</template> | ||||
| 	<div class="divider"></div> | ||||
|  | @ -45,7 +45,7 @@ import { defineAsyncComponent, defineComponent } from 'vue'; | |||
| import { host } from '@/config'; | ||||
| import { search } from '@/scripts/search'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { openAccountMenu } from '@/account'; | ||||
| import MkButton from '@/components/ui/button.vue'; | ||||
| import { StickySidebar } from '@/scripts/sticky-sidebar'; | ||||
|  | @ -62,7 +62,7 @@ export default defineComponent({ | |||
| 			host: host, | ||||
| 			accounts: [], | ||||
| 			connection: null, | ||||
| 			menuDef: menuDef, | ||||
| 			navbarItemDef: navbarItemDef, | ||||
| 			iconOnly: false, | ||||
| 			settingsWindowed: false, | ||||
| 		}; | ||||
|  | @ -74,9 +74,9 @@ export default defineComponent({ | |||
| 		}, | ||||
| 
 | ||||
| 		otherNavItemIndicated(): boolean { | ||||
| 			for (const def in this.menuDef) { | ||||
| 			for (const def in this.navbarItemDef) { | ||||
| 				if (this.menu.includes(def)) continue; | ||||
| 				if (this.menuDef[def].indicated) return true; | ||||
| 				if (this.navbarItemDef[def].indicated) return true; | ||||
| 			} | ||||
| 			return false; | ||||
| 		}, | ||||
|  | @ -131,7 +131,7 @@ export default defineComponent({ | |||
| 				withExtraOperation: true, | ||||
| 			}, ev); | ||||
| 		}, | ||||
| 	} | ||||
| 	}, | ||||
| }); | ||||
| </script> | ||||
| 
 | ||||
|  |  | |||
|  | @ -47,7 +47,6 @@ import XCommon from './_common_/common.vue'; | |||
| import { instanceName } from '@/config'; | ||||
| import { StickySidebar } from '@/scripts/sticky-sidebar'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { mainRouter } from '@/router'; | ||||
| import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | ||||
| import { defaultStore } from '@/store'; | ||||
|  |  | |||
|  | @ -69,12 +69,12 @@ import { v4 as uuid } from 'uuid'; | |||
| import XCommon from './_common_/common.vue'; | ||||
| import { deckStore, addColumn as addColumnToStore, loadDeck } from './deck/deck-store'; | ||||
| import DeckColumnCore from '@/ui/deck/column-core.vue'; | ||||
| import XSidebar from '@/ui/_common_/sidebar.vue'; | ||||
| import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; | ||||
| import XSidebar from '@/ui/_common_/navbar.vue'; | ||||
| import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; | ||||
| import MkButton from '@/components/ui/button.vue'; | ||||
| import { getScrollContainer } from '@/scripts/scroll'; | ||||
| import * as os from '@/os'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { $i } from '@/account'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { mainRouter } from '@/router'; | ||||
|  | @ -105,8 +105,8 @@ const columns = deckStore.reactiveState.columns; | |||
| const layout = deckStore.reactiveState.layout; | ||||
| const menuIndicated = computed(() => { | ||||
| 	if ($i == null) return false; | ||||
| 	for (const def in menuDef) { | ||||
| 		if (menuDef[def].indicated) return true; | ||||
| 	for (const def in navbarItemDef) { | ||||
| 		if (navbarItemDef[def].indicated) return true; | ||||
| 	} | ||||
| 	return false; | ||||
| }); | ||||
|  |  | |||
|  | @ -61,17 +61,17 @@ import { defineAsyncComponent, provide, onMounted, computed, ref, watch, Compute | |||
| import XCommon from './_common_/common.vue'; | ||||
| import { instanceName } from '@/config'; | ||||
| import { StickySidebar } from '@/scripts/sticky-sidebar'; | ||||
| import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; | ||||
| import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; | ||||
| import * as os from '@/os'; | ||||
| import { defaultStore } from '@/store'; | ||||
| import { menuDef } from '@/menu'; | ||||
| import { navbarItemDef } from '@/navbar'; | ||||
| import { i18n } from '@/i18n'; | ||||
| import { $i } from '@/account'; | ||||
| import { Router } from '@/nirax'; | ||||
| import { mainRouter } from '@/router'; | ||||
| import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | ||||
| const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); | ||||
| const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/sidebar.vue')); | ||||
| const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); | ||||
| const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); | ||||
| 
 | ||||
| const DESKTOP_THRESHOLD = 1100; | ||||
|  | @ -97,9 +97,9 @@ provideMetadataReceiver((info) => { | |||
| }); | ||||
| 
 | ||||
| const menuIndicated = computed(() => { | ||||
| 	for (const def in menuDef) { | ||||
| 	for (const def in navbarItemDef) { | ||||
| 		if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから | ||||
| 		if (menuDef[def].indicated) return true; | ||||
| 		if (navbarItemDef[def].indicated) return true; | ||||
| 	} | ||||
| 	return false; | ||||
| }); | ||||
|  |  | |||
|  | @ -6,33 +6,33 @@ import { createFilter, dataToEsm } from '@rollup/pluginutils'; | |||
| import { RollupJsonOptions } from '@rollup/plugin-json'; | ||||
| 
 | ||||
| export default function json5(options: RollupJsonOptions = {}): Plugin { | ||||
|   const filter = createFilter(options.include, options.exclude); | ||||
|   const indent = 'indent' in options ? options.indent : '\t'; | ||||
| 	const filter = createFilter(options.include, options.exclude); | ||||
| 	const indent = 'indent' in options ? options.indent : '\t'; | ||||
| 
 | ||||
|   return { | ||||
|     name: 'json5', | ||||
| 	return { | ||||
| 		name: 'json5', | ||||
| 
 | ||||
|     // eslint-disable-next-line no-shadow
 | ||||
|     transform(json, id) { | ||||
|       if (id.slice(-6) !== '.json5' || !filter(id)) return null; | ||||
| 		// eslint-disable-next-line no-shadow
 | ||||
| 		transform(json, id) { | ||||
| 			if (id.slice(-6) !== '.json5' || !filter(id)) return null; | ||||
| 
 | ||||
|       try { | ||||
|         const parsed = JSON5.parse(json); | ||||
|         return { | ||||
|           code: dataToEsm(parsed, { | ||||
|             preferConst: options.preferConst, | ||||
|             compact: options.compact, | ||||
|             namedExports: options.namedExports, | ||||
|             indent | ||||
|           }), | ||||
|           map: { mappings: '' } | ||||
|         }; | ||||
|       } catch (err) { | ||||
|         const message = 'Could not parse JSON file'; | ||||
|         const position = parseInt(/[\d]/.exec(err.message)[0], 10); | ||||
|         this.warn({ message, id, position }); | ||||
|         return null; | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| 			try { | ||||
| 				const parsed = JSON5.parse(json); | ||||
| 				return { | ||||
| 					code: dataToEsm(parsed, { | ||||
| 						preferConst: options.preferConst, | ||||
| 						compact: options.compact, | ||||
| 						namedExports: options.namedExports, | ||||
| 						indent, | ||||
| 					}), | ||||
| 					map: { mappings: '' }, | ||||
| 				}; | ||||
| 			} catch (err) { | ||||
| 				const message = 'Could not parse JSON file'; | ||||
| 				const position = parseInt(/[\d]/.exec(err.message)[0], 10); | ||||
| 				this.warn({ message, id, position }); | ||||
| 				return null; | ||||
| 			} | ||||
| 		}, | ||||
| 	}; | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue