diff options
| author | syuilo <4439005+syuilo@users.noreply.github.com> | 2025-03-09 12:34:08 +0900 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-03-09 12:34:08 +0900 |
| commit | d30ddd4c2ebcacc0d0b49c74e8dfe05b5422ba2e (patch) | |
| tree | c0c87a30037d3ffc11784627e67a1965b262c336 /packages/frontend/src/ui | |
| parent | [skip ci] Update CHANGELOG.md (prepend template) (diff) | |
| download | sharkey-d30ddd4c2ebcacc0d0b49c74e8dfe05b5422ba2e.tar.gz sharkey-d30ddd4c2ebcacc0d0b49c74e8dfe05b5422ba2e.tar.bz2 sharkey-d30ddd4c2ebcacc0d0b49c74e8dfe05b5422ba2e.zip | |
Refine preferences (#15597)
* wip
* wip
* wip
* test
* wip rollup pluginでsearchIndexの情報生成
* wip
* SPDX
* wip: markerIdを自動付与
* rollupでビルド時・devモード時に毎回uuidを生成するように
* 開発サーバーでだけ必要な挙動は開発サーバーのみで
* 条件が逆
* wip: childrenの生成
* update comment
* update comment
* rename auto generated file
* hashをパスと行数から決定
* Update privacy.vue
* Update privacy.vue
* wip
* Update general.vue
* Update general.vue
* wip
* wip
* Update SearchMarker.vue
* wip
* Update profile.vue
* Update mute-block.vue
* Update mute-block.vue
* Update general.vue
* Update general.vue
* childrenがduplicate key errorを吐く問題をいったん解決
* マーカーの形を成形
* loggerを置きかえ
* とりあえず省略記法に対応
* Refactor and Format codes
* wip
* Update settings-search-index.ts
* wip
* wip
* とりあえず不確定要因の仮置きidを削除
* hashの生成を正規化(絶対パスになっていたのを緩和)
* pathの入力を省略可能に
* adminでもパス生成できるように
* Update settings-search-index.ts
* Update privacy.vue
* wip
* build searchIndex
* wip
* build
* Update general.vue
* build
* Update sounds.vue
* build
* build
* Update sounds.vue
* 🎨
* 🎨
* Update privacy.vue
* Update privacy.vue
* Update security.vue
* create-search-indexを多少改善
* build
* Update 2fa.vue
* wip
* 必ずtransformCodeCacheを利用するように, キャッシュの明確な受け渡しを定義
* キャッシュはdevServerでなくても更新
* Revert "wip"
This reverts commit 41bffd3a13f55618bf939dc1c9acb2a77ead4054.
* inlining
* wip
* Update theme.vue
* 🎨
* wip normalize
* Update theme.vue
* キャッシュのパス変換
* build
* wip
* wip
* Update SearchMarker.vue
* i18n.ts['key'] の形式が取り出せない問題のFix
* build
* 仮でpath入れ
* 必ず絶対パスが使われるように
* wip
* 🎨
* storybookビルド時はcreateSearchIndexをしない
* inliningの構造化
* format code
* Update index.vue
* wip
* wip
* 🎨
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* wip
* clean up
* wip
* wip
* wip
* Update rollup-plugin-unwind-css-module-class-name.test.ts
* Update navbar.vue
* clean up
* wip
* wip
* wip
* wip
* wip
* Update preferences-backups.vue
* Update common.ts
* Update preferences.ts
* wip
* wip
* wip
* wip
* Update MkPreferenceContainer.vue
* Update MkPreferenceContainer.vue
* Update MkPreferenceContainer.vue
* enhance: 検索で上下矢印を使用することで検索結果を移動できるように
* Update main-boot.ts
* refactor
* wip
* Update sounds.vue
* fix(frontend): PageWindowでSearchMarkerが動作するように
* enhance(frontend): SearchMarkerの点滅を一定時間で止める
* wip
* lint fix
* fix: 子要素監視が抜けていたのを修正
* アニメーションの回数はCSSで制御するように
* refactor
* enhance(frontend): 検索インデックス作成時のログを削減
* revert
* fix
* fix
* Update preferences.ts
* Update preferences.ts
* wip
* Update preferences.ts
* wip
* 🎨
* wip
* Update MkPreferenceContainer.vue
* wip
* Update preferences.ts
* wip
* Update preferences.ts
* Update preferences.ts
* wip
* wip
* Update preferences.ts
* wip
* wip
* Update preferences.ts
* Update CHANGELOG.md
* Update preferences.ts
* Update deck-store.ts
* deckStoreをdefaultStoreに統合
* wip
* defaultStore -> store
* Update profile.ts
* wip
* refactor
* wip: plugin
* plugin
* plugin
* plugin
* Update plugin.ts
* wip
* Update plugin.vue
* Update preferences.ts
* Update main-boot.ts
* wip
* fix test
* Update plugin.vue
* Update plugin.vue
* Update utility.ts
* wip
* wip
* Update utility.ts
* wip
* wip
* clean up
* Update utility.ts
---------
Co-authored-by: tai-cha <dev@taichan.site>
Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
Diffstat (limited to 'packages/frontend/src/ui')
26 files changed, 226 insertions, 465 deletions
diff --git a/packages/frontend/src/ui/_common_/PreferenceRestore.vue b/packages/frontend/src/ui/_common_/PreferenceRestore.vue new file mode 100644 index 0000000000..0412733350 --- /dev/null +++ b/packages/frontend/src/ui/_common_/PreferenceRestore.vue @@ -0,0 +1,73 @@ +<!-- +SPDX-FileCopyrightText: syuilo and misskey-project +SPDX-License-Identifier: AGPL-3.0-only +--> + +<template> +<div :class="$style.root"> + <span :class="$style.icon"> + <i class="ti ti-info-circle"></i> + </span> + <span :class="$style.title">{{ i18n.ts._preferencesBackup.backupFound }}</span> + <span :class="$style.body"><button class="_textButton" @click="restore">{{ i18n.ts.restore }}</button> | <button class="_textButton" @click="skip">{{ i18n.ts.skip }}</button></span> +</div> +</template> + +<script lang="ts" setup> +import { $i } from '@/account.js'; +import { i18n } from '@/i18n.js'; +import { hideRestoreBackupSuggestion, restoreFromCloudBackup } from '@/preferences/utility.js'; + +function restore() { + restoreFromCloudBackup(); +} + +function skip() { + hideRestoreBackupSuggestion(); +} +</script> + +<style lang="scss" module> +.root { + --height: 24px; + font-size: 0.85em; + display: flex; + vertical-align: bottom; + width: 100%; + line-height: var(--height); + height: var(--height); + overflow: clip; + contain: strict; + background: var(--MI_THEME-panel); + + @container (max-width: 1000px) { + display: block; + text-align: center; + + > .body { + display: none; + } + } +} + +.icon { + margin-left: 10px; +} + +.title { + padding: 0 10px; + font-weight: bold; + + &:empty { + display: none; + } +} + +.body { + min-width: 0; + flex: 1; + overflow: clip; + white-space: nowrap; + text-overflow: ellipsis; +} +</style> diff --git a/packages/frontend/src/ui/_common_/common.vue b/packages/frontend/src/ui/_common_/common.vue index d145b9b6c6..51645f9676 100644 --- a/packages/frontend/src/ui/_common_/common.vue +++ b/packages/frontend/src/ui/_common_/common.vue @@ -17,18 +17,18 @@ SPDX-License-Identifier: AGPL-3.0-only <TransitionGroup tag="div" :class="[$style.notifications, { - [$style.notificationsPosition_leftTop]: defaultStore.state.notificationPosition === 'leftTop', - [$style.notificationsPosition_leftBottom]: defaultStore.state.notificationPosition === 'leftBottom', - [$style.notificationsPosition_rightTop]: defaultStore.state.notificationPosition === 'rightTop', - [$style.notificationsPosition_rightBottom]: defaultStore.state.notificationPosition === 'rightBottom', - [$style.notificationsStackAxis_vertical]: defaultStore.state.notificationStackAxis === 'vertical', - [$style.notificationsStackAxis_horizontal]: defaultStore.state.notificationStackAxis === 'horizontal', + [$style.notificationsPosition_leftTop]: prefer.s.notificationPosition === 'leftTop', + [$style.notificationsPosition_leftBottom]: prefer.s.notificationPosition === 'leftBottom', + [$style.notificationsPosition_rightTop]: prefer.s.notificationPosition === 'rightTop', + [$style.notificationsPosition_rightBottom]: prefer.s.notificationPosition === 'rightBottom', + [$style.notificationsStackAxis_vertical]: prefer.s.notificationStackAxis === 'vertical', + [$style.notificationsStackAxis_horizontal]: prefer.s.notificationStackAxis === 'horizontal', }]" - :moveClass="defaultStore.state.animation ? $style.transition_notification_move : ''" - :enterActiveClass="defaultStore.state.animation ? $style.transition_notification_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_notification_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_notification_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_notification_leaveTo : ''" + :moveClass="prefer.s.animation ? $style.transition_notification_move : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_notification_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_notification_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_notification_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_notification_leaveTo : ''" > <div v-for="notification in notifications" :key="notification.id" :class="$style.notification"> <XNotification :notification="notification"/> @@ -56,7 +56,7 @@ import * as sound from '@/scripts/sound.js'; import { $i } from '@/account.js'; import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; -import { defaultStore } from '@/store.js'; +import { prefer } from '@/preferences.js'; import { globalEvents } from '@/events.js'; const XStreamIndicator = defineAsyncComponent(() => import('./stream-indicator.vue')); diff --git a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue index 44253e93bd..698e9d8d47 100644 --- a/packages/frontend/src/ui/_common_/navbar-for-mobile.vue +++ b/packages/frontend/src/ui/_common_/navbar-for-mobile.vue @@ -54,11 +54,11 @@ import { openInstanceMenu } from './common.js'; import * as os from '@/os.js'; import { navbarItemDef } from '@/navbar.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; -import { defaultStore } from '@/store.js'; +import { prefer } from '@/preferences.js'; import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; -const menu = toRef(defaultStore.state, 'menu'); +const menu = toRef(prefer.s, 'menu'); const otherMenuItemIndicated = computed(() => { for (const def in navbarItemDef) { if (menu.value.includes(def)) continue; diff --git a/packages/frontend/src/ui/_common_/navbar.vue b/packages/frontend/src/ui/_common_/navbar.vue index fec8666dc1..1fb99f9f22 100644 --- a/packages/frontend/src/ui/_common_/navbar.vue +++ b/packages/frontend/src/ui/_common_/navbar.vue @@ -94,20 +94,21 @@ import { openInstanceMenu } from './common.js'; import * as os from '@/os.js'; import { navbarItemDef } from '@/navbar.js'; import { $i, openAccountMenu as openAccountMenu_ } from '@/account.js'; -import { defaultStore } from '@/store.js'; +import { store } from '@/store.js'; import { i18n } from '@/i18n.js'; import { instance } from '@/instance.js'; import { getHTMLElementOrNull } from '@/scripts/get-dom-node-or-null.js'; import { useRouter } from '@/router/supplier.js'; +import { prefer } from '@/preferences.js'; const router = useRouter(); const forceIconOnly = ref(window.innerWidth <= 1279); const iconOnly = computed(() => { - return forceIconOnly.value || (defaultStore.reactiveState.menuDisplay.value === 'sideIcon'); + return forceIconOnly.value || (store.reactiveState.menuDisplay.value === 'sideIcon'); }); -const menu = computed(() => defaultStore.state.menu); +const menu = computed(() => prefer.s.menu); const otherMenuItemIndicated = computed(() => { for (const def in navbarItemDef) { if (menu.value.includes(def)) continue; @@ -122,12 +123,12 @@ function calcViewState() { window.addEventListener('resize', calcViewState); -watch(defaultStore.reactiveState.menuDisplay, () => { +watch(store.reactiveState.menuDisplay, () => { calcViewState(); }); function toggleIconOnly() { - defaultStore.set('menuDisplay', iconOnly.value ? 'sideFull' : 'sideIcon'); + store.set('menuDisplay', iconOnly.value ? 'sideFull' : 'sideIcon'); } function openAccountMenu(ev: MouseEvent) { diff --git a/packages/frontend/src/ui/_common_/statusbars.vue b/packages/frontend/src/ui/_common_/statusbars.vue index ed881bef22..a8d87599e6 100644 --- a/packages/frontend/src/ui/_common_/statusbars.vue +++ b/packages/frontend/src/ui/_common_/statusbars.vue @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only <template> <div :class="$style.root"> <div - v-for="x in defaultStore.reactiveState.statusbars.value" :key="x.id" :class="[$style.item, { [$style.black]: x.black, + v-for="x in prefer.r.statusbars.value" :key="x.id" :class="[$style.item, { [$style.black]: x.black, [$style.verySmall]: x.size === 'verySmall', [$style.small]: x.size === 'small', [$style.large]: x.size === 'large', @@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { defineAsyncComponent } from 'vue'; import { instance } from '@/instance.js'; -import { defaultStore } from '@/store.js'; +import { prefer } from '@/preferences.js'; const XRss = defineAsyncComponent(() => import('./statusbar-rss.vue')); const XFederation = defineAsyncComponent(() => import('./statusbar-federation.vue')); const XUserList = defineAsyncComponent(() => import('./statusbar-user-list.vue')); diff --git a/packages/frontend/src/ui/_common_/stream-indicator.vue b/packages/frontend/src/ui/_common_/stream-indicator.vue index cc62a28b14..1eb809d198 100644 --- a/packages/frontend/src/ui/_common_/stream-indicator.vue +++ b/packages/frontend/src/ui/_common_/stream-indicator.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<div v-if="hasDisconnected && defaultStore.state.serverDisconnectedBehavior === 'quiet'" :class="$style.root" class="_panel _shadow" @click="resetDisconnected"> +<div v-if="hasDisconnected && prefer.s.serverDisconnectedBehavior === 'quiet'" :class="$style.root" class="_panel _shadow" @click="resetDisconnected"> <div><i class="ti ti-alert-triangle"></i> {{ i18n.ts.disconnectedFromServer }}</div> <div :class="$style.command" class="_buttons"> <MkButton small primary @click="reload">{{ i18n.ts.reload }}</MkButton> @@ -19,7 +19,7 @@ import { useStream } from '@/stream.js'; import { i18n } from '@/i18n.js'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; -import { defaultStore } from '@/store.js'; +import { prefer } from '@/preferences.js'; const zIndex = os.claimZIndex('high'); diff --git a/packages/frontend/src/ui/classic.header.vue b/packages/frontend/src/ui/classic.header.vue index f4633314ae..39b40754ff 100644 --- a/packages/frontend/src/ui/classic.header.vue +++ b/packages/frontend/src/ui/classic.header.vue @@ -53,15 +53,16 @@ import * as os from '@/os.js'; import { navbarItemDef } from '@/navbar.js'; import { openAccountMenu as openAccountMenu_, $i } from '@/account.js'; import MkButton from '@/components/MkButton.vue'; -import { defaultStore } from '@/store.js'; +import { store } from '@/store.js'; import { instance } from '@/instance.js'; import { i18n } from '@/i18n.js'; +import { prefer } from '@/preferences.js'; const WINDOW_THRESHOLD = 1400; const settingsWindowed = ref(window.innerWidth > WINDOW_THRESHOLD); -const menu = ref(defaultStore.state.menu); -// const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay')); +const menu = ref(prefer.s.menu); +// const menuDisplay = computed(store.makeGetterSetter('menuDisplay')); const otherNavItemIndicated = computed<boolean>(() => { for (const def in navbarItemDef) { if (menu.value.includes(def)) continue; diff --git a/packages/frontend/src/ui/classic.sidebar.vue b/packages/frontend/src/ui/classic.sidebar.vue index 5acef0bef8..c11771f028 100644 --- a/packages/frontend/src/ui/classic.sidebar.vue +++ b/packages/frontend/src/ui/classic.sidebar.vue @@ -59,14 +59,15 @@ import MkButton from '@/components/MkButton.vue'; // import { StickySidebar } from '@/scripts/sticky-sidebar.js'; // import { mainRouter } from '@/router.js'; //import MisskeyLogo from '@assets/client/misskey.svg'; -import { defaultStore } from '@/store.js'; +import { store } from '@/store.js'; import { instance } from '@/instance.js'; import { i18n } from '@/i18n.js'; +import { prefer } from '@/preferences.js'; const WINDOW_THRESHOLD = 1400; -const menu = ref(defaultStore.state.menu); -const menuDisplay = computed(defaultStore.makeGetterSetter('menuDisplay')); +const menu = ref(prefer.s.menu); +const menuDisplay = computed(store.makeGetterSetter('menuDisplay')); const otherNavItemIndicated = computed<boolean>(() => { for (const def in navbarItemDef) { if (menu.value.includes(def)) continue; @@ -99,7 +100,7 @@ function openAccountMenu(ev: MouseEvent) { }, ev); } -watch(defaultStore.reactiveState.menuDisplay, () => { +watch(store.reactiveState.menuDisplay, () => { calcViewState(); }); diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index da5059bb59..63c60a3d6f 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -26,7 +26,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> </div> - <Transition :name="defaultStore.state.animation ? 'tray-back' : ''"> + <Transition :name="prefer.s.animation ? 'tray-back' : ''"> <div v-if="widgetsShowing" class="tray-back _modalBg" @@ -35,11 +35,11 @@ SPDX-License-Identifier: AGPL-3.0-only ></div> </Transition> - <Transition :name="defaultStore.state.animation ? 'tray' : ''"> + <Transition :name="prefer.s.animation ? 'tray' : ''"> <XWidgets v-if="widgetsShowing" class="tray"/> </Transition> - <iframe v-if="defaultStore.state.aiChanMode" ref="live2d" class="ivnzpscs" src="https://misskey-dev.github.io/mascot-web/?scale=2&y=1.4"></iframe> + <iframe v-if="prefer.s.aiChanMode" ref="live2d" class="ivnzpscs" src="https://misskey-dev.github.io/mascot-web/?scale=2&y=1.4"></iframe> <XCommon/> </div> @@ -47,18 +47,19 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { defineAsyncComponent, onMounted, provide, ref, computed, shallowRef } from 'vue'; +import { instanceName } from '@@/js/config.js'; +import { isLink } from '@@/js/is-link.js'; import XSidebar from './classic.sidebar.vue'; import XCommon from './_common_/common.vue'; -import { instanceName } from '@@/js/config.js'; +import type { PageMetadata } from '@/scripts/page-metadata.js'; import { StickySidebar } from '@/scripts/sticky-sidebar.js'; import * as os from '@/os.js'; import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js'; -import type { PageMetadata } from '@/scripts/page-metadata.js'; -import { defaultStore } from '@/store.js'; +import { store } from '@/store.js'; import { i18n } from '@/i18n.js'; import { miLocalStorage } from '@/local-storage.js'; import { mainRouter } from '@/router/main.js'; -import { isLink } from '@@/js/is-link.js'; +import { prefer } from '@/preferences.js'; const XHeaderMenu = defineAsyncComponent(() => import('./classic.header.vue')); const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); @@ -74,7 +75,7 @@ const widgetsShowing = ref(false); const fullView = ref(false); const globalHeaderHeight = ref(0); const wallpaper = miLocalStorage.getItem('wallpaper') != null; -const showMenuOnTop = computed(() => defaultStore.state.menuDisplay === 'top'); +const showMenuOnTop = computed(() => store.state.menuDisplay === 'top'); const live2d = shallowRef<HTMLIFrameElement>(); const widgetsLeft = ref<HTMLElement>(); const widgetsRight = ref<HTMLElement>(); @@ -96,7 +97,7 @@ provide('shouldHeaderThin', showMenuOnTop.value); provide('forceSpacerMin', true); function attachSticky(el: HTMLElement) { - const sticky = new StickySidebar(el, 0, defaultStore.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す + const sticky = new StickySidebar(el, 0, store.state.menuDisplay === 'top' ? 60 : 0); // TODO: ヘッダーの高さを60pxと決め打ちしているのを直す window.addEventListener('scroll', () => { sticky.calc(window.scrollY); }, { passive: true }); @@ -142,9 +143,9 @@ if (window.innerWidth < 1024) { document.documentElement.style.overflowY = 'scroll'; -defaultStore.loaded.then(() => { - if (defaultStore.state.widgets.length === 0) { - defaultStore.set('widgets', [{ +store.loaded.then(() => { + if (store.state.widgets.length === 0) { + store.set('widgets', [{ name: 'calendar', id: 'a', place: null, data: {}, }, { @@ -162,7 +163,7 @@ onMounted(() => { isDesktop.value = (window.innerWidth >= DESKTOP_THRESHOLD); }, { passive: true }); - if (defaultStore.state.aiChanMode) { + if (prefer.s.aiChanMode) { const iframeRect = live2d.value.getBoundingClientRect(); window.addEventListener('mousemove', ev => { live2d.value.contentWindow.postMessage({ diff --git a/packages/frontend/src/ui/deck.vue b/packages/frontend/src/ui/deck.vue index 8e99c457ad..2107f6f53a 100644 --- a/packages/frontend/src/ui/deck.vue +++ b/packages/frontend/src/ui/deck.vue @@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only <div :class="$style.main"> <XAnnouncements v-if="$i"/> <XStatusBars/> - <div ref="columnsEl" :class="[$style.sections, { [$style.center]: deckStore.reactiveState.columnAlign.value === 'center', [$style.snapScroll]: snapScroll }]" @contextmenu.self.prevent="onContextmenu" @wheel.self="onWheel"> + <div ref="columnsEl" :class="[$style.sections, { [$style.center]: prefer.r['deck.columnAlign'].value === 'center', [$style.snapScroll]: snapScroll }]" @contextmenu.self.prevent="onContextmenu" @wheel.self="onWheel"> <!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため --> <section v-for="ids in layout" @@ -36,7 +36,7 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <div :class="$style.sideMenu"> <div :class="$style.sideMenuTop"> - <button v-tooltip.noDelay.left="`${i18n.ts._deck.profile}: ${deckStore.state.profile}`" :class="$style.sideMenuButton" class="_button" @click="changeProfile"><i class="ti ti-caret-down"></i></button> + <button v-tooltip.noDelay.left="`${i18n.ts._deck.profile}: ${store.state['deck.profile']}`" :class="$style.sideMenuButton" class="_button" @click="changeProfile"><i class="ti ti-caret-down"></i></button> <button v-tooltip.noDelay.left="i18n.ts._deck.deleteProfile" :class="$style.sideMenuButton" class="_button" @click="deleteProfile"><i class="ti ti-trash"></i></button> </div> <div :class="$style.sideMenuMiddle"> @@ -62,10 +62,10 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <Transition - :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_menuDrawerBg_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_menuDrawerBg_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_menuDrawerBg_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_menuDrawerBg_leaveTo : ''" > <div v-if="drawerMenuShowing" @@ -77,10 +77,10 @@ SPDX-License-Identifier: AGPL-3.0-only </Transition> <Transition - :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveTo : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_menuDrawer_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_menuDrawer_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_menuDrawer_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_menuDrawer_leaveTo : ''" > <div v-if="drawerMenuShowing" :class="$style.menu"> <XDrawerMenu/> @@ -95,8 +95,6 @@ SPDX-License-Identifier: AGPL-3.0-only import { computed, defineAsyncComponent, ref, watch, shallowRef } from 'vue'; import { v4 as uuid } from 'uuid'; import XCommon from './_common_/common.vue'; -import { deckStore, columnTypes, addColumn as addColumnToStore, forceSaveDeck, loadDeck, getProfiles, deleteProfile as deleteProfile_ } from './deck/deck-store.js'; -import type { ColumnType } from './deck/deck-store.js'; import type { MenuItem } from '@/types/menu.js'; import XSidebar from '@/ui/_common_/navbar.vue'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; @@ -107,7 +105,7 @@ import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; import { unisonReload } from '@/scripts/unison-reload.js'; import { deviceKind } from '@/scripts/device-kind.js'; -import { defaultStore } from '@/store.js'; +import { prefer } from '@/preferences.js'; import XMainColumn from '@/ui/deck/main-column.vue'; import XTlColumn from '@/ui/deck/tl-column.vue'; import XAntennaColumn from '@/ui/deck/antenna-column.vue'; @@ -119,6 +117,8 @@ import XMentionsColumn from '@/ui/deck/mentions-column.vue'; import XDirectColumn from '@/ui/deck/direct-column.vue'; import XRoleTimelineColumn from '@/ui/deck/role-timeline-column.vue'; import { mainRouter } from '@/router/main.js'; +import { store } from '@/store.js'; +import { columnTypes, forceSaveDeck, getProfiles, loadDeck, addColumn as addColumnToStore, deleteProfile as deleteProfile_ } from '@/deck.js'; const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue')); @@ -137,8 +137,8 @@ const columnComponents = { mainRouter.navHook = (path, flag): boolean => { if (flag === 'forcePage') return false; - const noMainColumn = !deckStore.state.columns.some(x => x.type === 'main'); - if (deckStore.state.navWindow || noMainColumn) { + const noMainColumn = !store.state['deck.columns'].some(x => x.type === 'main'); + if (prefer.s['deck.navWindow'] || noMainColumn) { os.pageWindow(path); return true; } @@ -160,8 +160,8 @@ watch(route, () => { }); */ -const columns = deckStore.reactiveState.columns; -const layout = deckStore.reactiveState.layout; +const columns = store.reactiveState['deck.columns']; +const layout = store.reactiveState['deck.layout']; const menuIndicated = computed(() => { if ($i == null) return false; for (const def in navbarItemDef) { @@ -214,15 +214,15 @@ loadDeck(); function changeProfile(ev: MouseEvent) { let items: MenuItem[] = [{ - text: deckStore.state.profile, + text: store.state['deck.profile'], active: true, action: () => {}, }]; getProfiles().then(profiles => { - items.push(...(profiles.filter(k => k !== deckStore.state.profile).map(k => ({ + items.push(...(profiles.filter(k => k !== store.state['deck.profile']).map(k => ({ text: k, action: () => { - deckStore.set('profile', k); + store.set('deck.profile', k); unisonReload(); }, }))), { type: 'divider' as const }, { @@ -237,7 +237,7 @@ function changeProfile(ev: MouseEvent) { if (canceled || name == null) return; os.promiseDialog((async () => { - await deckStore.set('profile', name); + await store.set('deck.profile', name); await forceSaveDeck(); })(), () => { unisonReload(); @@ -252,19 +252,19 @@ function changeProfile(ev: MouseEvent) { async function deleteProfile() { const { canceled } = await os.confirm({ type: 'warning', - text: i18n.tsx.deleteAreYouSure({ x: deckStore.state.profile }), + text: i18n.tsx.deleteAreYouSure({ x: store.state['deck.profile'] }), }); if (canceled) return; os.promiseDialog((async () => { - if (deckStore.state.profile === 'default') { - await deckStore.set('columns', []); - await deckStore.set('layout', []); + if (store.state['deck.profile'] === 'default') { + await store.set('deck.columns', []); + await store.set('deck.layout', []); await forceSaveDeck(); } else { - await deleteProfile_(deckStore.state.profile); + await deleteProfile_(store.state['deck.profile']); } - await deckStore.set('profile', 'default'); + await store.set('deck.profile', 'default'); })(), () => { unisonReload(); }); diff --git a/packages/frontend/src/ui/deck/antenna-column.vue b/packages/frontend/src/ui/deck/antenna-column.vue index b79cd8408b..5f0c607edb 100644 --- a/packages/frontend/src/ui/deck/antenna-column.vue +++ b/packages/frontend/src/ui/deck/antenna-column.vue @@ -15,17 +15,17 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, ref, shallowRef, watch, defineAsyncComponent } from 'vue'; -import type { entities as MisskeyEntities } from 'misskey-js'; import XColumn from './column.vue'; -import { updateColumn } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import type { entities as MisskeyEntities } from 'misskey-js'; +import type { Column } from '@/deck.js'; +import type { MenuItem } from '@/types/menu.js'; +import type { SoundStore } from '@/preferences/def.js'; +import { updateColumn } from '@/deck.js'; import MkTimeline from '@/components/MkTimeline.vue'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; -import type { MenuItem } from '@/types/menu.js'; import { antennasCache } from '@/cache.js'; -import type { SoundStore } from '@/store.js'; import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js'; import * as sound from '@/scripts/sound.js'; diff --git a/packages/frontend/src/ui/deck/channel-column.vue b/packages/frontend/src/ui/deck/channel-column.vue index 9e07c06639..f002f655f7 100644 --- a/packages/frontend/src/ui/deck/channel-column.vue +++ b/packages/frontend/src/ui/deck/channel-column.vue @@ -22,16 +22,16 @@ SPDX-License-Identifier: AGPL-3.0-only import { onMounted, ref, shallowRef, watch } from 'vue'; import * as Misskey from 'misskey-js'; import XColumn from './column.vue'; -import { updateColumn } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import type { Column } from '@/deck.js'; +import type { MenuItem } from '@/types/menu.js'; +import type { SoundStore } from '@/preferences/def.js'; +import { updateColumn } from '@/deck.js'; import MkTimeline from '@/components/MkTimeline.vue'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; import { favoritedChannelsCache } from '@/cache.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; -import type { MenuItem } from '@/types/menu.js'; -import type { SoundStore } from '@/store.js'; import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js'; import * as sound from '@/scripts/sound.js'; diff --git a/packages/frontend/src/ui/deck/column.vue b/packages/frontend/src/ui/deck/column.vue index f23e33c748..fc208197a0 100644 --- a/packages/frontend/src/ui/deck/column.vue +++ b/packages/frontend/src/ui/deck/column.vue @@ -43,11 +43,11 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onBeforeUnmount, onMounted, provide, watch, shallowRef, ref, computed } from 'vue'; -import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store.js'; +import type { Column } from '@/deck.js'; +import type { MenuItem } from '@/types/menu.js'; +import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from '@/deck.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; -import type { Column } from './deck-store.js'; -import type { MenuItem } from '@/types/menu.js'; provide('shouldHeaderThin', true); provide('shouldOmitHeaderTitle', true); diff --git a/packages/frontend/src/ui/deck/deck-store.ts b/packages/frontend/src/ui/deck/deck-store.ts index 9055ea6d43..bdca513a7a 100644 --- a/packages/frontend/src/ui/deck/deck-store.ts +++ b/packages/frontend/src/ui/deck/deck-store.ts @@ -3,57 +3,11 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { throttle } from 'throttle-debounce'; import { markRaw } from 'vue'; -import { notificationTypes } from 'misskey-js'; -import type { BasicTimelineType } from '@/timelines.js'; +import type { Column } from '@/deck.js'; import { Storage } from '@/pizzax.js'; -import { misskeyApi } from '@/scripts/misskey-api.js'; -import { deepClone } from '@/scripts/clone.js'; -import type { SoundStore } from '@/store.js'; - -type ColumnWidget = { - name: string; - id: string; - data: Record<string, any>; -}; - -export const columnTypes = [ - 'main', - 'widgets', - 'notifications', - 'tl', - 'antenna', - 'list', - 'channel', - 'mentions', - 'direct', - 'roleTimeline', -] as const; - -export type ColumnType = typeof columnTypes[number]; - -export type Column = { - id: string; - type: ColumnType; - name: string | null; - width: number; - widgets?: ColumnWidget[]; - active?: boolean; - flexible?: boolean; - antennaId?: string; - listId?: string; - channelId?: string; - roleId?: string; - excludeTypes?: typeof notificationTypes[number][]; - tl?: BasicTimelineType; - withRenotes?: boolean; - withReplies?: boolean; - withSensitive?: boolean; - onlyFiles?: boolean; - soundSetting?: SoundStore; -}; +// TODO: 消す(移行済みのため) export const deckStore = markRaw(new Storage('deck', { profile: { where: 'deviceAccount', @@ -67,272 +21,4 @@ export const deckStore = markRaw(new Storage('deck', { where: 'deviceAccount', default: [] as Column['id'][][], }, - columnAlign: { - where: 'deviceAccount', - default: 'left' as 'left' | 'right' | 'center', - }, - alwaysShowMainColumn: { - where: 'deviceAccount', - default: true, - }, - navWindow: { - where: 'deviceAccount', - default: true, - }, - useSimpleUiForNonRootPages: { - where: 'deviceAccount', - default: true, - }, })); - -export const loadDeck = async () => { - let deck; - - try { - deck = await misskeyApi('i/registry/get', { - scope: ['client', 'deck', 'profiles'], - key: deckStore.state.profile, - }); - } catch (err) { - if (typeof err === 'object' && err != null && 'code' in err && err.code === 'NO_SUCH_KEY') { - // 後方互換性のため - if (deckStore.state.profile === 'default') { - saveDeck(); - return; - } - - deckStore.set('columns', []); - deckStore.set('layout', []); - return; - } - throw err; - } - - deckStore.set('columns', deck.columns); - deckStore.set('layout', deck.layout); -}; - -export async function forceSaveDeck() { - await misskeyApi('i/registry/set', { - scope: ['client', 'deck', 'profiles'], - key: deckStore.state.profile, - value: { - columns: deckStore.reactiveState.columns.value, - layout: deckStore.reactiveState.layout.value, - }, - }); -} - -// TODO: deckがloadされていない状態でsaveすると意図せず上書きが発生するので対策する -export const saveDeck = throttle(1000, () => { - forceSaveDeck(); -}); - -export async function getProfiles(): Promise<string[]> { - return await misskeyApi('i/registry/keys', { - scope: ['client', 'deck', 'profiles'], - }); -} - -export async function deleteProfile(key: string): Promise<void> { - return await misskeyApi('i/registry/remove', { - scope: ['client', 'deck', 'profiles'], - key: key, - }); -} - -export function addColumn(column: Column) { - if (column.name === undefined) column.name = null; - deckStore.push('columns', column); - deckStore.push('layout', [column.id]); - saveDeck(); -} - -export function removeColumn(id: Column['id']) { - deckStore.set('columns', deckStore.state.columns.filter(c => c.id !== id)); - deckStore.set('layout', deckStore.state.layout - .map(ids => ids.filter(_id => _id !== id)) - .filter(ids => ids.length > 0)); - saveDeck(); -} - -export function swapColumn(a: Column['id'], b: Column['id']) { - const aX = deckStore.state.layout.findIndex(ids => ids.indexOf(a) !== -1); - const aY = deckStore.state.layout[aX].findIndex(id => id === a); - const bX = deckStore.state.layout.findIndex(ids => ids.indexOf(b) !== -1); - const bY = deckStore.state.layout[bX].findIndex(id => id === b); - const layout = deepClone(deckStore.state.layout); - layout[aX][aY] = b; - layout[bX][bY] = a; - deckStore.set('layout', layout); - saveDeck(); -} - -export function swapLeftColumn(id: Column['id']) { - const layout = deepClone(deckStore.state.layout); - deckStore.state.layout.some((ids, i) => { - if (ids.includes(id)) { - const left = deckStore.state.layout[i - 1]; - if (left) { - layout[i - 1] = deckStore.state.layout[i]; - layout[i] = left; - deckStore.set('layout', layout); - } - return true; - } - return false; - }); - saveDeck(); -} - -export function swapRightColumn(id: Column['id']) { - const layout = deepClone(deckStore.state.layout); - deckStore.state.layout.some((ids, i) => { - if (ids.includes(id)) { - const right = deckStore.state.layout[i + 1]; - if (right) { - layout[i + 1] = deckStore.state.layout[i]; - layout[i] = right; - deckStore.set('layout', layout); - } - return true; - } - return false; - }); - saveDeck(); -} - -export function swapUpColumn(id: Column['id']) { - const layout = deepClone(deckStore.state.layout); - const idsIndex = deckStore.state.layout.findIndex(ids => ids.includes(id)); - const ids = deepClone(deckStore.state.layout[idsIndex]); - ids.some((x, i) => { - if (x === id) { - const up = ids[i - 1]; - if (up) { - ids[i - 1] = id; - ids[i] = up; - - layout[idsIndex] = ids; - deckStore.set('layout', layout); - } - return true; - } - return false; - }); - saveDeck(); -} - -export function swapDownColumn(id: Column['id']) { - const layout = deepClone(deckStore.state.layout); - const idsIndex = deckStore.state.layout.findIndex(ids => ids.includes(id)); - const ids = deepClone(deckStore.state.layout[idsIndex]); - ids.some((x, i) => { - if (x === id) { - const down = ids[i + 1]; - if (down) { - ids[i + 1] = id; - ids[i] = down; - - layout[idsIndex] = ids; - deckStore.set('layout', layout); - } - return true; - } - return false; - }); - saveDeck(); -} - -export function stackLeftColumn(id: Column['id']) { - let layout = deepClone(deckStore.state.layout); - const i = deckStore.state.layout.findIndex(ids => ids.includes(id)); - layout = layout.map(ids => ids.filter(_id => _id !== id)); - layout[i - 1].push(id); - layout = layout.filter(ids => ids.length > 0); - deckStore.set('layout', layout); - saveDeck(); -} - -export function popRightColumn(id: Column['id']) { - let layout = deepClone(deckStore.state.layout); - const i = deckStore.state.layout.findIndex(ids => ids.includes(id)); - const affected = layout[i]; - layout = layout.map(ids => ids.filter(_id => _id !== id)); - layout.splice(i + 1, 0, [id]); - layout = layout.filter(ids => ids.length > 0); - deckStore.set('layout', layout); - - const columns = deepClone(deckStore.state.columns); - for (const column of columns) { - if (affected.includes(column.id)) { - column.active = true; - } - } - deckStore.set('columns', columns); - - saveDeck(); -} - -export function addColumnWidget(id: Column['id'], widget: ColumnWidget) { - const columns = deepClone(deckStore.state.columns); - const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); - const column = deepClone(deckStore.state.columns[columnIndex]); - if (column == null) return; - if (column.widgets == null) column.widgets = []; - column.widgets.unshift(widget); - columns[columnIndex] = column; - deckStore.set('columns', columns); - saveDeck(); -} - -export function removeColumnWidget(id: Column['id'], widget: ColumnWidget) { - const columns = deepClone(deckStore.state.columns); - const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); - const column = deepClone(deckStore.state.columns[columnIndex]); - if (column == null) return; - if (column.widgets == null) column.widgets = []; - column.widgets = column.widgets.filter(w => w.id !== widget.id); - columns[columnIndex] = column; - deckStore.set('columns', columns); - saveDeck(); -} - -export function setColumnWidgets(id: Column['id'], widgets: ColumnWidget[]) { - const columns = deepClone(deckStore.state.columns); - const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); - const column = deepClone(deckStore.state.columns[columnIndex]); - if (column == null) return; - column.widgets = widgets; - columns[columnIndex] = column; - deckStore.set('columns', columns); - saveDeck(); -} - -export function updateColumnWidget(id: Column['id'], widgetId: string, widgetData: any) { - const columns = deepClone(deckStore.state.columns); - const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); - const column = deepClone(deckStore.state.columns[columnIndex]); - if (column == null) return; - if (column.widgets == null) column.widgets = []; - column.widgets = column.widgets.map(w => w.id === widgetId ? { - ...w, - data: widgetData, - } : w); - columns[columnIndex] = column; - deckStore.set('columns', columns); - saveDeck(); -} - -export function updateColumn(id: Column['id'], column: Partial<Column>) { - const columns = deepClone(deckStore.state.columns); - const columnIndex = deckStore.state.columns.findIndex(c => c.id === id); - const currentColumn = deepClone(deckStore.state.columns[columnIndex]); - if (currentColumn == null) return; - for (const [k, v] of Object.entries(column)) { - currentColumn[k] = v; - } - columns[columnIndex] = currentColumn; - deckStore.set('columns', columns); - saveDeck(); -} diff --git a/packages/frontend/src/ui/deck/direct-column.vue b/packages/frontend/src/ui/deck/direct-column.vue index 2cecd6c669..772188d773 100644 --- a/packages/frontend/src/ui/deck/direct-column.vue +++ b/packages/frontend/src/ui/deck/direct-column.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import XColumn from './column.vue'; -import type { Column } from './deck-store.js'; +import type { Column } from '@/deck.js'; import MkNotes from '@/components/MkNotes.vue'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/ui/deck/list-column.vue b/packages/frontend/src/ui/deck/list-column.vue index 83961d02bc..f627ab5262 100644 --- a/packages/frontend/src/ui/deck/list-column.vue +++ b/packages/frontend/src/ui/deck/list-column.vue @@ -15,16 +15,16 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { watch, shallowRef, ref, onMounted } from 'vue'; -import type { entities as MisskeyEntities } from 'misskey-js'; import XColumn from './column.vue'; -import { updateColumn } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import type { entities as MisskeyEntities } from 'misskey-js'; +import type { Column } from '@/deck.js'; +import type { MenuItem } from '@/types/menu.js'; +import type { SoundStore } from '@/preferences/def.js'; +import { updateColumn } from '@/deck.js'; import MkTimeline from '@/components/MkTimeline.vue'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; -import type { MenuItem } from '@/types/menu.js'; -import type { SoundStore } from '@/store.js'; import { userListsCache } from '@/cache.js'; import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js'; import * as sound from '@/scripts/sound.js'; diff --git a/packages/frontend/src/ui/deck/main-column.vue b/packages/frontend/src/ui/deck/main-column.vue index 45c39a5cad..906e94f0b3 100644 --- a/packages/frontend/src/ui/deck/main-column.vue +++ b/packages/frontend/src/ui/deck/main-column.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> <template> -<XColumn v-if="deckStore.state.alwaysShowMainColumn || mainRouter.currentRoute.value.name !== 'index'" :column="column" :isStacked="isStacked"> +<XColumn v-if="prefer.s['deck.alwaysShowMainColumn'] || mainRouter.currentRoute.value.name !== 'index'" :column="column" :isStacked="isStacked"> <template #header> <template v-if="pageMetadata"> <i :class="pageMetadata.icon"></i> @@ -20,17 +20,17 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { provide, shallowRef, ref } from 'vue'; +import { getScrollContainer } from '@@/js/scroll.js'; +import { isLink } from '@@/js/is-link.js'; import XColumn from './column.vue'; -import { deckStore } from '@/ui/deck/deck-store.js'; -import type { Column } from '@/ui/deck/deck-store.js'; +import type { Column } from '@/deck.js'; +import type { PageMetadata } from '@/scripts/page-metadata.js'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js'; -import type { PageMetadata } from '@/scripts/page-metadata.js'; import { useScrollPositionManager } from '@/nirax.js'; -import { getScrollContainer } from '@@/js/scroll.js'; -import { isLink } from '@@/js/is-link.js'; import { mainRouter } from '@/router/main.js'; +import { prefer } from '@/preferences.js'; defineProps<{ column: Column; diff --git a/packages/frontend/src/ui/deck/mentions-column.vue b/packages/frontend/src/ui/deck/mentions-column.vue index 233fba554b..ffd0307940 100644 --- a/packages/frontend/src/ui/deck/mentions-column.vue +++ b/packages/frontend/src/ui/deck/mentions-column.vue @@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import XColumn from './column.vue'; -import type { Column } from './deck-store.js'; +import type { Column } from '@/deck.js'; import MkNotes from '@/components/MkNotes.vue'; import { i18n } from '../../i18n.js'; diff --git a/packages/frontend/src/ui/deck/notifications-column.vue b/packages/frontend/src/ui/deck/notifications-column.vue index c0303e86dc..0a2c0e9952 100644 --- a/packages/frontend/src/ui/deck/notifications-column.vue +++ b/packages/frontend/src/ui/deck/notifications-column.vue @@ -14,8 +14,8 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { defineAsyncComponent, shallowRef } from 'vue'; import XColumn from './column.vue'; -import { updateColumn } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import { updateColumn } from '@/deck.js'; +import type { Column } from '@/deck.js'; import XNotifications from '@/components/MkNotifications.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/ui/deck/role-timeline-column.vue b/packages/frontend/src/ui/deck/role-timeline-column.vue index 5b1420570d..4d1be08706 100644 --- a/packages/frontend/src/ui/deck/role-timeline-column.vue +++ b/packages/frontend/src/ui/deck/role-timeline-column.vue @@ -16,14 +16,14 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { computed, onMounted, ref, shallowRef, watch } from 'vue'; import XColumn from './column.vue'; -import { updateColumn } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import type { Column } from '@/deck.js'; +import type { MenuItem } from '@/types/menu.js'; +import type { SoundStore } from '@/preferences/def.js'; +import { updateColumn } from '@/deck.js'; import MkTimeline from '@/components/MkTimeline.vue'; import * as os from '@/os.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { i18n } from '@/i18n.js'; -import type { MenuItem } from '@/types/menu.js'; -import type { SoundStore } from '@/store.js'; import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js'; import * as sound from '@/scripts/sound.js'; diff --git a/packages/frontend/src/ui/deck/tl-column.vue b/packages/frontend/src/ui/deck/tl-column.vue index b9b3746abf..96da944398 100644 --- a/packages/frontend/src/ui/deck/tl-column.vue +++ b/packages/frontend/src/ui/deck/tl-column.vue @@ -34,15 +34,14 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, watch, ref, shallowRef, computed } from 'vue'; import XColumn from './column.vue'; -import { removeColumn, updateColumn } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import type { Column } from '@/deck.js'; import type { MenuItem } from '@/types/menu.js'; +import type { SoundStore } from '@/preferences/def.js'; +import { removeColumn, updateColumn } from '@/deck.js'; import MkTimeline from '@/components/MkTimeline.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; import { hasWithReplies, isAvailableBasicTimeline, basicTimelineIconClass } from '@/timelines.js'; -import { instance } from '@/instance.js'; -import type { SoundStore } from '@/store.js'; import { soundSettingsButton } from '@/ui/deck/tl-note-notification.js'; import * as sound from '@/scripts/sound.js'; diff --git a/packages/frontend/src/ui/deck/tl-note-notification.ts b/packages/frontend/src/ui/deck/tl-note-notification.ts index 03d4b3a580..277ebb0511 100644 --- a/packages/frontend/src/ui/deck/tl-note-notification.ts +++ b/packages/frontend/src/ui/deck/tl-note-notification.ts @@ -5,8 +5,8 @@ import * as Misskey from 'misskey-js'; import type { Ref } from 'vue'; -import type { SoundStore } from '@/store.js'; import type { SoundType } from '@/scripts/sound.js'; +import type { SoundStore } from '@/preferences/def.js'; import { getSoundDuration, playMisskeySfxFile, soundsTypes } from '@/scripts/sound.js'; import { i18n } from '@/i18n.js'; import * as os from '@/os.js'; diff --git a/packages/frontend/src/ui/deck/widgets-column.vue b/packages/frontend/src/ui/deck/widgets-column.vue index 20284d8c9f..4e84ef0ba0 100644 --- a/packages/frontend/src/ui/deck/widgets-column.vue +++ b/packages/frontend/src/ui/deck/widgets-column.vue @@ -17,8 +17,8 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { ref } from 'vue'; import XColumn from './column.vue'; -import { addColumnWidget, removeColumnWidget, setColumnWidgets, updateColumnWidget } from './deck-store.js'; -import type { Column } from './deck-store.js'; +import { addColumnWidget, removeColumnWidget, setColumnWidgets, updateColumnWidget } from '@/deck.js'; +import type { Column } from '@/deck.js'; import XWidgets from '@/components/MkWidgets.vue'; import { i18n } from '@/i18n.js'; diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 25f47a2d55..bddb62dc60 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only <MkStickyContainer ref="contents" :class="$style.contents" style="container-type: inline-size;" @contextmenu.stop="onContextmenu"> <template #header> <div> + <XPreferenceRestore v-if="shouldSuggestRestoreBackup"/> <XAnnouncements v-if="$i"/> <XStatusBars :class="$style.statusbars"/> </div> @@ -38,10 +39,10 @@ SPDX-License-Identifier: AGPL-3.0-only </div> <Transition - :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawerBg_leaveTo : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_menuDrawerBg_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_menuDrawerBg_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_menuDrawerBg_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_menuDrawerBg_leaveTo : ''" > <div v-if="drawerMenuShowing" @@ -53,10 +54,10 @@ SPDX-License-Identifier: AGPL-3.0-only </Transition> <Transition - :enterActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_menuDrawer_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_menuDrawer_leaveTo : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_menuDrawer_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_menuDrawer_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_menuDrawer_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_menuDrawer_leaveTo : ''" > <div v-if="drawerMenuShowing" :class="$style.menuDrawer"> <XDrawerMenu/> @@ -64,10 +65,10 @@ SPDX-License-Identifier: AGPL-3.0-only </Transition> <Transition - :enterActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_widgetsDrawerBg_leaveTo : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_widgetsDrawerBg_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_widgetsDrawerBg_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_widgetsDrawerBg_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_widgetsDrawerBg_leaveTo : ''" > <div v-if="widgetsShowing" @@ -79,10 +80,10 @@ SPDX-License-Identifier: AGPL-3.0-only </Transition> <Transition - :enterActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_enterActive : ''" - :leaveActiveClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_leaveActive : ''" - :enterFromClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_enterFrom : ''" - :leaveToClass="defaultStore.state.animation ? $style.transition_widgetsDrawer_leaveTo : ''" + :enterActiveClass="prefer.s.animation ? $style.transition_widgetsDrawer_enterActive : ''" + :leaveActiveClass="prefer.s.animation ? $style.transition_widgetsDrawer_leaveActive : ''" + :enterFromClass="prefer.s.animation ? $style.transition_widgetsDrawer_enterFrom : ''" + :leaveToClass="prefer.s.animation ? $style.transition_widgetsDrawer_leaveTo : ''" > <div v-if="widgetsShowing" :class="$style.widgetsDrawer"> <button class="_button" :class="$style.widgetsCloseButton" @click="widgetsShowing = false"><i class="ti ti-x"></i></button> @@ -105,7 +106,7 @@ import type MkStickyContainer from '@/components/global/MkStickyContainer.vue'; import type { PageMetadata } from '@/scripts/page-metadata.js'; import XDrawerMenu from '@/ui/_common_/navbar-for-mobile.vue'; import * as os from '@/os.js'; -import { defaultStore } from '@/store.js'; +import { store } from '@/store.js'; import { navbarItemDef } from '@/navbar.js'; import { i18n } from '@/i18n.js'; import { $i } from '@/account.js'; @@ -114,11 +115,14 @@ import { deviceKind } from '@/scripts/device-kind.js'; import { miLocalStorage } from '@/local-storage.js'; import { useScrollPositionManager } from '@/nirax.js'; import { mainRouter } from '@/router/main.js'; +import { prefer } from '@/preferences.js'; +import { shouldSuggestRestoreBackup } from '@/preferences/utility.js'; const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); const XAnnouncements = defineAsyncComponent(() => import('@/ui/_common_/announcements.vue')); +const XPreferenceRestore = defineAsyncComponent(() => import('@/ui/_common_/PreferenceRestore.vue')); const isRoot = computed(() => mainRouter.currentRoute.value.name === 'index'); @@ -174,9 +178,9 @@ if (window.innerWidth > 1024) { } } -defaultStore.loaded.then(() => { - if (defaultStore.state.widgets.length === 0) { - defaultStore.set('widgets', [{ +store.loaded.then(() => { + if (store.state.widgets.length === 0) { + store.set('widgets', [{ name: 'calendar', id: 'a', place: 'right', data: {}, }, { diff --git a/packages/frontend/src/ui/universal.widgets.vue b/packages/frontend/src/ui/universal.widgets.vue index fc0a4475d2..42b870cbb5 100644 --- a/packages/frontend/src/ui/universal.widgets.vue +++ b/packages/frontend/src/ui/universal.widgets.vue @@ -19,7 +19,7 @@ const editMode = ref(false); <script lang="ts" setup> import XWidgets from '@/components/MkWidgets.vue'; import { i18n } from '@/i18n.js'; -import { defaultStore } from '@/store.js'; +import { store } from '@/store.js'; const props = withDefaults(defineProps<{ // null = 全てのウィジェットを表示 @@ -31,24 +31,24 @@ const props = withDefaults(defineProps<{ }); const widgets = computed(() => { - if (props.place === null) return defaultStore.reactiveState.widgets.value; - if (props.place === 'left') return defaultStore.reactiveState.widgets.value.filter(w => w.place === 'left'); - return defaultStore.reactiveState.widgets.value.filter(w => w.place !== 'left'); + if (props.place === null) return store.reactiveState.widgets.value; + if (props.place === 'left') return store.reactiveState.widgets.value.filter(w => w.place === 'left'); + return store.reactiveState.widgets.value.filter(w => w.place !== 'left'); }); function addWidget(widget) { - defaultStore.set('widgets', [{ + store.set('widgets', [{ ...widget, place: props.place, - }, ...defaultStore.state.widgets]); + }, ...store.state.widgets]); } function removeWidget(widget) { - defaultStore.set('widgets', defaultStore.state.widgets.filter(w => w.id !== widget.id)); + store.set('widgets', store.state.widgets.filter(w => w.id !== widget.id)); } function updateWidget({ id, data }) { - defaultStore.set('widgets', defaultStore.state.widgets.map(w => w.id === id ? { + store.set('widgets', store.state.widgets.map(w => w.id === id ? { ...w, data, place: props.place, @@ -57,18 +57,18 @@ function updateWidget({ id, data }) { function updateWidgets(thisWidgets) { if (props.place === null) { - defaultStore.set('widgets', thisWidgets); + store.set('widgets', thisWidgets); return; } if (props.place === 'left') { - defaultStore.set('widgets', [ + store.set('widgets', [ ...thisWidgets.map(w => ({ ...w, place: 'left' })), - ...defaultStore.state.widgets.filter(w => w.place !== 'left' && !thisWidgets.some(t => w.id === t.id)), + ...store.state.widgets.filter(w => w.place !== 'left' && !thisWidgets.some(t => w.id === t.id)), ]); return; } - defaultStore.set('widgets', [ - ...defaultStore.state.widgets.filter(w => w.place === 'left' && !thisWidgets.some(t => w.id === t.id)), + store.set('widgets', [ + ...store.state.widgets.filter(w => w.place === 'left' && !thisWidgets.some(t => w.id === t.id)), ...thisWidgets.map(w => ({ ...w, place: 'right' })), ]); } diff --git a/packages/frontend/src/ui/visitor.vue b/packages/frontend/src/ui/visitor.vue index 8bcb260677..9ba9786ca8 100644 --- a/packages/frontend/src/ui/visitor.vue +++ b/packages/frontend/src/ui/visitor.vue @@ -70,15 +70,14 @@ SPDX-License-Identifier: AGPL-3.0-only <script lang="ts" setup> import { onMounted, provide, ref, computed } from 'vue'; -import XCommon from './_common_/common.vue'; import { instanceName } from '@@/js/config.js'; +import XCommon from './_common_/common.vue'; +import type { PageMetadata } from '@/scripts/page-metadata.js'; import * as os from '@/os.js'; import { instance } from '@/instance.js'; import XSigninDialog from '@/components/MkSigninDialog.vue'; import XSignupDialog from '@/components/MkSignupDialog.vue'; -import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { provideMetadataReceiver, provideReactiveMetadata } from '@/scripts/page-metadata.js'; -import type { PageMetadata } from '@/scripts/page-metadata.js'; import { i18n } from '@/i18n.js'; import MkVisitorDashboard from '@/components/MkVisitorDashboard.vue'; import { mainRouter } from '@/router/main.js'; @@ -108,7 +107,7 @@ const announcements = { limit: 10, }; -const isTimelineAvailable = ref(instance.policies?.ltlAvailable || instance.policies?.gtlAvailable); +const isTimelineAvailable = ref(instance.policies.ltlAvailable || instance.policies.gtlAvailable); const showMenu = ref(false); const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD); @@ -116,10 +115,6 @@ const narrow = ref(window.innerWidth < 1280); const keymap = computed(() => { return { - 'd': () => { - if (ColdDeviceStorage.get('syncDeviceDarkMode')) return; - defaultStore.set('darkMode', !defaultStore.state.darkMode); - }, 's': () => { mainRouter.push('/search'); }, |