diff --git a/apps/spotter/src/plugins/themes.plugin.ts b/apps/spotter/src/plugins/themes.plugin.ts index d88f850c..33eed96a 100644 --- a/apps/spotter/src/plugins/themes.plugin.ts +++ b/apps/spotter/src/plugins/themes.plugin.ts @@ -1,6 +1,12 @@ import { SpotterPlugin } from "@spotter-app/core"; -const THEMES = [ +interface Theme { + title: string, + value: string, + userTheme?: boolean, +} + +const THEMES: Theme[] = [ { title: 'Dark', value: '#212121,#ffffff,#3c3c3c,#ffffff,#0f60cf,#fefefe', @@ -15,6 +21,8 @@ const THEMES = [ }, ]; +const hexRegExp = /^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/; + export class SpotterThemesPlugin extends SpotterPlugin { async onInit() { @@ -24,13 +32,33 @@ export class SpotterThemesPlugin extends SpotterPlugin { prefix: 'thm', onQuery: async (q: string) => { const settings = await this.spotter.getSettings(); - const themes = THEMES.map(theme => { + const storage = await this.spotter.getStorage<{themes: Theme[]}>(); + + const themes = [ + ...THEMES, + ...(storage.themes ?? []).map(t => ({...t, userTheme: true})), + ].map(theme => { const active = settings.theme === theme.value; return { title: `${theme.title} ${active ? '- active' : ''}`, hovered: active, onHover: () => this.spotter.setTheme(theme.value), onSubmit: () => this.spotter.patchSettings({theme: theme.value}), + ...(theme.userTheme ? {onQuery: (q: string) => { + return [{ + title: 'Remove', + onSubmit: () => { + if (active) { + this.spotter.setTheme(THEMES[0].value) + this.spotter.patchSettings({theme: THEMES[0].value}) + } + + this.spotter.patchStorage({ + themes: (storage.themes ?? []).filter(t => t.value !== theme.value), + }); + } + }]; + }} : {}) } }); @@ -38,6 +66,43 @@ export class SpotterThemesPlugin extends SpotterPlugin { return themes; } + if (q.startsWith('#')) { + const colors = q.split(','); + const validTheme = colors.length === 6 && colors.every(c => hexRegExp.test(c)); + + if (!validTheme) { + return [{ + title: 'Invalid theme', + }]; + } + + const theme = q; + this.spotter.setTheme(theme); + return [{ + title: 'Save theme as', + onQuery: (q: string) => { + this.spotter.setPlaceholder('Theme name'); + if (!q.length) { + return []; + } + return [{ + title: 'Save', + onSubmit: async () => { + const storage = await this.spotter.getStorage<{themes: Theme[]}>(); + this.spotter.patchStorage({ + themes: [ + ...(storage.themes ?? []), + { title: q, value: theme }, + ], + }); + this.spotter.patchSettings({ theme }); + return true; + } + }] + }, + }]; + } + const lowercasedQuery = q.toLowerCase(); return themes.filter(t => t.title.toLowerCase().startsWith(lowercasedQuery)); },