a tool for shared writing and social publishing
1import { Block } from "components/Blocks/Block";
2import { create } from "zustand";
3import { combine, createJSONStorage, persist } from "zustand/middleware";
4
5type SelectedBlock = Pick<Block, "value" | "parent">;
6export const useUIState = create(
7 combine(
8 {
9 lastUsedHighlight: "1" as "1" | "2" | "3",
10 focusedEntity: null as
11 | { entityType: "page"; entityID: string }
12 | { entityType: "block"; entityID: string; parent: string }
13 | { entityType: "footnote"; entityID: string; parent: string }
14 | null,
15 foldedBlocks: [] as string[],
16 openPages: [] as string[],
17 selectedBlocks: [] as SelectedBlock[],
18 openPopover: null as string | null,
19 },
20 (set) => ({
21 setOpenPopover: (id: string | null) => {
22 set({ openPopover: id });
23 },
24 toggleFold: (entityID: string) => {
25 set((state) => {
26 return {
27 foldedBlocks: state.foldedBlocks.includes(entityID)
28 ? state.foldedBlocks.filter((b) => b !== entityID)
29 : [...state.foldedBlocks, entityID],
30 };
31 });
32 },
33 openPage: (parent: string, page: string) =>
34 set((state) => {
35 let parentPosition = state.openPages.findIndex((s) => s == parent);
36 return {
37 openPages:
38 parentPosition === -1
39 ? [page]
40 : [...state.openPages.slice(0, parentPosition + 1), page],
41 };
42 }),
43 closePage: (pages: string | string[]) =>
44 set((s) => ({
45 openPages: s.openPages.filter((c) => ![pages].flat().includes(c)),
46 })),
47 setFocusedBlock: (
48 b:
49 | { entityType: "page"; entityID: string }
50 | { entityType: "block"; entityID: string; parent: string }
51 | { entityType: "footnote"; entityID: string; parent: string }
52 | null,
53 ) => set(() => ({ focusedEntity: b })),
54 setSelectedBlock: (block: SelectedBlock) =>
55 set((state) => {
56 return { ...state, selectedBlocks: [block] };
57 }),
58 setSelectedBlocks: (blocks: SelectedBlock[]) =>
59 set((state) => {
60 return { ...state, selectedBlocks: blocks };
61 }),
62 addBlockToSelection: (block: SelectedBlock) =>
63 set((state) => {
64 if (state.selectedBlocks.find((b) => b.value === block.value))
65 return state;
66 return { ...state, selectedBlocks: [...state.selectedBlocks, block] };
67 }),
68 removeBlockFromSelection: (block: { value: string }) =>
69 set((state) => {
70 return {
71 ...state,
72 selectedBlocks: state.selectedBlocks.filter(
73 (f) => f.value !== block.value,
74 ),
75 };
76 }),
77 }),
78 ),
79);