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