summaryrefslogtreecommitdiff
path: root/packages/frontend/src/ui
diff options
context:
space:
mode:
authorsyuilo <4439005+syuilo@users.noreply.github.com>2025-03-09 12:34:08 +0900
committerGitHub <noreply@github.com>2025-03-09 12:34:08 +0900
commitd30ddd4c2ebcacc0d0b49c74e8dfe05b5422ba2e (patch)
treec0c87a30037d3ffc11784627e67a1965b262c336 /packages/frontend/src/ui
parent[skip ci] Update CHANGELOG.md (prepend template) (diff)
downloadsharkey-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')
-rw-r--r--packages/frontend/src/ui/_common_/PreferenceRestore.vue73
-rw-r--r--packages/frontend/src/ui/_common_/common.vue24
-rw-r--r--packages/frontend/src/ui/_common_/navbar-for-mobile.vue4
-rw-r--r--packages/frontend/src/ui/_common_/navbar.vue11
-rw-r--r--packages/frontend/src/ui/_common_/statusbars.vue4
-rw-r--r--packages/frontend/src/ui/_common_/stream-indicator.vue4
-rw-r--r--packages/frontend/src/ui/classic.header.vue7
-rw-r--r--packages/frontend/src/ui/classic.sidebar.vue9
-rw-r--r--packages/frontend/src/ui/classic.vue27
-rw-r--r--packages/frontend/src/ui/deck.vue54
-rw-r--r--packages/frontend/src/ui/deck/antenna-column.vue10
-rw-r--r--packages/frontend/src/ui/deck/channel-column.vue8
-rw-r--r--packages/frontend/src/ui/deck/column.vue6
-rw-r--r--packages/frontend/src/ui/deck/deck-store.ts318
-rw-r--r--packages/frontend/src/ui/deck/direct-column.vue2
-rw-r--r--packages/frontend/src/ui/deck/list-column.vue10
-rw-r--r--packages/frontend/src/ui/deck/main-column.vue12
-rw-r--r--packages/frontend/src/ui/deck/mentions-column.vue2
-rw-r--r--packages/frontend/src/ui/deck/notifications-column.vue4
-rw-r--r--packages/frontend/src/ui/deck/role-timeline-column.vue8
-rw-r--r--packages/frontend/src/ui/deck/tl-column.vue7
-rw-r--r--packages/frontend/src/ui/deck/tl-note-notification.ts2
-rw-r--r--packages/frontend/src/ui/deck/widgets-column.vue4
-rw-r--r--packages/frontend/src/ui/universal.vue44
-rw-r--r--packages/frontend/src/ui/universal.widgets.vue26
-rw-r--r--packages/frontend/src/ui/visitor.vue11
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');
},