a tool for shared writing and social publishing
1import { useReplicache } from "src/replicache";
2import { useSubscribe } from "src/replicache/useSubscribe";
3import { scanIndex } from "src/replicache/utils";
4
5export type FootnoteInfo = {
6 footnoteEntityID: string;
7 blockID: string;
8 index: number;
9};
10
11export function usePageFootnotes(pageID: string) {
12 let rep = useReplicache();
13 let data = useSubscribe(
14 rep?.rep,
15 async (tx) => {
16 let scan = scanIndex(tx);
17 let cardBlocks = await scan.eav(pageID, "card/block");
18 let canvasBlocks = await scan.eav(pageID, "canvas/block");
19
20 let sortedCardBlocks = cardBlocks
21 .map((b) => ({ value: b.data.value, position: b.data.position }))
22 .toSorted((a, b) => (a.position > b.position ? 1 : -1));
23
24 let sortedCanvasBlocks = canvasBlocks
25 .map((b) => ({ value: b.data.value, position: b.data.position }))
26 .toSorted((a, b) => {
27 if (a.position.y === b.position.y) return a.position.x - b.position.x;
28 return a.position.y - b.position.y;
29 });
30
31 let sorted = [...sortedCardBlocks, ...sortedCanvasBlocks];
32
33 let footnotes: FootnoteInfo[] = [];
34 let indexMap: Record<string, number> = {};
35 let idx = 1;
36
37 for (let block of sorted) {
38 let blockFootnotes = await scan.eav(block.value, "block/footnote");
39 let sortedFootnotes = blockFootnotes.toSorted((a, b) =>
40 a.data.position > b.data.position ? 1 : -1,
41 );
42 for (let fn of sortedFootnotes) {
43 footnotes.push({
44 footnoteEntityID: fn.data.value,
45 blockID: block.value,
46 index: idx,
47 });
48 indexMap[fn.data.value] = idx;
49 idx++;
50 }
51 }
52
53 return { pageID, footnotes, indexMap };
54 },
55 { dependencies: [pageID] },
56 );
57
58 return (
59 data || { pageID, footnotes: [], indexMap: {} as Record<string, number> }
60 );
61}