テーマをレジストリに保存するように

This commit is contained in:
syuilo 2021-01-11 22:31:17 +09:00
parent 20e67e7edd
commit 114a9fbdb2
6 changed files with 78 additions and 12 deletions

View file

@ -56,6 +56,7 @@ import { defaultStore, ColdDeviceStorage } from '@/store';
import { fetchInstance, instance } from '@/instance'; import { fetchInstance, instance } from '@/instance';
import { makeHotkey } from './scripts/hotkey'; import { makeHotkey } from './scripts/hotkey';
import { search } from './scripts/search'; import { search } from './scripts/search';
import { getThemes } from './theme-store';
console.info(`Misskey v${version}`); console.info(`Misskey v${version}`);
@ -211,7 +212,7 @@ app.mount('body');
watch(defaultStore.reactiveState.darkMode, (darkMode) => { watch(defaultStore.reactiveState.darkMode, (darkMode) => {
import('@/scripts/theme').then(({ builtinThemes }) => { import('@/scripts/theme').then(({ builtinThemes }) => {
const themes = builtinThemes.concat(ColdDeviceStorage.get('themes')); const themes = builtinThemes.concat(getThemes());
applyTheme(themes.find(x => x.id === (darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')))); applyTheme(themes.find(x => x.id === (darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme'))));
}); });
}, { immediate: localStorage.theme == null }); }, { immediate: localStorage.theme == null });

View file

