import { create } from "zustand"; import { Commit, CommitHash } from "../components/commits/types"; // Store for app-wide state interface ProjectStore { // Inputs inputMode: "image" | "video"; setInputMode: (mode: "image" | "video") => void; isImportedFromCode: boolean; setIsImportedFromCode: (imported: boolean) => void; referenceImages: string[]; setReferenceImages: (images: string[]) => void; // Outputs commits: Record; head: CommitHash | null; addCommit: (commit: Commit) => void; removeCommit: (hash: CommitHash) => void; resetCommits: () => void; appendCommitCode: ( hash: CommitHash, numVariant: number, code: string ) => void; setCommitCode: (hash: CommitHash, numVariant: number, code: string) => void; updateSelectedVariantIndex: (hash: CommitHash, index: number) => void; setHead: (hash: CommitHash) => void; resetHead: () => void; executionConsoles: { [key: number]: string[] }; appendExecutionConsole: (variantIndex: number, line: string) => void; resetExecutionConsoles: () => void; } export const useProjectStore = create((set) => ({ // Inputs and their setters inputMode: "image", setInputMode: (mode) => set({ inputMode: mode }), isImportedFromCode: false, setIsImportedFromCode: (imported) => set({ isImportedFromCode: imported }), referenceImages: [], setReferenceImages: (images) => set({ referenceImages: images }), // Outputs commits: {}, head: null, addCommit: (commit: Commit) => { // When adding a new commit, make sure all existing commits are marked as committed set((state) => ({ commits: { ...Object.fromEntries( Object.entries(state.commits).map(([hash, existingCommit]) => [ hash, { ...existingCommit, isCommitted: true }, ]) ), [commit.hash]: commit, }, })); }, removeCommit: (hash: CommitHash) => { set((state) => { const newCommits = { ...state.commits }; delete newCommits[hash]; return { commits: newCommits }; }); }, resetCommits: () => set({ commits: {} }), appendCommitCode: (hash: CommitHash, numVariant: number, code: string) => set((state) => { const commit = state.commits[hash]; // Don't update if the commit is already committed if (commit.isCommitted) { throw new Error("Attempted to append code to a committed commit"); } return { commits: { ...state.commits, [hash]: { ...commit, variants: commit.variants.map((variant, index) => index === numVariant ? { ...variant, code: variant.code + code } : variant ), }, }, }; }), setCommitCode: (hash: CommitHash, numVariant: number, code: string) => set((state) => { const commit = state.commits[hash]; // Don't update if the commit is already committed if (commit.isCommitted) { throw new Error("Attempted to set code of a committed commit"); } return { commits: { ...state.commits, [hash]: { ...commit, variants: commit.variants.map((variant, index) => index === numVariant ? { ...variant, code } : variant ), }, }, }; }), updateSelectedVariantIndex: (hash: CommitHash, index: number) => set((state) => { const commit = state.commits[hash]; // Don't update if the commit is already committed if (commit.isCommitted) { throw new Error( "Attempted to update selected variant index of a committed commit" ); } return { commits: { ...state.commits, [hash]: { ...commit, selectedVariantIndex: index, }, }, }; }), setHead: (hash: CommitHash) => set({ head: hash }), resetHead: () => set({ head: null }), executionConsoles: {}, appendExecutionConsole: (variantIndex: number, line: string) => set((state) => ({ executionConsoles: { ...state.executionConsoles, [variantIndex]: [ ...(state.executionConsoles[variantIndex] || []), line, ], }, })), resetExecutionConsoles: () => set({ executionConsoles: {} }), }));