a tool for shared writing and social publishing
1import { Block } from "components/Blocks/Block";
2import { Replicache } from "replicache";
3import type { ReplicacheMutators } from "src/replicache";
4import { useUIState } from "src/useUIState";
5import { v7 } from "uuid";
6
7export function indent(
8 block: Block,
9 previousBlock?: Block,
10 rep?: Replicache<ReplicacheMutators> | null,
11) {
12 if (!block.listData) return false;
13 if (!previousBlock?.listData) return false;
14 let depth = block.listData.depth;
15 let newParent = previousBlock.listData.path.find((f) => f.depth === depth);
16 if (!newParent) return false;
17 if (useUIState.getState().foldedBlocks.includes(newParent.entity))
18 useUIState.getState().toggleFold(newParent.entity);
19 rep?.mutate.retractFact({ factID: block.factID });
20 rep?.mutate.addLastBlock({
21 parent: newParent.entity,
22 factID: v7(),
23 entity: block.value,
24 });
25 return true;
26}
27
28export function outdentFull(
29 block: Block,
30 rep?: Replicache<ReplicacheMutators> | null,
31) {
32 if (!block.listData) return;
33
34 // make this block not a list
35 rep?.mutate.assertFact({
36 entity: block.value,
37 attribute: "block/is-list",
38 data: { type: "boolean", value: false },
39 });
40
41 // find the next block that is a level 1 list item or not a list item.
42 // If there are none or this block is a level 1 list item, we don't need to move anything
43
44 let after = block.listData?.path.find((f) => f.depth === 1)?.entity;
45
46 // move this block to be after that block
47 after &&
48 after !== block.value &&
49 rep?.mutate.moveBlock({
50 block: block.value,
51 oldParent: block.listData.parent,
52 newParent: block.parent,
53 position: { type: "after", entity: after },
54 });
55
56 // move all the childen to the be under it as a level 1 list item
57 rep?.mutate.moveChildren({
58 oldParent: block.value,
59 newParent: block.parent,
60 after: block.value,
61 });
62}
63
64export function outdent(
65 block: Block,
66 previousBlock: Block | null,
67 rep?: Replicache<ReplicacheMutators> | null,
68) {
69 if (!block.listData) return false;
70 let listData = block.listData;
71 if (listData.depth === 1) {
72 rep?.mutate.assertFact({
73 entity: block.value,
74 attribute: "block/is-list",
75 data: { type: "boolean", value: false },
76 });
77 rep?.mutate.moveChildren({
78 oldParent: block.value,
79 newParent: block.parent,
80 after: block.value,
81 });
82 } else {
83 if (!previousBlock || !previousBlock.listData) return false;
84 let after = previousBlock.listData.path.find(
85 (f) => f.depth === listData.depth - 1,
86 )?.entity;
87 if (!after) return false;
88 let parent: string | undefined = undefined;
89 if (listData.depth === 2) {
90 parent = block.parent;
91 } else {
92 parent = previousBlock.listData.path.find(
93 (f) => f.depth === listData.depth - 2,
94 )?.entity;
95 }
96 if (!parent) return false;
97 if (useUIState.getState().foldedBlocks.includes(parent))
98 useUIState.getState().toggleFold(parent);
99 rep?.mutate.outdentBlock({
100 block: block.value,
101 newParent: parent,
102 oldParent: listData.parent,
103 after,
104 });
105 }
106}