@ -25,6 +25,7 @@ import FormButton from '@/components/form/button.vue';
import { applyTheme, validateTheme } from '@/scripts/theme'; import { applyTheme, validateTheme } from '@/scripts/theme';
import * as os from '@/os'; import * as os from '@/os';
import { ColdDeviceStorage } from '@/store'; import { ColdDeviceStorage } from '@/store';
import { addTheme, getThemes } from '@/theme-store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -74,7 +75,7 @@ export default defineComponent({
}); });
return false; return false;
} }
if (ColdDeviceStorage.get('themes').some(t => t.id === theme.id)) { if (getThemes().some(t => t.id === theme.id)) {
os.dialog({ os.dialog({
type: 'info', type: 'info',
text: this.$ts._theme.alreadyInstalled text: this.$ts._theme.alreadyInstalled
@ -90,11 +91,10 @@ export default defineComponent({
if (theme) applyTheme(theme, false); if (theme) applyTheme(theme, false);
}, },
install(code) { async install(code) {
const theme = this.parseThemeCode(code); const theme = this.parseThemeCode(code);
if (!theme) return; if (!theme) return;
const themes = ColdDeviceStorage.get('themes').concat(theme); await addTheme(theme);
ColdDeviceStorage.set('themes', themes);
os.dialog({ os.dialog({
type: 'success', type: 'success',
text: this.$t('_theme.installed', { name: theme.name }) text: this.$t('_theme.installed', { name: theme.name })

View file

@ -37,6 +37,7 @@ import { Theme, builtinThemes } from '@/scripts/theme';
import copyToClipboard from '@/scripts/copy-to-clipboard'; import copyToClipboard from '@/scripts/copy-to-clipboard';
import * as os from '@/os'; import * as os from '@/os';
import { ColdDeviceStorage } from '@/store'; import { ColdDeviceStorage } from '@/store';
import { getThemes, removeTheme } from '@/theme-store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -57,7 +58,7 @@ export default defineComponent({
title: this.$ts._theme.manage, title: this.$ts._theme.manage,
icon: faFolderOpen icon: faFolderOpen
}, },
installedThemes: ColdDeviceStorage.ref('themes'), installedThemes: getThemes(),
builtinThemes, builtinThemes,
selectedThemeId: null, selectedThemeId: null,
faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye
@ -91,10 +92,7 @@ export default defineComponent({
}, },
uninstall() { uninstall() {
const theme = this.selectedTheme; removeTheme(this.selectedTheme);
const themes = ColdDeviceStorage.get('themes').filter(t => t.id != theme.id);
ColdDeviceStorage.set('themes', themes);
os.success();
}, },
} }
}); });

View file

@ -77,6 +77,7 @@ import { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
import { ColdDeviceStorage } from '@/store'; import { ColdDeviceStorage } from '@/store';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { fetchThemes, getThemes } from '@/theme-store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -96,7 +97,7 @@ export default defineComponent({
icon: faPalette icon: faPalette
}; };
const installedThemes = ColdDeviceStorage.ref('themes'); const installedThemes = ref(getThemes());
const themes = computed(() => builtinThemes.concat(installedThemes.value)); const themes = computed(() => builtinThemes.concat(installedThemes.value));
const darkThemes = computed(() => themes.value.filter(t => t.base == 'dark' || t.kind == 'dark')); const darkThemes = computed(() => themes.value.filter(t => t.base == 'dark' || t.kind == 'dark'));
const lightThemes = computed(() => themes.value.filter(t => t.base == 'light' || t.kind == 'light')); const lightThemes = computed(() => themes.value.filter(t => t.base == 'light' || t.kind == 'light'));
@ -137,6 +138,10 @@ export default defineComponent({
emit('info', INFO); emit('info', INFO);
}); });
fetchThemes().then(() => {
installedThemes.value = getThemes();
});
return { return {
INFO, INFO,
darkThemes, darkThemes,

View file

@ -208,7 +208,7 @@ type Plugin = {
*/ */
export class ColdDeviceStorage { export class ColdDeviceStorage {
public static default = { public static default = {
themes: [] as Theme[], themes: [] as Theme[], // TODO: そのうち消す
darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677', darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677',
lightTheme: '4eea646f-7afa-4645-83e9-83af0333cd37', lightTheme: '4eea646f-7afa-4645-83e9-83af0333cd37',
syncDeviceDarkMode: true, syncDeviceDarkMode: true,

62
src/client/theme-store.ts Normal file
View file

@ -0,0 +1,62 @@
import { api } from '@/os';
import { $i } from '@/account';
import { ColdDeviceStorage } from './store';
import { Theme } from './scripts/theme';
const lsCacheKey = $i ? `themes:${$i.id}` : '';
export function getThemes(): Theme[] {
return JSON.parse(localStorage.getItem(lsCacheKey) || '[]');
}
export async function fetchThemes(): Promise<void> {
if ($i == null) return;
try {
const themes = await api('i/registry/get', { scope: ['client'], key: 'themes' });
localStorage.setItem(lsCacheKey, JSON.stringify(themes));
} catch (e) {
if (e.code === 'NO_SUCH_KEY') return;
throw e;
}
}
export async function addTheme(theme: Theme): Promise<void> {
await fetchThemes();
const themes = getThemes().concat(theme);
await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes });
localStorage.setItem(lsCacheKey, JSON.stringify(themes));
}
export async function removeTheme(theme: Theme): Promise<void> {
const themes = getThemes().filter(t => t.id != theme.id);
await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes });
localStorage.setItem(lsCacheKey, JSON.stringify(themes));
}
// TODO: そのうち消す
if (ColdDeviceStorage.get('themes').length > 0) {
const lsThemes = ColdDeviceStorage.get('themes');
let registryThemes;
try {
registryThemes = await api('i/registry/get', { scope: ['client'], key: 'themes' });
} catch (e) {
if (e.code === 'NO_SUCH_KEY') {
registryThemes = [];
} else {
throw e;
}
}
const themes = [] as Theme[];
for (const theme of lsThemes) {
if (themes.some(x => x.id === theme.id)) continue;
themes.push(theme);
}
for (const theme of registryThemes) {
if (themes.some(x => x.id === theme.id)) continue;
themes.push(theme);
}
await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes });
localStorage.setItem(lsCacheKey, JSON.stringify(themes));
ColdDeviceStorage.set('themes', []);
}