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…
Reference in a new issue