a tool for shared writing and social publishing
at feature/fonts 175 lines 5.8 kB view raw
1import { Block } from "components/Blocks/Block"; 2import { ReadTransaction } from "replicache"; 3import { Fact } from "src/replicache"; 4import { scanIndex, scanIndexLocal } from "src/replicache/utils"; 5 6function computeDisplayNumbers(blocks: Block[]): void { 7 let counters = new Map<string, number>(); 8 for (let block of blocks) { 9 if (!block.listData) { 10 counters.clear(); 11 continue; 12 } 13 if (block.listData.listStyle !== "ordered") continue; 14 let parent = block.listData.parent; 15 if (block.listData.listStart !== undefined) { 16 counters.set(parent, block.listData.listStart); 17 } else if (!counters.has(parent)) { 18 counters.set(parent, 1); 19 } 20 block.listData.displayNumber = counters.get(parent)!; 21 counters.set(parent, counters.get(parent)! + 1); 22 } 23} 24 25export const getBlocksWithType = async ( 26 tx: ReadTransaction, 27 entityID: string, 28) => { 29 let initialized = await tx.get("initialized"); 30 if (!initialized) return null; 31 let scan = scanIndex(tx); 32 let blocks = await scan.eav(entityID, "card/block"); 33 34 let result = ( 35 await Promise.all( 36 blocks 37 .sort((a, b) => { 38 if (a.data.position === b.data.position) return a.id > b.id ? 1 : -1; 39 return a.data.position > b.data.position ? 1 : -1; 40 }) 41 .map(async (b) => { 42 let type = (await scan.eav(b.data.value, "block/type"))[0]; 43 let isList = await scan.eav(b.data.value, "block/is-list"); 44 if (!type) return null; 45 // All lists use recursive structure 46 if (isList[0]?.data.value) { 47 const getChildren = async ( 48 root: Fact<"card/block">, 49 parent: string, 50 depth: number, 51 path: { depth: number; entity: string }[], 52 ): Promise<Block[]> => { 53 let children = ( 54 await scan.eav(root.data.value, "card/block") 55 ).sort((a, b) => (a.data.position > b.data.position ? 1 : -1)); 56 let type = (await scan.eav(root.data.value, "block/type"))[0]; 57 let checklist = await scan.eav( 58 root.data.value, 59 "block/check-list", 60 ); 61 let listStyle = (await scan.eav(root.data.value, "block/list-style"))[0]; 62 let listNumber = (await scan.eav(root.data.value, "block/list-number"))[0]; 63 if (!type) return []; 64 let newPath = [...path, { entity: root.data.value, depth }]; 65 let childBlocks = await Promise.all( 66 children.map((c) => 67 getChildren(c, root.data.value, depth + 1, newPath), 68 ), 69 ); 70 return [ 71 { 72 ...root.data, 73 factID: root.id, 74 type: type.data.value, 75 parent: b.entity, 76 listData: { 77 depth: depth, 78 parent, 79 path: newPath, 80 checklist: !!checklist[0], 81 listStyle: listStyle?.data.value, 82 listStart: listNumber?.data.value, 83 }, 84 }, 85 ...childBlocks.flat(), 86 ]; 87 }; 88 return getChildren(b, b.entity, 1, []); 89 } 90 return [ 91 { 92 ...b.data, 93 factID: b.id, 94 type: type.data.value, 95 parent: b.entity, 96 }, 97 ] as Block[]; 98 }), 99 ) 100 ) 101 .flat() 102 .filter((f) => f !== null); 103 104 computeDisplayNumbers(result); 105 return result; 106}; 107 108export const getBlocksWithTypeLocal = ( 109 initialFacts: Fact<any>[], 110 entityID: string, 111) => { 112 let scan = scanIndexLocal(initialFacts); 113 let blocks = scan.eav(entityID, "card/block"); 114 let result = blocks 115 .sort((a, b) => { 116 if (a.data.position === b.data.position) return a.id > b.id ? 1 : -1; 117 return a.data.position > b.data.position ? 1 : -1; 118 }) 119 .map((b) => { 120 let type = scan.eav(b.data.value, "block/type")[0]; 121 let isList = scan.eav(b.data.value, "block/is-list"); 122 if (!type) return null; 123 // All lists use recursive structure 124 if (isList[0]?.data.value) { 125 const getChildren = ( 126 root: Fact<"card/block">, 127 parent: string, 128 depth: number, 129 path: { depth: number; entity: string }[], 130 ): Block[] => { 131 let children = scan 132 .eav(root.data.value, "card/block") 133 .sort((a, b) => (a.data.position > b.data.position ? 1 : -1)); 134 let type = scan.eav(root.data.value, "block/type")[0]; 135 let listStyle = scan.eav(root.data.value, "block/list-style")[0]; 136 let listNumber = scan.eav(root.data.value, "block/list-number")[0]; 137 if (!type) return []; 138 let newPath = [...path, { entity: root.data.value, depth }]; 139 let childBlocks = children.map((c) => 140 getChildren(c, root.data.value, depth + 1, newPath), 141 ); 142 return [ 143 { 144 ...root.data, 145 factID: root.id, 146 type: type.data.value, 147 parent: b.entity, 148 listData: { 149 depth: depth, 150 parent, 151 path: newPath, 152 listStyle: listStyle?.data.value, 153 listStart: listNumber?.data.value, 154 }, 155 }, 156 ...childBlocks.flat(), 157 ]; 158 }; 159 return getChildren(b, b.entity, 1, []); 160 } 161 return [ 162 { 163 ...b.data, 164 factID: b.id, 165 type: type.data.value, 166 parent: b.entity, 167 }, 168 ] as Block[]; 169 }) 170 .flat() 171 .filter((f) => f !== null); 172 173 computeDisplayNumbers(result); 174 return result; 175};