refactor(client): typed localStorage
This commit is contained in:
		
							parent
							
								
									a42b03c154
								
							
						
					
					
						commit
						91503405b4
					
				
					 25 changed files with 157 additions and 88 deletions
				
			
		|  | @ -6,12 +6,13 @@ import { del, get, set } from '@/scripts/idb-proxy'; | ||||||
| import { apiUrl } from '@/config'; | import { apiUrl } from '@/config'; | ||||||
| import { waiting, api, popup, popupMenu, success, alert } from '@/os'; | import { waiting, api, popup, popupMenu, success, alert } from '@/os'; | ||||||
| import { unisonReload, reloadChannel } from '@/scripts/unison-reload'; | import { unisonReload, reloadChannel } from '@/scripts/unison-reload'; | ||||||
|  | import { miLocalStorage } from './local-storage'; | ||||||
| 
 | 
 | ||||||
| // TODO: 他のタブと永続化されたstateを同期
 | // TODO: 他のタブと永続化されたstateを同期
 | ||||||
| 
 | 
 | ||||||
| type Account = misskey.entities.MeDetailed; | type Account = misskey.entities.MeDetailed; | ||||||
| 
 | 
 | ||||||
| const accountData = localStorage.getItem('account'); | const accountData = miLocalStorage.getItem('account'); | ||||||
| 
 | 
 | ||||||
| // TODO: 外部からはreadonlyに
 | // TODO: 外部からはreadonlyに
 | ||||||
