OpenCut/apps/web/src/stores/preview-store.ts

113 lines
2.7 KiB
TypeScript

import { create } from "zustand";
import { persist } from "zustand/middleware";
import { isGuideId, type GuideId } from "@/lib/guides";
import { DEFAULT_GRID_CONFIG } from "@/constants/guide-constants";
import type { GridConfig } from "@/lib/guides/types";
interface PreviewOverlaysState {
bookmarks: boolean;
}
interface PersistedPreviewState {
activeGuide?: string | null;
layoutGuide?: {
platform?: string | null;
};
overlays?: PreviewOverlaysState;
gridConfig?: GridConfig;
}
interface PreviewState {
activeGuide: GuideId | null;
overlays: PreviewOverlaysState;
gridConfig: GridConfig;
toggleGuide: (guideId: GuideId) => void;
setGridConfig: (config: Partial<GridConfig>) => void;
setOverlayVisibility: ({
overlay,
isVisible,
}: {
overlay: keyof PreviewOverlaysState;
isVisible: boolean;
}) => void;
toggleOverlayVisibility: ({
overlay,
}: {
overlay: keyof PreviewOverlaysState;
}) => void;
}
const DEFAULT_PREVIEW_OVERLAYS: PreviewOverlaysState = {
bookmarks: true,
};
function getPersistedActiveGuide(
state: PersistedPreviewState | undefined,
): GuideId | null {
const persistedGuide =
state?.activeGuide ?? state?.layoutGuide?.platform ?? null;
if (typeof persistedGuide !== "string") {
return null;
}
return isGuideId(persistedGuide) ? persistedGuide : null;
}
export const usePreviewStore = create<PreviewState>()(
persist(
(set) => ({
activeGuide: null,
overlays: DEFAULT_PREVIEW_OVERLAYS,
gridConfig: DEFAULT_GRID_CONFIG,
toggleGuide: (guideId) => {
set((state) => ({
activeGuide: state.activeGuide === guideId ? null : guideId,
}));
},
setGridConfig: (config) => {
set((state) => ({
gridConfig: { ...state.gridConfig, ...config },
}));
},
setOverlayVisibility: ({ overlay, isVisible }) => {
set((state) => ({
overlays: {
...state.overlays,
[overlay]: isVisible,
},
}));
},
toggleOverlayVisibility: ({ overlay }) => {
set((state) => ({
overlays: {
...state.overlays,
[overlay]: !state.overlays[overlay],
},
}));
},
}),
{
name: "preview-settings",
version: 4,
migrate: (persistedState) => {
const state = persistedState as PersistedPreviewState | undefined;
return {
activeGuide: getPersistedActiveGuide(state),
overlays: state?.overlays ?? DEFAULT_PREVIEW_OVERLAYS,
gridConfig: {
rows: state?.gridConfig?.rows ?? DEFAULT_GRID_CONFIG.rows,
cols: state?.gridConfig?.cols ?? DEFAULT_GRID_CONFIG.cols,
},
};
},
partialize: (state) => ({
activeGuide: state.activeGuide,
overlays: state.overlays,
gridConfig: state.gridConfig,
}),
},
),
);