feat: wire app store with appearance actions and CSS variable application
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
import type { AppSettings } from "@/types/settings";
|
import type { AppSettings } from "@/types/settings";
|
||||||
import type { BoardMeta } from "@/types/board";
|
import type { BoardMeta, ColumnWidth } from "@/types/board";
|
||||||
import { loadSettings, saveSettings, listBoards, ensureDataDirs } from "@/lib/storage";
|
import { loadSettings, saveSettings, listBoards, ensureDataDirs } from "@/lib/storage";
|
||||||
|
|
||||||
export type View = { type: "board-list" } | { type: "board"; boardId: string };
|
export type View = { type: "board-list" } | { type: "board"; boardId: string };
|
||||||
@@ -13,6 +13,10 @@ interface AppState {
|
|||||||
|
|
||||||
init: () => Promise<void>;
|
init: () => Promise<void>;
|
||||||
setTheme: (theme: AppSettings["theme"]) => void;
|
setTheme: (theme: AppSettings["theme"]) => void;
|
||||||
|
setAccentColor: (hue: string) => void;
|
||||||
|
setUiZoom: (zoom: number) => void;
|
||||||
|
setDensity: (density: AppSettings["density"]) => void;
|
||||||
|
setDefaultColumnWidth: (width: ColumnWidth) => void;
|
||||||
setView: (view: View) => void;
|
setView: (view: View) => void;
|
||||||
refreshBoards: () => Promise<void>;
|
refreshBoards: () => Promise<void>;
|
||||||
addRecentBoard: (boardId: string) => void;
|
addRecentBoard: (boardId: string) => void;
|
||||||
@@ -28,8 +32,37 @@ function applyTheme(theme: AppSettings["theme"]): void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applyAppearance(settings: AppSettings): void {
|
||||||
|
const root = document.documentElement;
|
||||||
|
root.style.fontSize = `${settings.uiZoom * 16}px`;
|
||||||
|
const hue = settings.accentColor;
|
||||||
|
const isDark = root.classList.contains("dark");
|
||||||
|
const lightness = isDark ? "60%" : "55%";
|
||||||
|
root.style.setProperty("--pylon-accent", `oklch(${lightness} 0.12 ${hue})`);
|
||||||
|
const densityMap = { compact: "0.75", comfortable: "1", spacious: "1.25" };
|
||||||
|
root.style.setProperty("--density-factor", densityMap[settings.density]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateAndSave(
|
||||||
|
get: () => AppState,
|
||||||
|
set: (partial: Partial<AppState>) => void,
|
||||||
|
patch: Partial<AppSettings>
|
||||||
|
): void {
|
||||||
|
const settings = { ...get().settings, ...patch };
|
||||||
|
set({ settings });
|
||||||
|
saveSettings(settings);
|
||||||
|
}
|
||||||
|
|
||||||
export const useAppStore = create<AppState>((set, get) => ({
|
export const useAppStore = create<AppState>((set, get) => ({
|
||||||
settings: { theme: "system", dataDirectory: null, recentBoardIds: [] },
|
settings: {
|
||||||
|
theme: "system",
|
||||||
|
dataDirectory: null,
|
||||||
|
recentBoardIds: [],
|
||||||
|
accentColor: "160",
|
||||||
|
uiZoom: 1,
|
||||||
|
density: "comfortable",
|
||||||
|
defaultColumnWidth: "standard",
|
||||||
|
},
|
||||||
boards: [],
|
boards: [],
|
||||||
view: { type: "board-list" },
|
view: { type: "board-list" },
|
||||||
initialized: false,
|
initialized: false,
|
||||||
@@ -40,13 +73,32 @@ export const useAppStore = create<AppState>((set, get) => ({
|
|||||||
const boards = await listBoards();
|
const boards = await listBoards();
|
||||||
set({ settings, boards, initialized: true });
|
set({ settings, boards, initialized: true });
|
||||||
applyTheme(settings.theme);
|
applyTheme(settings.theme);
|
||||||
|
applyAppearance(settings);
|
||||||
},
|
},
|
||||||
|
|
||||||
setTheme: (theme) => {
|
setTheme: (theme) => {
|
||||||
const settings = { ...get().settings, theme };
|
updateAndSave(get, set, { theme });
|
||||||
set({ settings });
|
|
||||||
saveSettings(settings);
|
|
||||||
applyTheme(theme);
|
applyTheme(theme);
|
||||||
|
applyAppearance({ ...get().settings, theme });
|
||||||
|
},
|
||||||
|
|
||||||
|
setAccentColor: (accentColor) => {
|
||||||
|
updateAndSave(get, set, { accentColor });
|
||||||
|
applyAppearance(get().settings);
|
||||||
|
},
|
||||||
|
|
||||||
|
setUiZoom: (uiZoom) => {
|
||||||
|
updateAndSave(get, set, { uiZoom });
|
||||||
|
applyAppearance(get().settings);
|
||||||
|
},
|
||||||
|
|
||||||
|
setDensity: (density) => {
|
||||||
|
updateAndSave(get, set, { density });
|
||||||
|
applyAppearance(get().settings);
|
||||||
|
},
|
||||||
|
|
||||||
|
setDefaultColumnWidth: (defaultColumnWidth) => {
|
||||||
|
updateAndSave(get, set, { defaultColumnWidth });
|
||||||
},
|
},
|
||||||
|
|
||||||
setView: (view) => set({ view }),
|
setView: (view) => set({ view }),
|
||||||
@@ -62,8 +114,6 @@ export const useAppStore = create<AppState>((set, get) => ({
|
|||||||
boardId,
|
boardId,
|
||||||
...settings.recentBoardIds.filter((id) => id !== boardId),
|
...settings.recentBoardIds.filter((id) => id !== boardId),
|
||||||
].slice(0, 10);
|
].slice(0, 10);
|
||||||
const updated = { ...settings, recentBoardIds: recent };
|
updateAndSave(get, set, { recentBoardIds: recent });
|
||||||
set({ settings: updated });
|
|
||||||
saveSettings(updated);
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user