| export const $i = accountData ? reactive(JSON.parse(accountData) as Account) : null; | 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() { | export async function signout() { | ||||||
| 	waiting(); | 	waiting(); | ||||||
| 	localStorage.removeItem('account'); | 	miLocalStorage.removeItem('account'); | ||||||
| 
 | 
 | ||||||
| 	await removeAccount($i.id); | 	await removeAccount($i.id); | ||||||
| 
 | 
 | ||||||
|  | @ -119,7 +120,7 @@ export function updateAccount(accountData) { | ||||||
| 	for (const [key, value] of Object.entries(accountData)) { | 	for (const [key, value] of Object.entries(accountData)) { | ||||||
| 		$i[key] = value; | 		$i[key] = value; | ||||||
| 	} | 	} | ||||||
| 	localStorage.setItem('account', JSON.stringify($i)); | 	miLocalStorage.setItem('account', JSON.stringify($i)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function refreshAccount() { | export function refreshAccount() { | ||||||
|  | @ -130,7 +131,7 @@ export async function login(token: Account['token'], redirect?: string) { | ||||||
| 	waiting(); | 	waiting(); | ||||||
| 	if (_DEV_) console.log('logging as token ', token); | 	if (_DEV_) console.log('logging as token ', token); | ||||||
| 	const me = await fetchAccount(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の認証とかで使う
 | 	document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う
 | ||||||
| 	await addAccount(me.id, token); | 	await addAccount(me.id, token); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ import { defaultStore } from '@/store'; | ||||||
| import { emojilist } from '@/scripts/emojilist'; | import { emojilist } from '@/scripts/emojilist'; | ||||||
| import { instance } from '@/instance'; | import { instance } from '@/instance'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| type EmojiDef = { | type EmojiDef = { | ||||||
| 	emoji: string; | 	emoji: string; | ||||||
|  | @ -208,7 +209,7 @@ function exec() { | ||||||
| 		} | 		} | ||||||
| 	} else if (props.type === 'hashtag') { | 	} else if (props.type === 'hashtag') { | ||||||
| 		if (!props.q || props.q === '') { | 		if (!props.q || props.q === '') { | ||||||
| 			hashtags.value = JSON.parse(localStorage.getItem('hashtags') || '[]'); | 			hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') || '[]'); | ||||||
| 			fetching.value = false; | 			fetching.value = false; | ||||||
| 		} else { | 		} else { | ||||||
| 			const cacheKey = `autocomplete:hashtag:${props.q}`; | 			const cacheKey = `autocomplete:hashtag:${props.q}`; | ||||||
|  |  | ||||||
|  | @ -25,8 +25,9 @@ | ||||||
| <script lang="ts"> | <script lang="ts"> | ||||||
| import { defineComponent } from 'vue'; | import { defineComponent } from 'vue'; | ||||||
| import tinycolor from 'tinycolor2'; | import tinycolor from 'tinycolor2'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const localStoragePrefix = 'ui:folder:'; | const miLocalStoragePrefix = 'ui:folder:' as const; | ||||||
| 
 | 
 | ||||||
| export default defineComponent({ | export default defineComponent({ | ||||||
| 	props: { | 	props: { | ||||||
|  | @ -44,13 +45,13 @@ export default defineComponent({ | ||||||
| 	data() { | 	data() { | ||||||
| 		return { | 		return { | ||||||
| 			bg: null, | 			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: { | 	watch: { | ||||||
| 		showBody() { | 		showBody() { | ||||||
| 			if (this.persistKey) { | 			if (this.persistKey) { | ||||||
| 				localStorage.setItem(localStoragePrefix + this.persistKey, this.showBody ? 't' : 'f'); | 				miLocalStorage.setItem(`${miLocalStoragePrefix}${this.persistKey}`, this.showBody ? 't' : 'f'); | ||||||
| 			} | 			} | ||||||
| 		}, | 		}, | ||||||
| 	}, | 	}, | ||||||
|  |  | ||||||
|  | @ -98,6 +98,7 @@ import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account' | ||||||
| import { uploadFile } from '@/scripts/upload'; | import { uploadFile } from '@/scripts/upload'; | ||||||
| import { deepClone } from '@/scripts/clone'; | import { deepClone } from '@/scripts/clone'; | ||||||
| import MkRippleEffect from '@/components/MkRippleEffect.vue'; | import MkRippleEffect from '@/components/MkRippleEffect.vue'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const modal = inject('modal'); | const modal = inject('modal'); | ||||||
| 
 | 
 | ||||||
|  | @ -156,7 +157,7 @@ let autocomplete = $ref(null); | ||||||
| let draghover = $ref(false); | let draghover = $ref(false); | ||||||
| let quoteId = $ref(null); | let quoteId = $ref(null); | ||||||
| let hasNotSpecifiedMentions = $ref(false); | let hasNotSpecifiedMentions = $ref(false); | ||||||
| let recentHashtags = $ref(JSON.parse(localStorage.getItem('hashtags') || '[]')); | let recentHashtags = $ref(JSON.parse(miLocalStorage.getItem('hashtags') || '[]')); | ||||||
| let imeText = $ref(''); | let imeText = $ref(''); | ||||||
| 
 | 
 | ||||||
| const typing = throttle(3000, () => { | const typing = throttle(3000, () => { | ||||||
|  | @ -543,7 +544,7 @@ function onDrop(ev): void { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function saveDraft() { | function saveDraft() { | ||||||
| 	const draftData = JSON.parse(localStorage.getItem('drafts') || '{}'); | 	const draftData = JSON.parse(miLocalStorage.getItem('drafts') || '{}'); | ||||||
| 
 | 
 | ||||||
| 	draftData[draftKey] = { | 	draftData[draftKey] = { | ||||||
| 		updatedAt: new Date(), | 		updatedAt: new Date(), | ||||||
|  | @ -558,15 +559,15 @@ function saveDraft() { | ||||||
| 		}, | 		}, | ||||||
| 	}; | 	}; | ||||||
| 
 | 
 | ||||||
| 	localStorage.setItem('drafts', JSON.stringify(draftData)); | 	miLocalStorage.setItem('drafts', JSON.stringify(draftData)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function deleteDraft() { | function deleteDraft() { | ||||||
| 	const draftData = JSON.parse(localStorage.getItem('drafts') ?? '{}'); | 	const draftData = JSON.parse(miLocalStorage.getItem('drafts') ?? '{}'); | ||||||
| 
 | 
 | ||||||
| 	delete draftData[draftKey]; | 	delete draftData[draftKey]; | ||||||
| 
 | 
 | ||||||
| 	localStorage.setItem('drafts', JSON.stringify(draftData)); | 	miLocalStorage.setItem('drafts', JSON.stringify(draftData)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function post(ev?: MouseEvent) { | async function post(ev?: MouseEvent) { | ||||||
|  | @ -622,8 +623,8 @@ async function post(ev?: MouseEvent) { | ||||||
| 			emit('posted'); | 			emit('posted'); | ||||||
| 			if (postData.text && postData.text !== '') { | 			if (postData.text && postData.text !== '') { | ||||||
| 				const hashtags_ = mfm.parse(postData.text).filter(x => x.type === 'hashtag').map(x => x.props.hashtag); | 				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[]; | 				const history = JSON.parse(miLocalStorage.getItem('hashtags') || '[]') as string[]; | ||||||
| 				localStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history)))); | 				miLocalStorage.setItem('hashtags', JSON.stringify(unique(hashtags_.concat(history)))); | ||||||
| 			} | 			} | ||||||
| 			posting = false; | 			posting = false; | ||||||
| 			postAccount = null; | 			postAccount = null; | ||||||
|  | @ -698,7 +699,7 @@ onMounted(() => { | ||||||
| 	nextTick(() => { | 	nextTick(() => { | ||||||
| 		// 書きかけの投稿を復元 | 		// 書きかけの投稿を復元 | ||||||
| 		if (!props.instant && !props.mention && !props.specified) { | 		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) { | 			if (draft) { | ||||||
| 				text = draft.data.text; | 				text = draft.data.text; | ||||||
| 				useCw = draft.data.useCw; | 				useCw = draft.data.useCw; | ||||||
|  |  | ||||||
|  | @ -1,3 +1,5 @@ | ||||||
|  | import { miLocalStorage } from "./local-storage"; | ||||||
|  | 
 | ||||||
| const address = new URL(location.href); | const address = new URL(location.href); | ||||||
| const siteName = (document.querySelector('meta[property="og:site_name"]') as HTMLMetaElement)?.content; | 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 url = address.origin; | ||||||
| export const apiUrl = url + '/api'; | export const apiUrl = url + '/api'; | ||||||
| export const wsUrl = url.replace('http://', 'ws://').replace('https://', 'wss://') + '/streaming'; | 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 langs = _LANGS_; | ||||||
| export const locale = JSON.parse(localStorage.getItem('locale')); | export const locale = JSON.parse(miLocalStorage.getItem('locale')); | ||||||
| export const version = _VERSION_; | export const version = _VERSION_; | ||||||
| export const instanceName = siteName === 'Misskey' ? host : siteName; | export const instanceName = siteName === 'Misskey' ? host : siteName; | ||||||
| export const ui = localStorage.getItem('ui'); | export const ui = miLocalStorage.getItem('ui'); | ||||||
| export const debug = localStorage.getItem('debug') === 'true'; | export const debug = miLocalStorage.getItem('debug') === 'true'; | ||||||
|  |  | ||||||
|  | @ -9,9 +9,12 @@ import '@/style.scss'; | ||||||
| //#region account indexedDB migration
 | //#region account indexedDB migration
 | ||||||
| import { set } from '@/scripts/idb-proxy'; | import { set } from '@/scripts/idb-proxy'; | ||||||
| 
 | 
 | ||||||
| if (localStorage.getItem('accounts') != null) { | { | ||||||
| 	set('accounts', JSON.parse(localStorage.getItem('accounts'))); | 	const accounts = miLocalStorage.getItem('accounts'); | ||||||
| 	localStorage.removeItem('accounts'); | 	if (accounts) { | ||||||
|  | 		set('accounts', JSON.parse(accounts)); | ||||||
|  | 		miLocalStorage.removeItem('accounts'); | ||||||
|  | 	} | ||||||
| } | } | ||||||
| //#endregion
 | //#endregion
 | ||||||
| 
 | 
 | ||||||
|  | @ -40,6 +43,7 @@ import { reloadChannel } from '@/scripts/unison-reload'; | ||||||
| import { reactionPicker } from '@/scripts/reaction-picker'; | import { reactionPicker } from '@/scripts/reaction-picker'; | ||||||
| import { getUrlWithoutLoginId } from '@/scripts/login-id'; | import { getUrlWithoutLoginId } from '@/scripts/login-id'; | ||||||
| import { getAccountFromId } from '@/scripts/get-account-from-id'; | import { getAccountFromId } from '@/scripts/get-account-from-id'; | ||||||
|  | import { miLocalStorage } from './local-storage'; | ||||||
| 
 | 
 | ||||||
| (async () => { | (async () => { | ||||||
| 	console.info(`Misskey v${version}`); | 	console.info(`Misskey v${version}`); | ||||||
|  | @ -154,7 +158,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; | ||||||
| 	const fetchInstanceMetaPromise = fetchInstance(); | 	const fetchInstanceMetaPromise = fetchInstance(); | ||||||
| 
 | 
 | ||||||
| 	fetchInstanceMetaPromise.then(() => { | 	fetchInstanceMetaPromise.then(() => { | ||||||
| 		localStorage.setItem('v', instance.version); | 		miLocalStorage.setItem('v', instance.version); | ||||||
| 
 | 
 | ||||||
| 		// Init service worker
 | 		// Init service worker
 | ||||||
| 		initializeSw(); | 		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) { | 	if (lastVersion !== version) { | ||||||
| 		localStorage.setItem('lastVersion', version); | 		miLocalStorage.setItem('lastVersion', version); | ||||||
| 
 | 
 | ||||||
| 		// テーマリビルドするため
 | 		// テーマリビルドするため
 | ||||||
| 		localStorage.removeItem('theme'); | 		miLocalStorage.removeItem('theme'); | ||||||
| 
 | 
 | ||||||
| 		try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため
 | 		try { // 変なバージョン文字列来るとcompareVersionsでエラーになるため
 | ||||||
| 			if (lastVersion != null && compareVersions(version, lastVersion) === 1) { | 			if (lastVersion != null && compareVersions(version, lastVersion) === 1) { | ||||||
|  | @ -244,7 +248,7 @@ import { getAccountFromId } from '@/scripts/get-account-from-id'; | ||||||
| 	// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため)
 | 	// NOTE: この処理は必ず↑のクライアント更新時処理より後に来ること(テーマ再構築のため)
 | ||||||
| 	watch(defaultStore.reactiveState.darkMode, (darkMode) => { | 	watch(defaultStore.reactiveState.darkMode, (darkMode) => { | ||||||
| 		applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); | 		applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); | ||||||
| 	}, { immediate: localStorage.theme == null }); | 	}, { immediate: miLocalStorage.getItem('theme') == null }); | ||||||
| 
 | 
 | ||||||
| 	const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); | 	const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); | ||||||
| 	const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); | 	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) { | 		if (lastUsed) { | ||||||
| 			const lastUsedDate = parseInt(lastUsed, 10); | 			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) { | 		if ('Notification' in window) { | ||||||
| 			// 許可を得ていなかったらリクエスト
 | 			// 許可を得ていなかったらリクエスト
 | ||||||
|  |  | ||||||
|  | @ -1,10 +1,11 @@ | ||||||
| import { computed, reactive } from 'vue'; | import { computed, reactive } from 'vue'; | ||||||
| import * as Misskey from 'misskey-js'; | import * as Misskey from 'misskey-js'; | ||||||
| import { api } from './os'; | import { api } from './os'; | ||||||
|  | import { miLocalStorage } from './local-storage'; | ||||||
| 
 | 
 | ||||||
| // TODO: 他のタブと永続化されたstateを同期
 | // TODO: 他のタブと永続化されたstateを同期
 | ||||||
| 
 | 
 | ||||||
| const instanceData = localStorage.getItem('instance'); | const instanceData = miLocalStorage.getItem('instance'); | ||||||
| 
 | 
 | ||||||
| // TODO: instanceをリアクティブにするかは再考の余地あり
 | // TODO: instanceをリアクティブにするかは再考の余地あり
 | ||||||
| 
 | 
 | ||||||
|  | @ -21,7 +22,7 @@ export async function fetchInstance() { | ||||||
| 		instance[k] = v; | 		instance[k] = v; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	localStorage.setItem('instance', JSON.stringify(instance)); | 	miLocalStorage.setItem('instance', JSON.stringify(instance)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const emojiCategories = computed(() => { | export const emojiCategories = computed(() => { | ||||||
|  |  | ||||||
							
								
								
									
										31
									
								
								packages/frontend/src/local-storage.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								packages/frontend/src/local-storage.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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), | ||||||
|  | }; | ||||||
|  | @ -5,6 +5,7 @@ import * as os from '@/os'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { ui } from '@/config'; | import { ui } from '@/config'; | ||||||
| import { unisonReload } from '@/scripts/unison-reload'; | import { unisonReload } from '@/scripts/unison-reload'; | ||||||
|  | import { miLocalStorage } from './local-storage'; | ||||||
| 
 | 
 | ||||||
| export const navbarItemDef = reactive({ | export const navbarItemDef = reactive({ | ||||||
| 	notifications: { | 	notifications: { | ||||||
|  | @ -110,21 +111,21 @@ export const navbarItemDef = reactive({ | ||||||
| 				text: i18n.ts.default, | 				text: i18n.ts.default, | ||||||
| 				active: ui === 'default' || ui === null, | 				active: ui === 'default' || ui === null, | ||||||
| 				action: () => { | 				action: () => { | ||||||
| 					localStorage.setItem('ui', 'default'); | 					miLocalStorage.setItem('ui', 'default'); | ||||||
| 					unisonReload(); | 					unisonReload(); | ||||||
| 				}, | 				}, | ||||||
| 			}, { | 			}, { | ||||||
| 				text: i18n.ts.deck, | 				text: i18n.ts.deck, | ||||||
| 				active: ui === 'deck', | 				active: ui === 'deck', | ||||||
| 				action: () => { | 				action: () => { | ||||||
| 					localStorage.setItem('ui', 'deck'); | 					miLocalStorage.setItem('ui', 'deck'); | ||||||
| 					unisonReload(); | 					unisonReload(); | ||||||
| 				}, | 				}, | ||||||
| 			}, { | 			}, { | ||||||
| 				text: i18n.ts.classic, | 				text: i18n.ts.classic, | ||||||
| 				active: ui === 'classic', | 				active: ui === 'classic', | ||||||
| 				action: () => { | 				action: () => { | ||||||
| 					localStorage.setItem('ui', 'classic'); | 					miLocalStorage.setItem('ui', 'classic'); | ||||||
| 					unisonReload(); | 					unisonReload(); | ||||||
| 				}, | 				}, | ||||||
| 			}], ev.currentTarget ?? ev.target); | 			}], ev.currentTarget ?? ev.target); | ||||||
|  |  | ||||||
|  | @ -26,6 +26,7 @@ import * as os from '@/os'; | ||||||
| import { unisonReload } from '@/scripts/unison-reload'; | import { unisonReload } from '@/scripts/unison-reload'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata } from '@/scripts/page-metadata'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const props = withDefaults(defineProps<{ | const props = withDefaults(defineProps<{ | ||||||
| 	error?: Error; | 	error?: Error; | ||||||
|  | @ -42,7 +43,7 @@ os.api('meta', { | ||||||
| 	loaded = true; | 	loaded = true; | ||||||
| 	serverIsDead = false; | 	serverIsDead = false; | ||||||
| 	meta = res; | 	meta = res; | ||||||
| 	localStorage.setItem('v', res.version); | 	miLocalStorage.setItem('v', res.version); | ||||||
| }, () => { | }, () => { | ||||||
| 	loaded = true; | 	loaded = true; | ||||||
| 	serverIsDead = true; | 	serverIsDead = true; | ||||||
|  |  | ||||||
|  | @ -40,6 +40,7 @@ import { defaultStore } from '@/store'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| //import { Autocomplete } from '@/scripts/autocomplete'; | //import { Autocomplete } from '@/scripts/autocomplete'; | ||||||
| import { uploadFile } from '@/scripts/upload'; | import { uploadFile } from '@/scripts/upload'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ | const props = defineProps<{ | ||||||
| 	user?: Misskey.entities.UserDetailed | null; | 	user?: Misskey.entities.UserDetailed | null; | ||||||
|  | @ -188,7 +189,7 @@ function clear() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function saveDraft() { | function saveDraft() { | ||||||
| 	const drafts = JSON.parse(localStorage.getItem('message_drafts') || '{}'); | 	const drafts = JSON.parse(miLocalStorage.getItem('message_drafts') || '{}'); | ||||||
| 
 | 
 | ||||||
| 	drafts[draftKey] = { | 	drafts[draftKey] = { | ||||||
| 		updatedAt: new Date(), | 		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() { | function deleteDraft() { | ||||||
| 	const drafts = JSON.parse(localStorage.getItem('message_drafts') || '{}'); | 	const drafts = JSON.parse(miLocalStorage.getItem('message_drafts') || '{}'); | ||||||
| 
 | 
 | ||||||
| 	delete drafts[draftKey]; | 	delete drafts[draftKey]; | ||||||
| 
 | 
 | ||||||
| 	localStorage.setItem('message_drafts', JSON.stringify(drafts)); | 	miLocalStorage.setItem('message_drafts', JSON.stringify(drafts)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| async function insertEmoji(ev: MouseEvent) { | async function insertEmoji(ev: MouseEvent) { | ||||||
|  | @ -222,7 +223,7 @@ onMounted(() => { | ||||||
| 	//new Autocomplete(textEl, this, { model: 'text' }); | 	//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) { | 	if (draft) { | ||||||
| 		text = draft.data.text; | 		text = draft.data.text; | ||||||
| 		file = draft.data.file; | 		file = draft.data.file; | ||||||
|  |  | ||||||
|  | @ -46,6 +46,7 @@ import { i18n } from '@/i18n'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata } from '@/scripts/page-metadata'; | ||||||
| import { AsUiComponent, AsUiRoot, patch, registerAsUiLib, render } from '@/scripts/aiscript/ui'; | import { AsUiComponent, AsUiRoot, patch, registerAsUiLib, render } from '@/scripts/aiscript/ui'; | ||||||
| import MkAsUi from '@/components/MkAsUi.vue'; | import MkAsUi from '@/components/MkAsUi.vue'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const parser = new Parser(); | const parser = new Parser(); | ||||||
| let aiscript: Interpreter; | let aiscript: Interpreter; | ||||||
|  | @ -55,13 +56,13 @@ const root = ref<AsUiRoot>(); | ||||||
| let components: Ref<AsUiComponent>[] = []; | let components: Ref<AsUiComponent>[] = []; | ||||||
| let uiKey = $ref(0); | let uiKey = $ref(0); | ||||||
| 
 | 
 | ||||||
| const saved = localStorage.getItem('scratchpad'); | const saved = miLocalStorage.getItem('scratchpad'); | ||||||
| if (saved) { | if (saved) { | ||||||
| 	code.value = saved; | 	code.value = saved; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| watch(code, () => { | watch(code, () => { | ||||||
| 	localStorage.setItem('scratchpad', code.value); | 	miLocalStorage.setItem('scratchpad', code.value); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| async function run() { | async function run() { | ||||||
|  |  | ||||||
|  | @ -16,11 +16,12 @@ import * as os from '@/os'; | ||||||
| import { unisonReload } from '@/scripts/unison-reload'; | import { unisonReload } from '@/scripts/unison-reload'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | 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() { | async function apply() { | ||||||
| 	localStorage.setItem('customCss', localCustomCss.value); | 	miLocalStorage.setItem('customCss', localCustomCss.value); | ||||||
| 
 | 
 | ||||||
| 	const { canceled } = await os.confirm({ | 	const { canceled } = await os.confirm({ | ||||||
| 		type: 'info', | 		type: 'info', | ||||||
|  |  | ||||||
|  | @ -120,10 +120,11 @@ import * as os from '@/os'; | ||||||
| import { unisonReload } from '@/scripts/unison-reload'; | import { unisonReload } from '@/scripts/unison-reload'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata } from '@/scripts/page-metadata'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const lang = ref(localStorage.getItem('lang')); | const lang = ref(miLocalStorage.getItem('lang')); | ||||||
| const fontSize = ref(localStorage.getItem('fontSize')); | const fontSize = ref(miLocalStorage.getItem('fontSize')); | ||||||
| const useSystemFont = ref(localStorage.getItem('useSystemFont') != null); | const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); | ||||||
| 
 | 
 | ||||||
| async function reloadAsk() { | async function reloadAsk() { | ||||||
| 	const { canceled } = await os.confirm({ | 	const { canceled } = await os.confirm({ | ||||||
|  | @ -157,23 +158,23 @@ const squareAvatars = computed(defaultStore.makeGetterSetter('squareAvatars')); | ||||||
| const aiChanMode = computed(defaultStore.makeGetterSetter('aiChanMode')); | const aiChanMode = computed(defaultStore.makeGetterSetter('aiChanMode')); | ||||||
| 
 | 
 | ||||||
| watch(lang, () => { | watch(lang, () => { | ||||||
| 	localStorage.setItem('lang', lang.value as string); | 	miLocalStorage.setItem('lang', lang.value as string); | ||||||
| 	localStorage.removeItem('locale'); | 	miLocalStorage.removeItem('locale'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| watch(fontSize, () => { | watch(fontSize, () => { | ||||||
| 	if (fontSize.value == null) { | 	if (fontSize.value == null) { | ||||||
| 		localStorage.removeItem('fontSize'); | 		miLocalStorage.removeItem('fontSize'); | ||||||
| 	} else { | 	} else { | ||||||
| 		localStorage.setItem('fontSize', fontSize.value); | 		miLocalStorage.setItem('fontSize', fontSize.value); | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| watch(useSystemFont, () => { | watch(useSystemFont, () => { | ||||||
| 	if (useSystemFont.value) { | 	if (useSystemFont.value) { | ||||||
| 		localStorage.setItem('useSystemFont', 't'); | 		miLocalStorage.setItem('useSystemFont', 't'); | ||||||
| 	} else { | 	} else { | ||||||
| 		localStorage.removeItem('useSystemFont'); | 		miLocalStorage.removeItem('useSystemFont'); | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,6 +33,7 @@ import { instance } from '@/instance'; | ||||||
| import { useRouter } from '@/router'; | import { useRouter } from '@/router'; | ||||||
| import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const indexInfo = { | const indexInfo = { | ||||||
| 	title: i18n.ts.settings, | 	title: i18n.ts.settings, | ||||||
|  | @ -180,8 +181,8 @@ const menuDef = computed(() => [{ | ||||||
| 		icon: 'ti ti-trash', | 		icon: 'ti ti-trash', | ||||||
| 		text: i18n.ts.clearCache, | 		text: i18n.ts.clearCache, | ||||||
| 		action: () => { | 		action: () => { | ||||||
| 			localStorage.removeItem('locale'); | 			miLocalStorage.removeItem('locale'); | ||||||
| 			localStorage.removeItem('theme'); | 			miLocalStorage.removeItem('theme'); | ||||||
| 			unisonReload(); | 			unisonReload(); | ||||||
| 		}, | 		}, | ||||||
| 	}, { | 	}, { | ||||||
|  |  | ||||||
|  | @ -45,6 +45,7 @@ import { $i } from '@/account'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
| import { version, host } from '@/config'; | import { version, host } from '@/config'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata } from '@/scripts/page-metadata'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| const { t, ts } = i18n; | const { t, ts } = i18n; | ||||||
| 
 | 
 | ||||||
| useCssModule(); | useCssModule(); | ||||||
|  | @ -170,9 +171,9 @@ function getSettings(): Profile['settings'] { | ||||||
| 	return { | 	return { | ||||||
| 		hot, | 		hot, | ||||||
| 		cold, | 		cold, | ||||||
| 		fontSize: localStorage.getItem('fontSize'), | 		fontSize: miLocalStorage.getItem('fontSize'), | ||||||
| 		useSystemFont: localStorage.getItem('useSystemFont') as 't' | null, | 		useSystemFont: miLocalStorage.getItem('useSystemFont') as 't' | null, | ||||||
| 		wallpaper: localStorage.getItem('wallpaper'), | 		wallpaper: miLocalStorage.getItem('wallpaper'), | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -279,23 +280,23 @@ async function applyProfile(id: string): Promise<void> { | ||||||
| 
 | 
 | ||||||
| 	// fontSize | 	// fontSize | ||||||
| 	if (settings.fontSize) { | 	if (settings.fontSize) { | ||||||
| 		localStorage.setItem('fontSize', settings.fontSize); | 		miLocalStorage.setItem('fontSize', settings.fontSize); | ||||||
| 	} else { | 	} else { | ||||||
| 		localStorage.removeItem('fontSize'); | 		miLocalStorage.removeItem('fontSize'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// useSystemFont | 	// useSystemFont | ||||||
| 	if (settings.useSystemFont) { | 	if (settings.useSystemFont) { | ||||||
| 		localStorage.setItem('useSystemFont', settings.useSystemFont); | 		miLocalStorage.setItem('useSystemFont', settings.useSystemFont); | ||||||
| 	} else { | 	} else { | ||||||
| 		localStorage.removeItem('useSystemFont'); | 		miLocalStorage.removeItem('useSystemFont'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// wallpaper | 	// wallpaper | ||||||
| 	if (settings.wallpaper != null) { | 	if (settings.wallpaper != null) { | ||||||
| 		localStorage.setItem('wallpaper', settings.wallpaper); | 		miLocalStorage.setItem('wallpaper', settings.wallpaper); | ||||||
| 	} else { | 	} else { | ||||||
| 		localStorage.removeItem('wallpaper'); | 		miLocalStorage.removeItem('wallpaper'); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	const { canceled: cancel2 } = await os.confirm({ | 	const { canceled: cancel2 } = await os.confirm({ | ||||||
|  |  | ||||||
|  | @ -82,6 +82,7 @@ import { instance } from '@/instance'; | ||||||
| import { uniqueBy } from '@/scripts/array'; | import { uniqueBy } from '@/scripts/array'; | ||||||
| import { fetchThemes, getThemes } from '@/theme-store'; | import { fetchThemes, getThemes } from '@/theme-store'; | ||||||
| import { definePageMetadata } from '@/scripts/page-metadata'; | import { definePageMetadata } from '@/scripts/page-metadata'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| const installedThemes = ref(getThemes()); | const installedThemes = ref(getThemes()); | ||||||
| const builtinThemes = getBuiltinThemesRef(); | const builtinThemes = getBuiltinThemesRef(); | ||||||
|  | @ -120,7 +121,7 @@ const lightThemeId = computed({ | ||||||
| }); | }); | ||||||
| const darkMode = computed(defaultStore.makeGetterSetter('darkMode')); | const darkMode = computed(defaultStore.makeGetterSetter('darkMode')); | ||||||
| const syncDeviceDarkMode = computed(ColdDeviceStorage.makeGetterSetter('syncDeviceDarkMode')); | const syncDeviceDarkMode = computed(ColdDeviceStorage.makeGetterSetter('syncDeviceDarkMode')); | ||||||
| const wallpaper = ref(localStorage.getItem('wallpaper')); | const wallpaper = ref(miLocalStorage.getItem('wallpaper')); | ||||||
| const themesCount = installedThemes.value.length; | const themesCount = installedThemes.value.length; | ||||||
| 
 | 
 | ||||||
| watch(syncDeviceDarkMode, () => { | watch(syncDeviceDarkMode, () => { | ||||||
|  | @ -131,9 +132,9 @@ watch(syncDeviceDarkMode, () => { | ||||||
| 
 | 
 | ||||||
| watch(wallpaper, () => { | watch(wallpaper, () => { | ||||||
| 	if (wallpaper.value == null) { | 	if (wallpaper.value == null) { | ||||||
| 		localStorage.removeItem('wallpaper'); | 		miLocalStorage.removeItem('wallpaper'); | ||||||
| 	} else { | 	} else { | ||||||
| 		localStorage.setItem('wallpaper', wallpaper.value); | 		miLocalStorage.setItem('wallpaper', wallpaper.value); | ||||||
| 	} | 	} | ||||||
| 	location.reload(); | 	location.reload(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| import { utils, values } from '@syuilo/aiscript'; | import { utils, values } from '@syuilo/aiscript'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
| import { $i } from '@/account'; | import { $i } from '@/account'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| export function createAiScriptEnv(opts) { | export function createAiScriptEnv(opts) { | ||||||
| 	let apiRequests = 0; | 	let apiRequests = 0; | ||||||
|  | @ -32,12 +33,12 @@ export function createAiScriptEnv(opts) { | ||||||
| 		}), | 		}), | ||||||
| 		'Mk:save': values.FN_NATIVE(([key, value]) => { | 		'Mk:save': values.FN_NATIVE(([key, value]) => { | ||||||
| 			utils.assertString(key); | 			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; | 			return values.NULL; | ||||||
| 		}), | 		}), | ||||||
| 		'Mk:load': values.FN_NATIVE(([key]) => { | 		'Mk:load': values.FN_NATIVE(([key]) => { | ||||||
| 			utils.assertString(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}`))); | ||||||
| 		}), | 		}), | ||||||
| 	}; | 	}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard'; | ||||||
| import { url } from '@/config'; | import { url } from '@/config'; | ||||||
| import { noteActions } from '@/store'; | import { noteActions } from '@/store'; | ||||||
| import { notePage } from '@/filters/note'; | import { notePage } from '@/filters/note'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| export function getNoteMenu(props: { | export function getNoteMenu(props: { | ||||||
| 	note: misskey.entities.Note; | 	note: misskey.entities.Note; | ||||||
|  | @ -181,7 +182,7 @@ export function getNoteMenu(props: { | ||||||
| 		props.translating.value = true; | 		props.translating.value = true; | ||||||
| 		const res = await os.api('notes/translate', { | 		const res = await os.api('notes/translate', { | ||||||
| 			noteId: appearNote.id, | 			noteId: appearNote.id, | ||||||
| 			targetLang: localStorage.getItem('lang') || navigator.language, | 			targetLang: miLocalStorage.getItem('lang') || navigator.language, | ||||||
| 		}); | 		}); | ||||||
| 		props.translating.value = false; | 		props.translating.value = false; | ||||||
| 		props.translation.value = res; | 		props.translation.value = res; | ||||||
|  |  | ||||||
|  | @ -22,15 +22,15 @@ if (idbAvailable) { | ||||||
| 
 | 
 | ||||||
| export async function get(key: string) { | export async function get(key: string) { | ||||||
| 	if (idbAvailable) return iget(key); | 	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) { | export async function set(key: string, val: any) { | ||||||
| 	if (idbAvailable) return iset(key, val); | 	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) { | export async function del(key: string) { | ||||||
| 	if (idbAvailable) return idel(key); | 	if (idbAvailable) return idel(key); | ||||||
| 	return localStorage.removeItem(fallbackName(key)); | 	return window.localStorage.removeItem(fallbackName(key)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -14,6 +14,7 @@ export type Theme = { | ||||||
| import lightTheme from '@/themes/_light.json5'; | import lightTheme from '@/themes/_light.json5'; | ||||||
| import darkTheme from '@/themes/_dark.json5'; | import darkTheme from '@/themes/_dark.json5'; | ||||||
| import { deepClone } from './clone'; | import { deepClone } from './clone'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| 
 | 
 | ||||||
| export const themeProps = Object.keys(lightTheme.props).filter(key => !key.startsWith('X')); | 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); | 	document.documentElement.style.setProperty('color-schema', colorSchema); | ||||||
| 
 | 
 | ||||||
| 	if (persist) { | 	if (persist) { | ||||||
| 		localStorage.setItem('theme', JSON.stringify(props)); | 		miLocalStorage.setItem('theme', JSON.stringify(props)); | ||||||
| 		localStorage.setItem('colorSchema', colorSchema); | 		miLocalStorage.setItem('colorSchema', colorSchema); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// 色計算など再度行えるようにクライアント全体に通知
 | 	// 色計算など再度行えるようにクライアント全体に通知
 | ||||||
|  |  | ||||||
|  | @ -86,6 +86,14 @@ export const defaultStore = markRaw(new Storage('base', { | ||||||
| 		where: 'account', | 		where: 'account', | ||||||
| 		default: [] as string[], | 		default: [] as string[], | ||||||
| 	}, | 	}, | ||||||
|  | 	latestDonateDialogShowAt: { | ||||||
|  | 		where: 'account', | ||||||
|  | 		default: null, | ||||||
|  | 	}, | ||||||
|  | 	neverShowDonateDialog: { | ||||||
|  | 		where: 'account', | ||||||
|  | 		default: false, | ||||||
|  | 	}, | ||||||
| 
 | 
 | ||||||
| 	menu: { | 	menu: { | ||||||
| 		where: 'deviceAccount', | 		where: 'deviceAccount', | ||||||
|  | @ -274,7 +282,7 @@ export const defaultStore = markRaw(new Storage('base', { | ||||||
| 
 | 
 | ||||||
| // TODO: 他のタブと永続化されたstateを同期
 | // TODO: 他のタブと永続化されたstateを同期
 | ||||||
| 
 | 
 | ||||||
| const PREFIX = 'miux:'; | const PREFIX = 'miux:' as const; | ||||||
| 
 | 
 | ||||||
| type Plugin = { | type Plugin = { | ||||||
| 	id: string; | 	id: string; | ||||||
|  | @ -296,6 +304,7 @@ interface Watcher { | ||||||
| import lightTheme from '@/themes/l-light.json5'; | import lightTheme from '@/themes/l-light.json5'; | ||||||
| import darkTheme from '@/themes/d-green-lime.json5'; | import darkTheme from '@/themes/d-green-lime.json5'; | ||||||
| import { Note, UserDetailed } from 'misskey-js/built/entities'; | import { Note, UserDetailed } from 'misskey-js/built/entities'; | ||||||
|  | import { miLocalStorage } from './local-storage'; | ||||||
| 
 | 
 | ||||||
| export class ColdDeviceStorage { | export class ColdDeviceStorage { | ||||||
| 	public static default = { | 	public static default = { | ||||||
|  | @ -320,7 +329,7 @@ export class ColdDeviceStorage { | ||||||
| 		// TODO: indexedDBにする
 | 		// TODO: indexedDBにする
 | ||||||
| 		//       ただしその際はnullチェックではなくキー存在チェックにしないとダメ
 | 		//       ただしその際はnullチェックではなくキー存在チェックにしないとダメ
 | ||||||
| 		//       (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
 | 		//       (indexedDBはnullを保存できるため、ユーザーが意図してnullを格納した可能性がある)
 | ||||||
| 		const value = localStorage.getItem(PREFIX + key); | 		const value = miLocalStorage.getItem(`${PREFIX}${key}`); | ||||||
| 		if (value == null) { | 		if (value == null) { | ||||||
| 			return ColdDeviceStorage.default[key]; | 			return ColdDeviceStorage.default[key]; | ||||||
| 		} else { | 		} 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 { | 	public static set<T extends keyof typeof ColdDeviceStorage.default>(key: T, value: typeof ColdDeviceStorage.default[T]): void { | ||||||
| 		// 呼び出し側のバグ等で undefined が来ることがある
 | 		// 呼び出し側のバグ等で undefined が来ることがある
 | ||||||
| 		// undefined を文字列として localStorage に入れると参照する際の JSON.parse でコケて不具合の元になるため無視
 | 		// undefined を文字列として miLocalStorage に入れると参照する際の JSON.parse でコケて不具合の元になるため無視
 | ||||||
| 		// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | 		// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
 | ||||||
| 		if (value === undefined) { | 		if (value === undefined) { | ||||||
| 			console.error(`attempt to store undefined value for key '${key}'`); | 			console.error(`attempt to store undefined value for key '${key}'`); | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		localStorage.setItem(PREFIX + key, JSON.stringify(value)); | 		miLocalStorage.setItem(`${PREFIX}${key}`, JSON.stringify(value)); | ||||||
| 
 | 
 | ||||||
| 		for (const watcher of this.watchers) { | 		for (const watcher of this.watchers) { | ||||||
| 			if (watcher.key === key) watcher.callback(value); | 			if (watcher.key === key) watcher.callback(value); | ||||||
|  |  | ||||||
|  | @ -1,11 +1,13 @@ | ||||||
| import { api } from '@/os'; | import { api } from '@/os'; | ||||||
| import { $i } from '@/account'; | import { $i } from '@/account'; | ||||||
| import { Theme } from './scripts/theme'; | 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[] { | 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> { | export async function fetchThemes(): Promise<void> { | ||||||
|  | @ -13,7 +15,7 @@ export async function fetchThemes(): Promise<void> { | ||||||
| 
 | 
 | ||||||
| 	try { | 	try { | ||||||
| 		const themes = await api('i/registry/get', { scope: ['client'], key: 'themes' }); | 		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) { | 	} catch (err) { | ||||||
| 		if (err.code === 'NO_SUCH_KEY') return; | 		if (err.code === 'NO_SUCH_KEY') return; | ||||||
| 		throw err; | 		throw err; | ||||||
|  | @ -21,14 +23,16 @@ export async function fetchThemes(): Promise<void> { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function addTheme(theme: Theme): Promise<void> { | export async function addTheme(theme: Theme): Promise<void> { | ||||||
|  | 	if ($i == null) return; | ||||||
| 	await fetchThemes(); | 	await fetchThemes(); | ||||||
| 	const themes = getThemes().concat(theme); | 	const themes = getThemes().concat(theme); | ||||||
| 	await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); | 	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> { | export async function removeTheme(theme: Theme): Promise<void> { | ||||||
|  | 	if ($i == null) return; | ||||||
| 	const themes = getThemes().filter(t => t.id !== theme.id); | 	const themes = getThemes().filter(t => t.id !== theme.id); | ||||||
| 	await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); | 	await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); | ||||||
| 	localStorage.setItem(lsCacheKey, JSON.stringify(themes)); | 	miLocalStorage.setItem(lsCacheKey!, JSON.stringify(themes)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -51,6 +51,7 @@ import { mainRouter } from '@/router'; | ||||||
| import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | ||||||
| import { defaultStore } from '@/store'; | import { defaultStore } from '@/store'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| const XHeaderMenu = defineAsyncComponent(() => import('./classic.header.vue')); | const XHeaderMenu = defineAsyncComponent(() => import('./classic.header.vue')); | ||||||
| const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); | const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); | ||||||
| 
 | 
 | ||||||
|  | @ -62,7 +63,7 @@ let pageMetadata = $ref<null | ComputedRef<PageMetadata>>(); | ||||||
| let widgetsShowing = $ref(false); | let widgetsShowing = $ref(false); | ||||||
| let fullView = $ref(false); | let fullView = $ref(false); | ||||||
| let globalHeaderHeight = $ref(0); | let globalHeaderHeight = $ref(0); | ||||||
| const wallpaper = localStorage.getItem('wallpaper') != null; | const wallpaper = miLocalStorage.getItem('wallpaper') != null; | ||||||
| const showMenuOnTop = $computed(() => defaultStore.state.menuDisplay === 'top'); | const showMenuOnTop = $computed(() => defaultStore.state.menuDisplay === 'top'); | ||||||
| let live2d = $shallowRef<HTMLIFrameElement>(); | let live2d = $shallowRef<HTMLIFrameElement>(); | ||||||
| let widgetsLeft = $ref(); | let widgetsLeft = $ref(); | ||||||
|  | @ -123,7 +124,7 @@ function onAiClick(ev) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| if (window.innerWidth < 1024) { | if (window.innerWidth < 1024) { | ||||||
| 	localStorage.setItem('ui', 'default'); | 	miLocalStorage.setItem('ui', 'default'); | ||||||
| 	location.reload(); | 	location.reload(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -71,6 +71,7 @@ import { Router } from '@/nirax'; | ||||||
| import { mainRouter } from '@/router'; | import { mainRouter } from '@/router'; | ||||||
| import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | import { PageMetadata, provideMetadataReceiver, setPageMetadata } from '@/scripts/page-metadata'; | ||||||
| import { deviceKind } from '@/scripts/device-kind'; | import { deviceKind } from '@/scripts/device-kind'; | ||||||
|  | import { miLocalStorage } from '@/local-storage'; | ||||||
| const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); | const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); | ||||||
| const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); | const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/navbar.vue')); | ||||||
| const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); | const XStatusBars = defineAsyncComponent(() => import('@/ui/_common_/statusbars.vue')); | ||||||
|  | @ -170,7 +171,7 @@ function top() { | ||||||
| 	window.scroll({ top: 0, behavior: 'smooth' }); | 	window.scroll({ top: 0, behavior: 'smooth' }); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const wallpaper = localStorage.getItem('wallpaper') != null; | const wallpaper = miLocalStorage.getItem('wallpaper') != null; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue