Skip to content

Commit 6527b2d

Browse files
committed
migrate personal left sidebar setting
1 parent 3a9a73d commit 6527b2d

File tree

6 files changed

+433
-847
lines changed

6 files changed

+433
-847
lines changed

apps/roam/src/components/LeftSidebarView.tsx

Lines changed: 68 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
/* eslint-disable @typescript-eslint/naming-convention */
2-
import React, {
3-
useCallback,
4-
useEffect,
5-
useMemo,
6-
useRef,
7-
useState,
8-
} from "react";
2+
import React, { useCallback, useEffect, useRef, useState } from "react";
93
import ReactDOM from "react-dom";
104
import {
115
Collapse,
@@ -21,29 +15,23 @@ import {
2115
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
2216
import openBlockInSidebar from "roamjs-components/writes/openBlockInSidebar";
2317
import extractRef from "roamjs-components/util/extractRef";
24-
import {
25-
getFormattedConfigTree,
26-
notify,
27-
subscribe,
28-
} from "~/utils/discourseConfigRef";
29-
import type {
30-
LeftSidebarConfig,
31-
LeftSidebarPersonalSectionConfig,
32-
} from "~/utils/getLeftSidebarSettings";
18+
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
3319
import { createBlock } from "roamjs-components/writes";
34-
import deleteBlock from "roamjs-components/writes/deleteBlock";
3520
import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
3621
import refreshConfigTree from "~/utils/refreshConfigTree";
37-
import { Dispatch, SetStateAction } from "react";
3822
import { SettingsDialog } from "./settings/Settings";
3923
import { OnloadArgs } from "roamjs-components/types";
4024
import renderOverlay from "roamjs-components/util/renderOverlay";
4125
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
4226
import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
4327
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
44-
import { migrateLeftSidebarSettings } from "~/utils/migrateLeftSidebarSettings";
45-
import { useLeftSidebarGlobalSettings } from "./settings/utils/hooks";
46-
import { setGlobalSetting } from "./settings/utils/accessors";
28+
import {
29+
useLeftSidebarGlobalSettings,
30+
useLeftSidebarPersonalSettings,
31+
} from "./settings/utils/hooks";
32+
import { getGlobalSetting, setGlobalSetting, setPersonalSetting } from "./settings/utils/accessors";
33+
import type { LeftSidebarGlobalSettings } from "./settings/utils/zodSchema";
34+
import type { PersonalSection } from "./settings/utils/zodSchema";
4735

4836
const parseReference = (text: string) => {
4937
const extracted = extractRef(text);
@@ -87,36 +75,6 @@ const openTarget = async (e: React.MouseEvent, targetUid: string) => {
8775
}
8876
};
8977

90-
const toggleFoldedState = ({
91-
isOpen,
92-
setIsOpen,
93-
folded,
94-
parentUid,
95-
}: {
96-
isOpen: boolean;
97-
setIsOpen: Dispatch<SetStateAction<boolean>>;
98-
folded: { uid?: string; value: boolean };
99-
parentUid: string;
100-
}) => {
101-
if (isOpen) {
102-
setIsOpen(false);
103-
if (folded.uid) {
104-
void deleteBlock(folded.uid);
105-
folded.uid = undefined;
106-
folded.value = false;
107-
}
108-
} else {
109-
setIsOpen(true);
110-
const newUid = window.roamAlphaAPI.util.generateUID();
111-
void createBlock({
112-
parentUid,
113-
node: { text: "Folded", uid: newUid },
114-
});
115-
folded.uid = newUid;
116-
folded.value = true;
117-
}
118-
};
119-
12078
const SectionChildren = ({
12179
childrenNodes,
12280
truncateAt,
@@ -156,31 +114,32 @@ const SectionChildren = ({
156114
};
157115

158116
const PersonalSectionItem = ({
117+
sectionName,
159118
section,
119+
onToggleFolded,
160120
}: {
161-
section: LeftSidebarPersonalSectionConfig;
121+
sectionName: string;
122+
section: PersonalSection;
123+
onToggleFolded: (sectionName: string) => void;
162124
}) => {
163-
const titleRef = parseReference(section.text);
164-
const blockText = useMemo(
165-
() =>
166-
titleRef.type === "block" ? getTextByBlockUid(titleRef.uid) : undefined,
167-
[titleRef],
168-
);
169-
const truncateAt = section.settings?.truncateResult.value;
170-
const [isOpen, setIsOpen] = useState<boolean>(
171-
!!section.settings?.folded.value || false,
172-
);
125+
const truncateAt = section.Settings?.["Truncate-result?"];
126+
const [isOpen, setIsOpen] = useState<boolean>(section.Settings?.Folded ?? false);
173127

174-
const handleChevronClick = () => {
175-
if (!section.settings) return;
176-
177-
toggleFoldedState({
178-
isOpen,
179-
setIsOpen,
180-
folded: section.settings.folded,
181-
parentUid: section.settings.uid || "",
182-
});
183-
};
128+
useEffect(() => {
129+
setIsOpen(section.Settings?.Folded ?? false);
130+
}, [section.Settings?.Folded]);
131+
132+
const handleChevronClick = useCallback(() => {
133+
const newState = !isOpen;
134+
setIsOpen(newState);
135+
onToggleFolded(sectionName);
136+
}, [isOpen, sectionName, onToggleFolded]);
137+
138+
const childrenNodes = section.Children.map((child) => ({
139+
uid: child.Page,
140+
text: child.Page,
141+
alias: child.Alias ? { value: child.Alias } : undefined,
142+
}));
184143

185144
return (
186145
<>
@@ -189,14 +148,14 @@ const PersonalSectionItem = ({
189148
<div
190149
className="flex items-center"
191150
onClick={() => {
192-
if ((section.children?.length || 0) > 0) {
151+
if (section.Children.length > 0) {
193152
handleChevronClick();
194153
}
195154
}}
196155
>
197-
{(blockText || titleRef.display).toUpperCase()}
156+
{sectionName.toUpperCase()}
198157
</div>
199-
{(section.children?.length || 0) > 0 && (
158+
{section.Children.length > 0 && (
200159
<span
201160
className="sidebar-title-button-chevron p-1"
202161
onClick={handleChevronClick}
@@ -207,25 +166,37 @@ const PersonalSectionItem = ({
207166
</div>
208167
</div>
209168
<Collapse isOpen={isOpen}>
210-
<SectionChildren
211-
childrenNodes={section.children || []}
212-
truncateAt={truncateAt}
213-
/>
169+
<SectionChildren childrenNodes={childrenNodes} truncateAt={truncateAt} />
214170
</Collapse>
215171
</>
216172
);
217173
};
218174

219-
const PersonalSections = ({ config }: { config: LeftSidebarConfig }) => {
220-
const sections = config.personal.sections || [];
175+
const PersonalSections = () => {
176+
const personalSettings = useLeftSidebarPersonalSettings();
177+
const sections = Object.entries(personalSettings);
178+
179+
const handleToggleFolded = useCallback(
180+
(sectionName: string) => {
181+
const section = personalSettings[sectionName];
182+
if (!section) return;
183+
const newFolded = !section.Settings.Folded;
184+
setPersonalSetting(["Left Sidebar", sectionName, "Settings", "Folded"], newFolded);
185+
},
186+
[personalSettings],
187+
);
221188

222189
if (!sections.length) return null;
223190

224191
return (
225192
<div className="personal-left-sidebar-sections">
226-
{sections.map((section) => (
227-
<div key={section.uid}>
228-
<PersonalSectionItem section={section} />
193+
{sections.map(([name, section]) => (
194+
<div key={name}>
195+
<PersonalSectionItem
196+
sectionName={name}
197+
section={section}
198+
onToggleFolded={handleToggleFolded}
199+
/>
229200
</div>
230201
))}
231202
</div>
@@ -284,27 +255,6 @@ const GlobalSection = () => {
284255
);
285256
};
286257

287-
export const useConfig = () => {
288-
const [config, setConfig] = useState(
289-
() => getFormattedConfigTree().leftSidebar,
290-
);
291-
useEffect(() => {
292-
const handleUpdate = () => {
293-
setConfig(getFormattedConfigTree().leftSidebar);
294-
};
295-
const unsubscribe = subscribe(handleUpdate);
296-
return () => {
297-
unsubscribe();
298-
};
299-
}, []);
300-
return { config, setConfig };
301-
};
302-
303-
export const refreshAndNotify = () => {
304-
refreshConfigTree();
305-
notify();
306-
};
307-
308258
const FavoritesPopover = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
309259
const [isMenuOpen, setIsMenuOpen] = useState(false);
310260
const menuTriggerRef = useRef<HTMLSpanElement | null>(null);
@@ -416,13 +366,11 @@ const FavoritesPopover = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
416366
};
417367

418368
const LeftSidebarView = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
419-
const { config } = useConfig();
420-
421369
return (
422370
<>
423371
<FavoritesPopover onloadArgs={onloadArgs} />
424372
<GlobalSection />
425-
<PersonalSections config={config} />
373+
<PersonalSections />
426374
</>
427375
);
428376
};
@@ -435,31 +383,23 @@ const migrateFavorites = async () => {
435383
const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE);
436384
if (!configPageUid) return;
437385

438-
let leftSidebarUid = config.uid;
439-
if (leftSidebarUid) {
440-
const leftSidebarTree = getBasicTreeByParentUid(leftSidebarUid);
441-
const hasAnyPersonalSection = leftSidebarTree.some((node) =>
442-
node.text.endsWith("/Personal-Section"),
443-
);
444-
if (hasAnyPersonalSection) {
445-
await createBlock({
446-
parentUid: leftSidebarUid,
447-
node: { text: "Favorites Migrated" },
448-
});
449-
refreshConfigTree();
450-
return;
451-
}
452-
}
453-
454386
const results = window.roamAlphaAPI.q(`
455-
[:find ?uid
387+
[:find ?uid
456388
:where [?e :page/sidebar]
457389
[?e :block/uid ?uid]]
458390
`);
459-
const favorites = (results as string[][]).map(([uid]) => ({
460-
uid,
461-
}));
391+
const favorites = (results as string[][]).map(([uid]) => uid);
392+
393+
const currentSettings = getGlobalSetting<LeftSidebarGlobalSettings>(["Left Sidebar"]);
394+
const existingChildren = new Set(currentSettings?.Children || []);
395+
const newFavorites = favorites.filter((uid) => !existingChildren.has(uid));
396+
397+
if (newFavorites.length > 0) {
398+
const mergedChildren = [...(currentSettings?.Children || []), ...newFavorites];
399+
setGlobalSetting(["Left Sidebar", "Children"], mergedChildren);
400+
}
462401

402+
let leftSidebarUid = config.uid;
463403
if (!leftSidebarUid) {
464404
const tree = getBasicTreeByParentUid(configPageUid);
465405
const found = tree.find((n) => n.text === "Left Sidebar");
@@ -473,47 +413,6 @@ const migrateFavorites = async () => {
473413
}
474414
}
475415

476-
let globalSectionUid = config.global.uid;
477-
if (!globalSectionUid) {
478-
const tree = getBasicTreeByParentUid(leftSidebarUid);
479-
const found = tree.find((n) => n.text === "Global-Section");
480-
if (found) {
481-
globalSectionUid = found.uid;
482-
} else {
483-
globalSectionUid = await createBlock({
484-
parentUid: leftSidebarUid,
485-
node: { text: "Global-Section" },
486-
});
487-
}
488-
}
489-
490-
let childrenUid = config.global.childrenUid;
491-
if (!childrenUid) {
492-
const tree = getBasicTreeByParentUid(globalSectionUid);
493-
const found = tree.find((n) => n.text === "Children");
494-
if (found) {
495-
childrenUid = found.uid;
496-
} else {
497-
childrenUid = await createBlock({
498-
parentUid: globalSectionUid,
499-
node: { text: "Children" },
500-
});
501-
}
502-
}
503-
504-
const childrenTree = getBasicTreeByParentUid(childrenUid);
505-
const existingTexts = new Set(childrenTree.map((c) => c.text));
506-
const newFavorites = favorites.filter(({ uid }) => !existingTexts.has(uid));
507-
508-
if (newFavorites.length > 0) {
509-
await Promise.all(
510-
newFavorites.map(({ uid }) =>
511-
createBlock({ parentUid: childrenUid, node: { text: uid } }),
512-
),
513-
);
514-
refreshAndNotify();
515-
}
516-
517416
await createBlock({
518417
parentUid: leftSidebarUid,
519418
node: { text: "Favorites Migrated" },
@@ -539,7 +438,6 @@ export const mountLeftSidebar = async (
539438
let root = wrapper.querySelector(`#${id}`) as HTMLDivElement;
540439
if (!root) {
541440
await migrateFavorites();
542-
await migrateLeftSidebarSettings();
543441
wrapper.innerHTML = "";
544442
root = document.createElement("div");
545443
root.id = id;

0 commit comments

Comments
 (0)