1import { writable } from 'svelte/store';
2import { defaultTheme, type Theme } from './theme';
3
4export type ApiEndpoints = Record<string, string> & {
5 slingshot: string;
6 spacedust: string;
7 constellation: string;
8 jetstream: string;
9};
10export type Settings = {
11 endpoints: ApiEndpoints;
12 theme: Theme;
13 socialAppUrl: string;
14};
15
16export const defaultSettings: Settings = {
17 endpoints: {
18 slingshot: 'https://slingshot.microcosm.blue',
19 spacedust: 'https://spacedust.microcosm.blue',
20 constellation: 'https://constellation.microcosm.blue',
21 jetstream: 'wss://jetstream2.fr.hose.cam'
22 },
23 theme: defaultTheme,
24 socialAppUrl: 'https://bsky.app'
25};
26
27const createSettingsStore = () => {
28 // Prevent SSR crash if localStorage is missing
29 const stored = typeof localStorage !== 'undefined' ? localStorage.getItem('settings') : null;
30
31 const initial: Partial<Settings> = stored ? JSON.parse(stored) : defaultSettings;
32 initial.endpoints = { ...defaultSettings.endpoints, ...initial.endpoints };
33 initial.theme = { ...defaultSettings.theme, ...initial.theme };
34 initial.socialAppUrl = initial.socialAppUrl ?? defaultSettings.socialAppUrl;
35
36 const { subscribe, set, update } = writable<Settings>(initial as Settings);
37
38 subscribe((settings) => {
39 if (typeof document === 'undefined') return;
40 const theme = settings.theme;
41 document.documentElement.style.setProperty('--nucleus-bg', theme.bg);
42 document.documentElement.style.setProperty('--nucleus-fg', theme.fg);
43 document.documentElement.style.setProperty('--nucleus-accent', theme.accent);
44 document.documentElement.style.setProperty('--nucleus-accent2', theme.accent2);
45
46 const oldMeta = document.querySelector('meta[name="theme-color"]');
47 if (oldMeta) oldMeta.remove();
48
49 const metaThemeColor = document.createElement('meta');
50 metaThemeColor.setAttribute('name', 'theme-color');
51 metaThemeColor.setAttribute('content', theme.bg);
52 document.head.appendChild(metaThemeColor);
53 });
54
55 return {
56 subscribe,
57 set: (value: Settings) => {
58 if (typeof localStorage !== 'undefined')
59 localStorage.setItem('settings', JSON.stringify(value));
60 set(value);
61 },
62 update: (fn: (value: Settings) => Settings) => {
63 update((value) => {
64 const newValue = fn(value);
65 if (typeof localStorage !== 'undefined')
66 localStorage.setItem('settings', JSON.stringify(newValue));
67 return newValue;
68 });
69 },
70 reset: () => {
71 if (typeof localStorage !== 'undefined')
72 localStorage.setItem('settings', JSON.stringify(defaultSettings));
73 set(defaultSettings);
74 }
75 };
76};
77
78export const settings = createSettingsStore();
79
80export const needsReload = (current: Settings, other: Settings): boolean => {
81 return (
82 current.endpoints.slingshot !== other.endpoints.slingshot ||
83 current.endpoints.spacedust !== other.endpoints.spacedust ||
84 current.endpoints.constellation !== other.endpoints.constellation ||
85 current.endpoints.jetstream !== other.endpoints.jetstream
86 );
87};