chore(repo): initialize planarchy workspace
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
"use client";
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export type HeatmapColorScheme = "green-red" | "blue-orange" | "purple-yellow" | "mono";
|
||||
|
||||
export interface AppPreferences {
|
||||
/** Hide allocations that belong to COMPLETED or CANCELLED projects. Default: true. */
|
||||
hideCompletedProjects: boolean;
|
||||
/**
|
||||
* Timeline row rendering style.
|
||||
* "strip" — horizontal colored blocks per allocation (classic Gantt) + load graph
|
||||
* "bar" — stacked vertical bars per day showing hours by project
|
||||
* "heatmap" — strips overlaid with a green→red utilization colour per day column
|
||||
*/
|
||||
timelineDisplayMode: "strip" | "bar" | "heatmap";
|
||||
/** Color palette used for heatmap overlays and bar-mode project view bars. */
|
||||
heatmapColorScheme: HeatmapColorScheme;
|
||||
}
|
||||
|
||||
const STORAGE_KEY = "planarchy_prefs";
|
||||
const CHANGE_EVENT = "planarchy-prefs-changed";
|
||||
|
||||
const DEFAULT: AppPreferences = {
|
||||
hideCompletedProjects: true,
|
||||
timelineDisplayMode: "strip",
|
||||
heatmapColorScheme: "green-red",
|
||||
};
|
||||
|
||||
export function readAppPreferences(): AppPreferences {
|
||||
if (typeof window === "undefined") return DEFAULT;
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return DEFAULT;
|
||||
return { ...DEFAULT, ...(JSON.parse(raw) as Partial<AppPreferences>) };
|
||||
} catch {
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
function saveAppPreferences(prefs: AppPreferences) {
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(prefs));
|
||||
// Broadcast to all hook instances in the same tab
|
||||
window.dispatchEvent(new CustomEvent<AppPreferences>(CHANGE_EVENT, { detail: prefs }));
|
||||
}
|
||||
|
||||
export function useAppPreferences() {
|
||||
const [prefs, setPrefs] = useState<AppPreferences>(DEFAULT);
|
||||
|
||||
useEffect(() => {
|
||||
// Sync from storage on mount
|
||||
setPrefs(readAppPreferences());
|
||||
|
||||
// Keep in sync when any hook instance saves a change
|
||||
function handleChange(e: Event) {
|
||||
setPrefs((e as CustomEvent<AppPreferences>).detail);
|
||||
}
|
||||
window.addEventListener(CHANGE_EVENT, handleChange);
|
||||
return () => window.removeEventListener(CHANGE_EVENT, handleChange);
|
||||
}, []);
|
||||
|
||||
const setHideCompletedProjects = useCallback((value: boolean) => {
|
||||
setPrefs((prev) => {
|
||||
const next = { ...prev, hideCompletedProjects: value };
|
||||
saveAppPreferences(next);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setTimelineDisplayMode = useCallback((value: AppPreferences["timelineDisplayMode"]) => {
|
||||
setPrefs((prev) => {
|
||||
const next = { ...prev, timelineDisplayMode: value };
|
||||
saveAppPreferences(next);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setHeatmapColorScheme = useCallback((value: HeatmapColorScheme) => {
|
||||
setPrefs((prev) => {
|
||||
const next = { ...prev, heatmapColorScheme: value };
|
||||
saveAppPreferences(next);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
|
||||
return { prefs, setHideCompletedProjects, setTimelineDisplayMode, setHeatmapColorScheme };
|
||||
}
|
||||
Reference in New Issue
Block a user