Files
openchamber/packages/ui/src/stores/useSessionDisplayStore.ts
T

81 lines
3.2 KiB
TypeScript
Raw Normal View History

import { create } from 'zustand';
import { persist } from 'zustand/middleware';
type ProjectSortOrder = 'manual' | 'a-z' | 'z-a' | 'date-added' | 'recent';
// 'by-worktree' keeps per-worktree sub-headers inside each project zone
// (parallel-work overview); 'flat' merges everything into one recency list.
type SessionGroupingMode = 'by-worktree' | 'flat';
type SessionDisplayStore = {
sessionGroupingMode: SessionGroupingMode;
setSessionGroupingMode: (mode: SessionGroupingMode) => void;
/** Project/recent zone headers stick to the top while their zone scrolls. */
stickyZoneHeaders: boolean;
toggleStickyZoneHeaders: () => void;
2026-05-03 16:32:14 +03:00
showRecentSection: boolean;
// VS Code only: the compact webview keeps archived buckets inline because it
// has no room for the full Archive page. Web/desktop ignore this flag and
// always route archived sessions to the Archive page instead.
showArchivedSessions: boolean;
projectSortOrder: ProjectSortOrder;
2026-05-03 16:32:14 +03:00
setShowRecentSection: (show: boolean) => void;
setShowArchivedSessions: (show: boolean) => void;
2026-05-03 16:32:14 +03:00
toggleRecentSection: () => void;
toggleArchivedSessions: () => void;
setProjectSortOrder: (order: ProjectSortOrder) => void;
};
2026-07-21 22:59:42 +03:00
export const migrateSessionDisplayState = (
persisted: unknown,
version: number,
): Partial<SessionDisplayStore> => {
const state = (persisted ?? {}) as Partial<SessionDisplayStore> & {
displayMode?: string;
};
2026-07-21 22:59:42 +03:00
if (version < 2) {
state.projectSortOrder = 'manual';
2026-07-21 22:59:42 +03:00
}
if (version < 3 && state.projectSortOrder === 'recent') {
state.projectSortOrder = 'manual';
}
if (version < 4) {
// v4 removes the default/minimal display mode: the sidebar now has a
// single row layout. Drop the stale key from persisted state.
delete state.displayMode;
2026-07-21 22:59:42 +03:00
}
return state;
};
export const useSessionDisplayStore = create<SessionDisplayStore>()(
persist(
(set) => ({
sessionGroupingMode: 'by-worktree',
setSessionGroupingMode: (mode) => set({ sessionGroupingMode: mode }),
stickyZoneHeaders: true,
toggleStickyZoneHeaders: () => set((state) => ({ stickyZoneHeaders: !state.stickyZoneHeaders })),
2026-05-03 16:32:14 +03:00
showRecentSection: true,
// Default to HIDDEN so the pre-hydration state matches the quiet/safe
// option: archived sessions must never flash visible on startup and then
// disappear once the persisted preference rehydrates.
showArchivedSessions: false,
2026-07-21 22:59:42 +03:00
projectSortOrder: 'manual',
2026-05-03 16:32:14 +03:00
setShowRecentSection: (show) => set({ showRecentSection: show }),
setShowArchivedSessions: (show) => set({ showArchivedSessions: show }),
2026-05-03 16:32:14 +03:00
toggleRecentSection: () => set((state) => ({ showRecentSection: !state.showRecentSection })),
toggleArchivedSessions: () => set((state) => ({ showArchivedSessions: !state.showArchivedSessions })),
setProjectSortOrder: (order) => set({ projectSortOrder: order }),
}),
{
name: 'session-display-mode',
version: 4,
2026-07-21 22:59:42 +03:00
// v1→v2 adds projectSortOrder using the canonical manual ordering.
// v2→v3 replaces the previously shipped recent default with manual.
// v3→v4 removes displayMode (single sidebar row layout).
2026-07-21 22:59:42 +03:00
migrate: migrateSessionDisplayState,
},
),
);
2026-08-13 15:30:54 +03:00
export type { ProjectSortOrder };