@hadoku/themes 5.13.8 → 5.13.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -69,6 +69,7 @@ export type { ThemeName, ThemeFamily } from './theme-types';
69
69
  export type { HadokuThemeRootProps } from './HadokuThemeRoot';
70
70
  export { themePrefs, ThemePrefsSchema } from './themePrefs';
71
71
  export type { ThemePrefs } from './themePrefs';
72
+ export { useSettingsTab } from './settingsTab';
72
73
  export { resolvePrefsApiBase, PREFS_API_BASE_GLOBAL } from './prefsApiBase';
73
74
  export { THEME_EFFECTS, hasAdvanced, getThemeEffects } from './effects';
74
75
  export type { AdvancedEffect, ThemeEffectMap } from './effects';
package/dist/index.js CHANGED
@@ -151,6 +151,8 @@ export { HadokuThemeProvider, useHadokuTheme, useHadokuThemeOptional } from './t
151
151
  export { SunIcon, MoonIcon, StrawberryIcon, WaveIcon, ZapIcon, CoffeeIcon, FlowerIcon, HeartIcon, LeafIcon, LanternIcon } from './ThemeIcons.js';
152
152
  // Canonical theme prefs client — was copy-pasted into every child app.
153
153
  export { themePrefs, ThemePrefsSchema } from './themePrefs.js';
154
+ // The settings popout's remembered tab, on the same shared row.
155
+ export { useSettingsTab } from './settingsTab.js';
154
156
  // Shared by every prefs client in the ecosystem, so a dev/E2E stack can point
155
157
  // them all at a local prefs-api with one global instead of mocking the network.
156
158
  export { resolvePrefsApiBase, PREFS_API_BASE_GLOBAL } from './prefsApiBase.js';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * `[savedTabId, saveTabId]` for the current app. The saved id may name a tab
3
+ * the app no longer offers; the caller falls back to its default then.
4
+ */
5
+ export declare function useSettingsTab(): [string | null, (id: string) => void];
@@ -0,0 +1,51 @@
1
+ /**
2
+ * The settings popout's remembered tab, per user and per app.
3
+ *
4
+ * Stored on the shared 'portfolio' row (themePrefs) under `settingsTabs`, keyed
5
+ * by the app's path prefix, so cardtable's "Sound" and the task app's "App"
6
+ * don't overwrite each other. User scope: the tab follows the person, not the
7
+ * device.
8
+ *
9
+ * Read through a subscription taken when this module evaluates, never through
10
+ * `themePrefs.read()`: every read() with a cached blob kicks a background GET,
11
+ * and the theme hook has already issued the boot read. Subscribing first means
12
+ * this sees the cache hydrate and that read's result without asking again.
13
+ */
14
+ import { useCallback, useSyncExternalStore } from 'react';
15
+ import { themePrefs } from './themePrefs.js';
16
+ let tabs = {};
17
+ const listeners = new Set();
18
+ themePrefs.subscribe((next) => {
19
+ tabs = next.settingsTabs ?? {};
20
+ for (const l of listeners)
21
+ l();
22
+ });
23
+ function subscribe(listener) {
24
+ listeners.add(listener);
25
+ return () => {
26
+ listeners.delete(listener);
27
+ };
28
+ }
29
+ const getTabs = () => tabs;
30
+ /** The app this page belongs to: its first path segment ('' at the site root). */
31
+ function appScope() {
32
+ if (typeof window === 'undefined')
33
+ return '';
34
+ return window.location.pathname.split('/')[1] ?? '';
35
+ }
36
+ /**
37
+ * `[savedTabId, saveTabId]` for the current app. The saved id may name a tab
38
+ * the app no longer offers; the caller falls back to its default then.
39
+ */
40
+ export function useSettingsTab() {
41
+ const all = useSyncExternalStore(subscribe, getTabs, getTabs);
42
+ const scope = appScope();
43
+ const save = useCallback((id) => {
44
+ themePrefs
45
+ .save({ settingsTabs: { ...tabs, [scope]: id } }, { scope: 'user' })
46
+ .catch((err) => {
47
+ console.error('[useSettingsTab] prefs save failed', err?.message ?? err);
48
+ });
49
+ }, [scope]);
50
+ return [all[scope] ?? null, save];
51
+ }
@@ -21,9 +21,11 @@ export declare const ThemePrefsSchema: z.ZodObject<{
21
21
  simple: "simple";
22
22
  advanced: "advanced";
23
23
  }>>;
24
+ settingsTabs: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
24
25
  }, z.core.$strip>;
25
26
  export type ThemePrefs = z.infer<typeof ThemePrefsSchema>;
26
27
  export declare const themePrefs: import("@wolffm/prefs-client").PrefsClient<{
27
28
  theme?: string | undefined;
28
29
  themeMode?: "simple" | "advanced" | undefined;
30
+ settingsTabs?: Record<string, string> | undefined;
29
31
  }>;
@@ -29,7 +29,11 @@ import { resolvePrefsApiBase } from './prefsApiBase.js';
29
29
  z.config({ jitless: true });
30
30
  export const ThemePrefsSchema = z.object({
31
31
  theme: z.string().optional(),
32
- themeMode: z.enum(['simple', 'advanced']).optional()
32
+ themeMode: z.enum(['simple', 'advanced']).optional(),
33
+ // The settings popout's last-open tab, keyed by app (see ./settingsTab). The
34
+ // popout is platform UI, not an app's, so it shares this row — which the
35
+ // theme has already read at boot, so remembering the tab costs no request.
36
+ settingsTabs: z.record(z.string(), z.string()).optional()
33
37
  });
34
38
  export const themePrefs = createPrefsClient({
35
39
  appId: 'portfolio',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hadoku/themes",
3
- "version": "5.13.8",
3
+ "version": "5.13.10",
4
4
  "description": "18 beautiful themes with a symmetric, WCAG-verified token set and a complete Tailwind v4 color mapping - Light, Dark, Strawberry, Ocean, Cyberpunk, Coffee, Lavender, Nature, Pink, Izakaya",
5
5
  "type": "module",
6
6
  "repository": {