diff --git a/packages/frontend/src/account.ts b/packages/frontend/src/account.ts index 0e991cdfb547947254ba0f6fdaccf1fb1ff6093d..93916ccf2fdc2a13a3837c07bb5462d249f50d48 100644 --- a/packages/frontend/src/account.ts +++ b/packages/frontend/src/account.ts @@ -6,12 +6,13 @@ import { del, get, set } from '@/scripts/idb-proxy'; import { apiUrl } from '@/config'; import { waiting, api, popup, popupMenu, success, alert } from '@/os'; import { unisonReload, reloadChannel } from '@/scripts/unison-reload'; +import { miLocalStorage } from './local-storage'; // TODO: ä»–ã®ã‚¿ãƒ–ã¨æ°¸ç¶šåŒ–ã•ã‚ŒãŸstateã‚’åŒæœŸ type Account = misskey.entities.MeDetailed; -const accountData = localStorage.getItem('account'); +const accountData = miLocalStorage.getItem('account'); // TODO: 外部ã‹ã‚‰ã¯readonlyã« export const $i = accountData ? reactive(JSON.parse(accountData) as Account) : null; @@ -21,7 +22,7 @@ export const iAmAdmin = $i != null && $i.isAdmin; export async function signout() { waiting(); - localStorage.removeItem('account'); + miLocalStorage.removeItem('account'); await removeAccount($i.id); @@ -119,7 +120,7 @@ export function updateAccount(accountData) { for (const [key, value] of Object.entries(accountData)) { $i[key] = value; } - localStorage.setItem('account', JSON.stringify($i)); + miLocalStorage.setItem('account', JSON.stringify($i)); } export function refreshAccount() { @@ -130,7 +131,7 @@ export async function login(token: Account['token'], redirect?: string) { waiting(); if (_DEV_) console.log('logging as token ', token); const me = await fetchAccount(token); - localStorage.setItem('account', JSON.stringify(me)); + miLocalStorage.setItem('account', JSON.stringify(me)); document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardã®èªè¨¼ã¨ã‹ã§ä½¿ã† await addAccount(me.id, token); diff --git a/packages/frontend/src/components/MkAutocomplete.vue b/packages/frontend/src/components/MkAutocomplete.vue index 08e2c29de29419e68b889cf86f8fa79fb4acc3c9..8ed60bc5dc071d7c932e0ae3ca7b79c689368f46 100644 --- a/packages/frontend/src/components/MkAutocomplete.vue +++ b/packages/frontend/src/components/MkAutocomplete.vue @@ -46,6 +46,7 @@ import { defaultStore } from '@/store'; import { emojilist } from '@/scripts/emojilist'; import { instance } from '@/instance'; import { i18n } from '@/i18n'; +import { miLocalStorage } from '@/local-storage'; type EmojiDef = { emoji: string; @@ -208,7 +209,7 @@ function exec() { } } else if (props.type === 'hashtag') { if (!props.q || props.q === '') { - hashtags.value = JSON.parse(localStorage.getItem('hashtags') || '[]'); + hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') || '[]'); fetching.value = false; } else { const cacheKey = `autocomplete:hashtag:${props.q}`; diff --git a/packages/frontend/src/components/MkFolder.vue b/packages/frontend/src/components/MkFolder.vue index 5a406c8635f85fc3163d32322ca4da8e5560bbcd..dc10c7d3f3b6e1c19538b338083e7fd7c24d9ede 100644 --- a/packages/frontend/src/components/MkFolder.vue +++ b/packages/frontend/src/components/MkFolder.vue @@ -25,8 +25,9 @@ <script lang="ts"> import { defineComponent } from 'vue'; import tinycolor from 'tinycolor2'; +import { miLocalStorage } from '@/local-storage'; -const localStoragePrefix = 'ui:folder:'; +const miLocalStoragePrefix = 'ui:folder:' as const; export default defineComponent({ props: { @@ -44,13 +45,13 @@ export default defineComponent({ data() { return { bg: null, - showBody: (this.persistKey && localStorage.getItem(localStoragePrefix + this.persistKey)) ? localStorage.getItem(localStoragePrefix + this.persistKey) === 't' : this.expanded, + showBody: (this.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`) === 't') : this.expanded, }; }, watch: { showBody() { if (this.persistKey) { - localStorage.setItem(localStoragePrefix + this.persistKey, this.showBody ? 't' : 'f'); + miLocalStorage.setItem(`${miLocalStoragePrefix}${this.persistKey}`, this.showBody ? 't' : 'f'); } }, }, diff --git a/packages/frontend/src/components/MkPostForm.vue b/packages/frontend/src/components/MkPostForm.vue index 883ad9f14f2d2211b598a856658cbace74d40b13..ff3b7ec1f594be5a7d7272f281319656c35f7357 100644 --- a/packages/frontend/src/components/MkPostForm.vue +++ b/packages/frontend/src/components/MkPostForm.vue @@ -98,6 +98,7 @@ import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account' import { uploadFile } from '@/scripts/upload'; import { deepClone } from '@/scripts/clone'; import MkRippleEffect from '@/components/MkRippleEffect.vue'; +import { miLocalStorage } from '@/local-storage'; const modal = inject('modal'); @@ -156,7 +157,7 @@ let autocomplete = $ref(null); let draghover = $ref(false); let quoteId = $ref(null); let hasNotSpecifiedMentions = $ref(false); -let recentHashtags = $ref(JSON.parse(localStorage.getItem('hashtags') || '[]')); +let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') || '[]')); let imeText = $ref(''); const typing = throttle(3000, () => { @@ -543,7 +544,7 @@ function onDrop(ev): void { } function saveDraft() { - const draftData = JSON.parse(localStorage.getItem('drafts') || '{}'); + const draftData = JSON.parse(miLocalStorage.getItem('drafts') || '{}'); draftData[draftKey] = { updatedAt: new Date(), @@ -558,15 +559,15 @@ function saveDraft() { }, }; - localStorage.setItem('drafts', JSON.stringify(draftData)); + miLocalStorage.setItem('drafts', JSON.stringify(draftData)); } function deleteDraft() { - const draftData = JSON.parse(localStorage.getItem('drafts') ?? '{}'); + const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}'); delete draftData[draftKey]; - localStorage.setItem('drafts', JSON.stringify(draftData)); + miLocalStorage.setItem('drafts', JSON.stringify(draftData)); } async function post(ev?: MouseEvent) { @@ -622,8 +623,8 @@ async function post(ev?: MouseEvent) { emit('posted'); if (postData.text && postData.text !== '') { const hashtags_ = mfm.parse(postData.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag); - const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[]; - localStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history)))); + const history = JSON.parse(miLocalStorage.getItem('hashtags') || '[]') as string[]; + miLocalStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history)))); } posting = false; postAccount = null; @@ -698,7 +699,7 @@ onMounted(() => { nextTick(() => { // 書ãã‹ã‘ã®æŠ•ç¨¿ã‚’復元 if (!props.instant && !props.mention && !props.specified) { - const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[draftKey]; + const draft = JSON.parse(miLocalStorage.getItem('drafts') || '{}')[draftKey]; if (draft) { text = draft.data.text; useCw = draft.data.useCw; diff --git a/packages/frontend/src/config.ts b/packages/frontend/src/config.ts index f2022b0f02104123fe5249928a9064b70c5886c3..4b084d365b29aaf2103a3114fbdde0f5a7a0a638 100644 --- a/packages/frontend/src/config.ts +++ b/packages/frontend/src/config.ts @@ -1,3 +1,5 @@ +import { miLocalStorage } from "./local-storage"; + const address = new URL(location.href); const siteName = (document.querySelector('meta[property="og:site_name"]') as HTMLMetaElement)?.content; @@ -6,10 +8,10 @@ export const hostname = address.hostname; export const url = address.origin; export const apiUrl = url + '/api'; export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming'; -export const lang = localStorage.getItem('lang'); +export const lang = miLocalStorage.getItem('lang'); export const langs = _LANGS_; -export const locale = JSON.parse(localStorage.getItem('locale')); +export const locale = JSON.parse(miLocalStorage.getItem('locale')); export const version = _VERSION_; export const instanceName = siteName === 'Misskey' ? host : siteName; -export const ui = localStorage.getItem('ui'); -export const debug = localStorage.getItem('debug') === 'true'; +export const ui = miLocalStorage.getItem('ui'); +export const debug = miLocalStorage.getItem('debug') === 'true'; diff --git a/packages/frontend/src/init.ts b/packages/frontend/src/init.ts index 45ade64127904458bcac266f40d41ed4ad9d0e69..bd515f47ea6854893454344d3b9d5636d501502f 100644 --- a/packages/frontend/src/init.ts +++ b/packages/frontend/src/init.ts @@ -9,9 +9,12 @@ import '@/style.scss'; //#region account indexedDB migration import { set } from '@/scripts/idb-proxy'; -if (localStorage.getItem('accounts') != null) { - set('accounts', JSON.parse(localStorage.getItem('accounts'))); - localStorage.removeItem('accounts'); +{ + const accounts = miLocalStorage.getItem('accounts'); + if (accounts) { + set('accounts', JSON.parse(accounts)); + miLocalStorage.removeItem('accounts'); + } } //#endregion @@ -40,6 +43,7 @@ import { reloadChannel } from '@/scripts/unison-reload'; import { reactionPicker } from '@/scripts/reaction-picker'; import { getUrlWithoutLoginId } from '@/scripts/login-id'; import { getAccountFromId } from '@/scripts/get-account-from-id'; +import { miLocalStorage } from './local-storage'; (async () => { console.info(`Misskey v${version}`); @@ -154,7 +158,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; const fetchInstanceMetaPromise = fetchInstance(); fetchInstanceMetaPromise.then(() => { - localStorage.setItem('v', instance.version); + miLocalStorage.setItem('v', instance.version); // Init service worker initializeSw(); @@ -223,12 +227,12 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; } // クライアントãŒæ›´æ–°ã•ã‚ŒãŸã‹ï¼Ÿ - const lastVersion = localStorage.getItem('lastVersion'); + const lastVersion = miLocalStorage.getItem('lastVersion'); if (lastVersion !== version) { - localStorage.setItem('lastVersion', version); + miLocalStorage.setItem('lastVersion', version); // テーマリビルドã™ã‚‹ãŸã‚ - localStorage.removeItem('theme'); + miLocalStorage.removeItem('theme'); try { // 変ãªãƒãƒ¼ã‚¸ãƒ§ãƒ³æ–‡å—列æ¥ã‚‹ã¨compareVersionsã§ã‚¨ãƒ©ãƒ¼ã«ãªã‚‹ãŸã‚ if (lastVersion != null && compareVersions(version, lastVersion) === 1) { @@ -244,7 +248,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; // NOTE: ã“ã®å‡¦ç†ã¯å¿…ãšâ†‘ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆæ›´æ–°æ™‚処ç†ã‚ˆã‚Šå¾Œã«æ¥ã‚‹ã“ã¨(テーマå†æ§‹ç¯‰ã®ãŸã‚) watch(defaultStore.reactiveState.darkMode, (darkMode) => { applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); - }, { immediate: localStorage.theme == null }); + }, { immediate: miLocalStorage.getItem('theme') == null }); const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); @@ -341,7 +345,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; }); } - const lastUsed = localStorage.getItem('lastUsed'); + const lastUsed = miLocalStorage.getItem('lastUsed'); if (lastUsed) { const lastUsedDate = parseInt(lastUsed, 10); // 二時間以上å‰ãªã‚‰ @@ -351,7 +355,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; })); } } - localStorage.setItem('lastUsed', Date.now().toString()); + miLocalStorage.setItem('lastUsed', Date.now().toString()); if ('Notification' in window) { // 許å¯ã‚’å¾—ã¦ã„ãªã‹ã£ãŸã‚‰ãƒªã‚¯ã‚¨ã‚¹ãƒˆ diff --git a/packages/frontend/src/instance.ts b/packages/frontend/src/instance.ts index 51464f32fb2ba817a1d2e0f697881ab769011b19..82d3e7aea2902deb7e099a8ec415343ddaba3a43 100644 --- a/packages/frontend/src/instance.ts +++ b/packages/frontend/src/instance.ts @@ -1,10 +1,11 @@ import { computed, reactive } from 'vue'; import * as Misskey from 'misskey-js'; import { api } from './os'; +import { miLocalStorage } from './local-storage'; // TODO: ä»–ã®ã‚¿ãƒ–ã¨æ°¸ç¶šåŒ–ã•ã‚ŒãŸstateã‚’åŒæœŸ -const instanceData = localStorage.getItem('instance'); +const instanceData = miLocalStorage.getItem('instance'); // TODO: instanceをリアクティブã«ã™ã‚‹ã‹ã¯å†è€ƒã®ä½™åœ°ã‚ã‚Š @@ -21,7 +22,7 @@ export async function fetchInstance() { instance[k] = v; } - localStorage.setItem('instance', JSON.stringify(instance)); + miLocalStorage.setItem('instance', JSON.stringify(instance)); } export const emojiCategories = computed(() => { diff --git a/packages/frontend/src/local-storage.ts b/packages/frontend/src/local-storage.ts new file mode 100644 index 0000000000000000000000000000000000000000..5286a6f3a7bb3159eca5523893358cca9de5151f --- /dev/null +++ b/packages/frontend/src/local-storage.ts @@ -0,0 +1,31 @@ +type Keys = + 'v' | + 'lastVersion' | + 'instance' | + 'account' | + 'accounts' | + 'lastUsed' | + 'lang' | + 'drafts' | + 'hashtags' | + 'wallpaper' | + 'theme' | + 'colorSchema' | + 'useSystemFont' | + 'fontSize' | + 'ui' | + 'locale' | + 'theme' | + 'customCss' | + 'message_drafts' | + 'scratchpad' | + `miux:${string}` | + `ui:folder:${string}` | + `themes:${string}` | + `aiscript:${string}`; + +export const miLocalStorage = { + getItem: (key: Keys) => window.localStorage.getItem(key), + setItem: (key: Keys, value: string) => window.localStorage.setItem(key, value), + removeItem: (key: Keys) => window.localStorage.removeItem(key), +}; diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index efc0abfc6e78385b34268967f3a046e5267fe305..9ee78741dc474328a69f02ad61c84be870d22fe1 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -5,6 +5,7 @@ import * as os from '@/os'; import { i18n } from '@/i18n'; import { ui } from '@/config'; import { unisonReload } from '@/scripts/unison-reload'; +import { miLocalStorage } from './local-storage'; export const navbarItemDef = reactive({ notifications: { @@ -110,21 +111,21 @@ export const navbarItemDef = reactive({ text: i18n.ts.default, active: ui === 'default' || ui === null, action: () => { - localStorage.setItem('ui', 'default'); + miLocalStorage.setItem('ui', 'default'); unisonReload(); }, }, { text: i18n.ts.deck, active: ui === 'deck', action: () => { - localStorage.setItem('ui', 'deck'); + miLocalStorage.setItem('ui', 'deck'); unisonReload(); }, }, { text: i18n.ts.classic, active: ui === 'classic', action: () => { - localStorage.setItem('ui', 'classic'); + miLocalStorage.setItem('ui', 'classic'); unisonReload(); }, }], ev.currentTarget ?? ev.target); diff --git a/packages/frontend/src/pages/_error_.vue b/packages/frontend/src/pages/_error_.vue index da2889ba2705e5743bf24be52bee1fd9e4d14fe1..5001b5a8b4d1e91c52e648a18cad368bcc56d10f 100644 --- a/packages/frontend/src/pages/_error_.vue +++ b/packages/frontend/src/pages/_error_.vue @@ -26,6 +26,7 @@ import * as os from '@/os'; import { unisonReload } from '@/scripts/unison-reload'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { miLocalStorage } from '@/local-storage'; const props = withDefaults(defineProps<{ error?: Error; @@ -42,7 +43,7 @@ os.api('meta', { loaded = true; serverIsDead = false; meta = res; - localStorage.setItem('v', res.version); + miLocalStorage.setItem('v', res.version); }, () => { loaded = true; serverIsDead = true; diff --git a/packages/frontend/src/pages/messaging/messaging-room.form.vue b/packages/frontend/src/pages/messaging/messaging-room.form.vue index a0fa2677d008f9b95985b4fa41f5e7c81ad352b7..e880129033be0eb4990b5ff768c5bb0c34036c94 100644 --- a/packages/frontend/src/pages/messaging/messaging-room.form.vue +++ b/packages/frontend/src/pages/messaging/messaging-room.form.vue @@ -40,6 +40,7 @@ import { defaultStore } from '@/store'; import { i18n } from '@/i18n'; //import { Autocomplete } from '@/scripts/autocomplete'; import { uploadFile } from '@/scripts/upload'; +import { miLocalStorage } from '@/local-storage'; const props = defineProps<{ user?: Misskey.entities.UserDetailed | null; @@ -188,7 +189,7 @@ function clear() { } function saveDraft() { - const drafts = JSON.parse(localStorage.getItem('message_drafts') || '{}'); + const drafts = JSON.parse(miLocalStorage.getItem('message_drafts') || '{}'); drafts[draftKey] = { updatedAt: new Date(), @@ -199,15 +200,15 @@ function saveDraft() { }, }; - localStorage.setItem('message_drafts', JSON.stringify(drafts)); + miLocalStorage.setItem('message_drafts', JSON.stringify(drafts)); } function deleteDraft() { - const drafts = JSON.parse(localStorage.getItem('message_drafts') || '{}'); + const drafts = JSON.parse(miLocalStorage.getItem('message_drafts') || '{}'); delete drafts[draftKey]; - localStorage.setItem('message_drafts', JSON.stringify(drafts)); + miLocalStorage.setItem('message_drafts', JSON.stringify(drafts)); } async function insertEmoji(ev: MouseEvent) { @@ -222,7 +223,7 @@ onMounted(() => { //new Autocomplete(textEl, this, { model: 'text' }); // 書ãã‹ã‘ã®æŠ•ç¨¿ã‚’復元 - const draft = JSON.parse(localStorage.getItem('message_drafts') || '{}')[draftKey]; + const draft = JSON.parse(miLocalStorage.getItem('message_drafts') || '{}')[draftKey]; if (draft) { text = draft.data.text; file = draft.data.file; diff --git a/packages/frontend/src/pages/scratchpad.vue b/packages/frontend/src/pages/scratchpad.vue index 316133b96807d70ff666d0a4f9ee97ceaf39fa78..ff5f06c8da8c68236614ab1054ffbcece838b627 100644 --- a/packages/frontend/src/pages/scratchpad.vue +++ b/packages/frontend/src/pages/scratchpad.vue @@ -46,6 +46,7 @@ import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; import { AsUiComponent, AsUiRoot, patch, registerAsUiLib, render } from '@/scripts/aiscript/ui'; import MkAsUi from '@/components/MkAsUi.vue'; +import { miLocalStorage } from '@/local-storage'; const parser = new Parser(); let aiscript: Interpreter; @@ -55,13 +56,13 @@ const root = ref<AsUiRoot>(); let components: Ref<AsUiComponent>[] = []; let uiKey = $ref(0); -const saved = localStorage.getItem('scratchpad'); +const saved = miLocalStorage.getItem('scratchpad'); if (saved) { code.value = saved; } watch(code, () => { - localStorage.setItem('scratchpad', code.value); + miLocalStorage.setItem('scratchpad', code.value); }); async function run() { diff --git a/packages/frontend/src/pages/settings/custom-css.vue b/packages/frontend/src/pages/settings/custom-css.vue index 9fa9bdd6585531dc2484ad543abfa89a4f0b9b2a..be2ec32ac2e8e90e8aac12704ac1c1a8baee42cf 100644 --- a/packages/frontend/src/pages/settings/custom-css.vue +++ b/packages/frontend/src/pages/settings/custom-css.vue @@ -16,11 +16,12 @@ import * as os from '@/os'; import { unisonReload } from '@/scripts/unison-reload'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { miLocalStorage } from '@/local-storage'; -const localCustomCss = ref(localStorage.getItem('customCss') ?? ''); +const localCustomCss = ref(miLocalStorage.getItem('customCss') ?? ''); async function apply() { - localStorage.setItem('customCss', localCustomCss.value); + miLocalStorage.setItem('customCss', localCustomCss.value); const { canceled } = await os.confirm({ type: 'info', diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index b90dc3da0e4a479b079f8fce09d27e40af6f8cc8..580c38149a3aca374207709d8318ed1ec7f2a657 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -120,10 +120,11 @@ import * as os from '@/os'; import { unisonReload } from '@/scripts/unison-reload'; import { i18n } from '@/i18n'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { miLocalStorage } from '@/local-storage'; -const lang = ref(localStorage.getItem('lang')); -const fontSize = ref(localStorage.getItem('fontSize')); -const useSystemFont = ref(localStorage.getItem('useSystemFont') != null); +const lang = ref(miLocalStorage.getItem('lang')); +const fontSize = ref(miLocalStorage.getItem('fontSize')); +const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); async function reloadAsk() { const { canceled } = await os.confirm({ @@ -157,23 +158,23 @@ const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars')); const aiChanMode = computed(defaultStore.makeGetterSetter('aiChanMode')); watch(lang, () => { - localStorage.setItem('lang', lang.value as string); - localStorage.removeItem('locale'); + miLocalStorage.setItem('lang', lang.value as string); + miLocalStorage.removeItem('locale'); }); watch(fontSize, () => { if (fontSize.value == null) { - localStorage.removeItem('fontSize'); + miLocalStorage.removeItem('fontSize'); } else { - localStorage.setItem('fontSize', fontSize.value); + miLocalStorage.setItem('fontSize', fontSize.value); } }); watch(useSystemFont, () => { if (useSystemFont.value) { - localStorage.setItem('useSystemFont', 't'); + miLocalStorage.setItem('useSystemFont', 't'); } else { - localStorage.removeItem('useSystemFont'); + miLocalStorage.removeItem('useSystemFont'); } }); diff --git a/packages/frontend/src/pages/settings/index.vue b/packages/frontend/src/pages/settings/index.vue index 119a75b6507bae2d28dec4f39ecd21fe527792ac..3468d44e00b6e02f12b13629104e90626f2a9b3d 100644 --- a/packages/frontend/src/pages/settings/index.vue +++ b/packages/frontend/src/pages/settings/index.vue @@ -33,6 +33,7 @@ import { instance } from '@/instance'; import { useRouter } from '@/router'; import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import * as os from '@/os'; +import { miLocalStorage } from '@/local-storage'; const indexInfo = { title: i18n.ts.settings, @@ -180,8 +181,8 @@ const menuDef = computed(() => [{ icon: 'ti ti-trash', text: i18n.ts.clearCache, action: () => { - localStorage.removeItem('locale'); - localStorage.removeItem('theme'); + miLocalStorage.removeItem('locale'); + miLocalStorage.removeItem('theme'); unisonReload(); }, }, { diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 0c32676c8947d9752860d847a663279e6cf827e1..87a08612fc89aed2b84b3aa98721076bf8838c41 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -45,6 +45,7 @@ import { $i } from '@/account'; import { i18n } from '@/i18n'; import { version, host } from '@/config'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { miLocalStorage } from '@/local-storage'; const { t, ts } = i18n; useCssModule(); @@ -170,9 +171,9 @@ function getSettings(): Profile['settings'] { return { hot, cold, - fontSize: localStorage.getItem('fontSize'), - useSystemFont: localStorage.getItem('useSystemFont') as 't' | null, - wallpaper: localStorage.getItem('wallpaper'), + fontSize: miLocalStorage.getItem('fontSize'), + useSystemFont: miLocalStorage.getItem('useSystemFont') as 't' | null, + wallpaper: miLocalStorage.getItem('wallpaper'), }; } @@ -279,23 +280,23 @@ async function applyProfile(id: string): Promise<void> { // fontSize if (settings.fontSize) { - localStorage.setItem('fontSize', settings.fontSize); + miLocalStorage.setItem('fontSize', settings.fontSize); } else { - localStorage.removeItem('fontSize'); + miLocalStorage.removeItem('fontSize'); } // useSystemFont if (settings.useSystemFont) { - localStorage.setItem('useSystemFont', settings.useSystemFont); + miLocalStorage.setItem('useSystemFont', settings.useSystemFont); } else { - localStorage.removeItem('useSystemFont'); + miLocalStorage.removeItem('useSystemFont'); } // wallpaper if (settings.wallpaper != null) { - localStorage.setItem('wallpaper', settings.wallpaper); + miLocalStorage.setItem('wallpaper', settings.wallpaper); } else { - localStorage.removeItem('wallpaper'); + miLocalStorage.removeItem('wallpaper'); } const { canceled: cancel2 } = await os.confirm({ diff --git a/packages/frontend/src/pages/settings/theme.vue b/packages/frontend/src/pages/settings/theme.vue index 60aa80647d4f815c4baa340b40cf1f30f0b740e3..a2dc9bc95f82c204e7d8f8e82d801c4f1cb95894 100644 --- a/packages/frontend/src/pages/settings/theme.vue +++ b/packages/frontend/src/pages/settings/theme.vue @@ -82,6 +82,7 @@ import { instance } from '@/instance'; import { uniqueBy } from '@/scripts/array'; import { fetchThemes, getThemes } from '@/theme-store'; import { definePageMetadata } from '@/scripts/page-metadata'; +import { miLocalStorage } from '@/local-storage'; const installedThemes = ref(getThemes()); const builtinThemes = getBuiltinThemesRef(); @@ -120,7 +121,7 @@ const lightThemeId = computed({ }); const darkMode = computed(defaultStore.makeGetterSetter('darkMode')); const syncDeviceDarkMode = computed(ColdDeviceStorage.makeGetterSetter('syncDeviceDarkMode')); -const wallpaper = ref(localStorage.getItem('wallpaper')); +const wallpaper = ref(miLocalStorage.getItem('wallpaper')); const themesCount = installedThemes.value.length; watch(syncDeviceDarkMode, () => { @@ -131,9 +132,9 @@ watch(syncDeviceDarkMode, () => { watch(wallpaper, () => { if (wallpaper.value == null) { - localStorage.removeItem('wallpaper'); + miLocalStorage.removeItem('wallpaper'); } else { - localStorage.setItem('wallpaper', wallpaper.value); + miLocalStorage.setItem('wallpaper', wallpaper.value); } location.reload(); }); diff --git a/packages/frontend/src/scripts/aiscript/api.ts b/packages/frontend/src/scripts/aiscript/api.ts index 6debcb8a139336d02d32dcaf1465b012ab648e5a..2a442230806a455af7f149668d4a1985c2ebd921 100644 --- a/packages/frontend/src/scripts/aiscript/api.ts +++ b/packages/frontend/src/scripts/aiscript/api.ts @@ -1,6 +1,7 @@ import { utils, values } from '@syuilo/aiscript'; import * as os from '@/os'; import { $i } from '@/account'; +import { miLocalStorage } from '@/local-storage'; export function createAiScriptEnv(opts) { let apiRequests = 0; @@ -32,12 +33,12 @@ export function createAiScriptEnv(opts) { }), 'Mk:save': values.FN_NATIVE(([key, value]) => { utils.assertString(key); - localStorage.setItem('aiscript:' + opts.storageKey + ':' + key.value, JSON.stringify(utils.valToJs(value))); + miLocalStorage.setItem(`aiscript:${opts.storageKey}:${key.value}`, JSON.stringify(utils.valToJs(value))); return values.NULL; }), 'Mk:load': values.FN_NATIVE(([key]) => { utils.assertString(key); - return utils.jsToVal(JSON.parse(localStorage.getItem('aiscript:' + opts.storageKey + ':' + key.value))); + return utils.jsToVal(JSON.parse(miLocalStorage.getItem(`aiscript:${opts.storageKey}:${key.value}`))); }), }; } diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index 7656770894b38aadbb3091452a59415f0841b2e2..1b723220ee460ef1306940f7b11ba49370b9af99 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -9,6 +9,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard'; import { url } from '@/config'; import { noteActions } from '@/store'; import { notePage } from '@/filters/note'; +import { miLocalStorage } from '@/local-storage'; export function getNoteMenu(props: { note: misskey.entities.Note; @@ -181,7 +182,7 @@ export function getNoteMenu(props: { props.translating.value = true; const res = await os.api('notes/translate', { noteId: appearNote.id, - targetLang: localStorage.getItem('lang') || navigator.language, + targetLang: miLocalStorage.getItem('lang') || navigator.language, }); props.translating.value = false; props.translation.value = res; diff --git a/packages/frontend/src/scripts/idb-proxy.ts b/packages/frontend/src/scripts/idb-proxy.ts index 77bb84463cc2e59506dd99743194e1fa64c2c578..218682bb56b8fad69251fdb0f2324510a78257c9 100644 --- a/packages/frontend/src/scripts/idb-proxy.ts +++ b/packages/frontend/src/scripts/idb-proxy.ts @@ -22,15 +22,15 @@ if (idbAvailable) { export async function get(key: string) { if (idbAvailable) return iget(key); - return JSON.parse(localStorage.getItem(fallbackName(key))); + return JSON.parse(window.localStorage.getItem(fallbackName(key))); } export async function set(key: string, val: any) { if (idbAvailable) return iset(key, val); - return localStorage.setItem(fallbackName(key), JSON.stringify(val)); + return window.localStorage.setItem(fallbackName(key), JSON.stringify(val)); } export async function del(key: string) { if (idbAvailable) return idel(key); - return localStorage.removeItem(fallbackName(key)); + return window.localStorage.removeItem(fallbackName(key)); } diff --git a/packages/frontend/src/scripts/theme.ts b/packages/frontend/src/scripts/theme.ts index 62a2b9459a7c4534296c4182c509477e5a0bf5a4..42cb00265dfda16fc6799c7ec695c3227af219e1 100644 --- a/packages/frontend/src/scripts/theme.ts +++ b/packages/frontend/src/scripts/theme.ts @@ -14,6 +14,7 @@ export type Theme = { import lightTheme from '@/themes/_light.json5'; import darkTheme from '@/themes/_dark.json5'; import { deepClone } from './clone'; +import { miLocalStorage } from '@/local-storage'; export const themeProps = Object.keys(lightTheme.props).filter(key => !key.startsWith('X')); @@ -84,8 +85,8 @@ export function applyTheme(theme: Theme, persist = true) { document.documentElement.style.setProperty('color-schema', colorSchema); if (persist) { - localStorage.setItem('theme', JSON.stringify(props)); - localStorage.setItem('colorSchema', colorSchema); + miLocalStorage.setItem('theme', JSON.stringify(props)); + miLocalStorage.setItem('colorSchema', colorSchema); } // 色計算ãªã©å†åº¦è¡Œãˆã‚‹ã‚ˆã†ã«ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆå…¨ä½“ã«é€šçŸ¥ diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index 4b1f47c2bcbb9df977e73862a0714abe1be2295d..97b6ebc188eee1fe092783f271216f0a07b187b2 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -86,6 +86,14 @@ export const defaultStore = markRaw(new Storage('base', { where: 'account', default: [] as string[], }, + latestDonateDialogShowAt: { + where: 'account', + default: null, + }, + neverShowDonateDialog: { + where: 'account', + default: false, + }, menu: { where: 'deviceAccount', @@ -274,7 +282,7 @@ export const defaultStore = markRaw(new Storage('base', { // TODO: ä»–ã®ã‚¿ãƒ–ã¨æ°¸ç¶šåŒ–ã•ã‚ŒãŸstateã‚’åŒæœŸ -const PREFIX = 'miux:'; +const PREFIX = 'miux:' as const; type Plugin = { id: string; @@ -296,6 +304,7 @@ interface Watcher { import lightTheme from '@/themes/l-light.json5'; import darkTheme from '@/themes/d-green-lime.json5'; import { Note, UserDetailed } from 'misskey-js/built/entities'; +import { miLocalStorage } from './local-storage'; export class ColdDeviceStorage { public static default = { @@ -320,7 +329,7 @@ export class ColdDeviceStorage { // TODO: indexedDBã«ã™ã‚‹ // ãŸã ã—ãã®éš›ã¯nullãƒã‚§ãƒƒã‚¯ã§ã¯ãªãã‚ーå˜åœ¨ãƒã‚§ãƒƒã‚¯ã«ã—ãªã„ã¨ãƒ€ãƒ¡ // (indexedDBã¯nullã‚’ä¿å˜ã§ãã‚‹ãŸã‚ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒæ„図ã—ã¦nullã‚’æ ¼ç´ã—ãŸå¯èƒ½æ€§ãŒã‚ã‚‹) - const value = localStorage.getItem(PREFIX + key); + const value = miLocalStorage.getItem(`${PREFIX}${key}`); if (value == null) { return ColdDeviceStorage.default[key]; } else { @@ -330,14 +339,14 @@ export class ColdDeviceStorage { public static set<T extends keyof typeof ColdDeviceStorage.default>(key: T, value: typeof ColdDeviceStorage.default[T]): void { // 呼ã³å‡ºã—å´ã®ãƒã‚°ç‰ã§ undefined ãŒæ¥ã‚‹ã“ã¨ãŒã‚ã‚‹ - // undefined ã‚’æ–‡å—列ã¨ã—㦠localStorage ã«å…¥ã‚Œã‚‹ã¨å‚ç…§ã™ã‚‹éš›ã® JSON.parse ã§ã‚³ã‚±ã¦ä¸å…·åˆã®å…ƒã«ãªã‚‹ãŸã‚無視 + // undefined ã‚’æ–‡å—列ã¨ã—㦠miLocalStorage ã«å…¥ã‚Œã‚‹ã¨å‚ç…§ã™ã‚‹éš›ã® JSON.parse ã§ã‚³ã‚±ã¦ä¸å…·åˆã®å…ƒã«ãªã‚‹ãŸã‚無視 // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition if (value === undefined) { console.error(`attempt to store undefined value for key '${key}'`); return; } - localStorage.setItem(PREFIX + key, JSON.stringify(value)); + miLocalStorage.setItem(`${PREFIX}${key}`, JSON.stringify(value)); for (const watcher of this.watchers) { if (watcher.key === key) watcher.callback(value); diff --git a/packages/frontend/src/theme-store.ts b/packages/frontend/src/theme-store.ts index fdc92ed793e5899a52b32093e5439813184284df..aa1244665b2713875de16467ee26e4f607f477e9 100644 --- a/packages/frontend/src/theme-store.ts +++ b/packages/frontend/src/theme-store.ts @@ -1,11 +1,13 @@ import { api } from '@/os'; import { $i } from '@/account'; import { Theme } from './scripts/theme'; +import { miLocalStorage } from './local-storage'; -const lsCacheKey = $i ? `themes:${$i.id}` : ''; +const lsCacheKey = $i ? `themes:${$i.id}` as const : null; export function getThemes(): Theme[] { - return JSON.parse(localStorage.getItem(lsCacheKey) || '[]'); + if ($i == null) return []; + return JSON.parse(miLocalStorage.getItem(lsCacheKey!) || '[]'); } export async function fetchThemes(): Promise<void> { @@ -13,7 +15,7 @@ export async function fetchThemes(): Promise<void> { try { const themes = await api('i/registry/get', { scope: ['client'], key: 'themes' }); - localStorage.setItem(lsCacheKey, JSON.stringify(themes)); + miLocalStorage.setItem(lsCacheKey!, JSON.stringify(themes)); } catch (err) { if (err.code === 'NO_SUCH_KEY') return; throw err; @@ -21,14 +23,16 @@ export async function fetchThemes(): Promise<void> { } export async function addTheme(theme: Theme): Promise<void> { + if ($i == null) return; await fetchThemes(); const themes = getThemes().concat(theme); await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); - localStorage.setItem(lsCacheKey, JSON.stringify(themes)); + miLocalStorage.setItem(lsCacheKey!, JSON.stringify(themes)); } export async function removeTheme(theme: Theme): Promise<void> { + if ($i == null) return; const themes = getThemes().filter(t => t.id !== theme.id); await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); - localStorage.setItem(lsCacheKey, JSON.stringify(themes)); + miLocalStorage.setItem(lsCacheKey!, JSON.stringify(themes)); } diff --git a/packages/frontend/src/ui/classic.vue b/packages/frontend/src/ui/classic.vue index 280e69e7dd39eb6e161502a752af42af66f79acb..f220501ee2d9b24055d4503330cbe59841562c05 100644 --- a/packages/frontend/src/ui/classic.vue +++ b/packages/frontend/src/ui/classic.vue @@ -51,6 +51,7 @@ import { mainRouter } from '@/router'; import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import { defaultStore } from '@/store'; import { i18n } from '@/i18n'; +import { miLocalStorage } from '@/local-storage'; const XHeaderMenu = defineAsyncComponent(() => import('./classic.header.vue')); const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); @@ -62,7 +63,7 @@ let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); let widgetsShowing = $ref(false); let fullView = $ref(false); let globalHeaderHeight = $ref(0); -const wallpaper = localStorage.getItem('wallpaper') != null; +const wallpaper = miLocalStorage.getItem('wallpaper') != null; const showMenuOnTop = $computed(() => defaultStore.state.menuDisplay === 'top'); let live2d = $shallowRef<HTMLIFrameElement>(); let widgetsLeft = $ref(); @@ -123,7 +124,7 @@ function onAiClick(ev) { } if (window.innerWidth < 1024) { - localStorage.setItem('ui', 'default'); + miLocalStorage.setItem('ui', 'default'); location.reload(); } diff --git a/packages/frontend/src/ui/universal.vue b/packages/frontend/src/ui/universal.vue index 9e1fee5b6bb9f6843ea96dd7f35da1f5852906ea..06129ffc8702be19fb4e194f212651c26ac11bc1 100644 --- a/packages/frontend/src/ui/universal.vue +++ b/packages/frontend/src/ui/universal.vue @@ -71,6 +71,7 @@ import { Router } from '@/nirax'; import { mainRouter } from '@/router'; import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; import { deviceKind } from '@/scripts/device-kind'; +import { miLocalStorage } from '@/local-storage'; const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); @@ -170,7 +171,7 @@ function top() { window.scroll({ top: 0, behavior: 'smooth' }); } -const wallpaper = localStorage.getItem('wallpaper') != null; +const wallpaper = miLocalStorage.getItem('wallpaper') != null; </script> <style lang="scss" scoped>