diff --git a/apps/roam/src/components/LeftSidebarView.tsx b/apps/roam/src/components/LeftSidebarView.tsx
index b449a15ff..5a002d4f1 100644
--- a/apps/roam/src/components/LeftSidebarView.tsx
+++ b/apps/roam/src/components/LeftSidebarView.tsx
@@ -19,8 +19,6 @@ import {
TabId,
} from "@blueprintjs/core";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
-import openBlockInSidebar from "roamjs-components/writes/openBlockInSidebar";
-import extractRef from "roamjs-components/util/extractRef";
import {
getFormattedConfigTree,
notify,
@@ -40,50 +38,9 @@ import { OnloadArgs } from "roamjs-components/types";
import renderOverlay from "roamjs-components/util/renderOverlay";
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
-import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
import { migrateLeftSidebarSettings } from "~/utils/migrateLeftSidebarSettings";
-
-const parseReference = (text: string) => {
- const extracted = extractRef(text);
- if (text.startsWith("((") && text.endsWith("))")) {
- return { type: "block" as const, uid: extracted, display: text };
- } else {
- return { type: "page" as const, display: text };
- }
-};
-
-const truncate = (s: string, max: number | undefined): string => {
- if (!max || max <= 0) return s;
- return s.length > max ? `${s.slice(0, max)}...` : s;
-};
-
-const openTarget = async (e: React.MouseEvent, targetUid: string) => {
- e.preventDefault();
- e.stopPropagation();
- const target = parseReference(targetUid);
- if (target.type === "block") {
- if (e.shiftKey) {
- await openBlockInSidebar(target.uid);
- return;
- }
- await window.roamAlphaAPI.ui.mainWindow.openBlock({
- block: { uid: target.uid },
- });
- return;
- }
-
- if (e.shiftKey) {
- await window.roamAlphaAPI.ui.rightSidebar.addWindow({
- // @ts-expect-error - todo test
- // eslint-disable-next-line @typescript-eslint/naming-convention
- window: { type: "outline", "block-uid": targetUid },
- });
- } else {
- await window.roamAlphaAPI.ui.mainWindow.openPage({
- page: { uid: targetUid },
- });
- }
-};
+import { parseReference, SectionChildren } from "./left-sidebar/utils";
+import { ViewGlobalLeftSidebar } from "./left-sidebar/ViewGlobalLeftSidebar";
const toggleFoldedState = ({
isOpen,
@@ -115,44 +72,6 @@ const toggleFoldedState = ({
}
};
-const SectionChildren = ({
- childrenNodes,
- truncateAt,
-}: {
- childrenNodes: { uid: string; text: string; alias?: { value: string } }[];
- truncateAt?: number;
-}) => {
- if (!childrenNodes?.length) return null;
- return (
- <>
- {childrenNodes.map((child) => {
- const ref = parseReference(child.text);
- const alias = child.alias?.value;
- const display =
- ref.type === "page"
- ? getPageTitleByPageUid(ref.display)
- : getTextByBlockUid(ref.uid);
- const label = alias || truncate(display, truncateAt);
- const onClick = (e: React.MouseEvent) => {
- return void openTarget(e, child.text);
- };
- return (
-
- );
- })}
- >
- );
-};
-
const PersonalSectionItem = ({
section,
}: {
@@ -230,47 +149,6 @@ const PersonalSections = ({ config }: { config: LeftSidebarConfig }) => {
);
};
-const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {
- const [isOpen, setIsOpen] = useState(
- !!config.settings?.folded.value,
- );
- if (!config.children?.length) return null;
- const isCollapsable = config.settings?.collapsable.value;
-
- return (
- <>
- {
- if (!isCollapsable || !config.settings) return;
- toggleFoldedState({
- isOpen,
- setIsOpen,
- folded: config.settings.folded,
- parentUid: config.settings.uid,
- });
- }}
- >
-
- GLOBAL
- {isCollapsable && (
-
-
-
- )}
-
-
- {isCollapsable ? (
-
-
-
- ) : (
-
- )}
- >
- );
-};
-
export const useConfig = () => {
const [config, setConfig] = useState(
() => getFormattedConfigTree().leftSidebar,
@@ -408,7 +286,7 @@ const LeftSidebarView = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
return (
<>
-
+
>
);
@@ -533,7 +411,9 @@ export const mountLeftSidebar = async (
export const unmountLeftSidebar = (wrapper: HTMLElement): void => {
if (!wrapper) return;
- const root = wrapper.querySelector(`#${"dg-left-sidebar-root"}`) as HTMLDivElement;
+ const root = wrapper.querySelector(
+ `#${"dg-left-sidebar-root"}`,
+ ) as HTMLDivElement;
if (root) {
ReactDOM.unmountComponentAtNode(root);
root.remove();
diff --git a/apps/roam/src/components/left-sidebar/LeftSidebarGlobalSettings.tsx b/apps/roam/src/components/left-sidebar/LeftSidebarGlobalSettings.tsx
new file mode 100644
index 000000000..5214d8547
--- /dev/null
+++ b/apps/roam/src/components/left-sidebar/LeftSidebarGlobalSettings.tsx
@@ -0,0 +1,280 @@
+import React, { useCallback, useEffect, useMemo, useState, memo } from "react";
+import { Button, ButtonGroup } from "@blueprintjs/core";
+import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
+import getAllPageNames from "roamjs-components/queries/getAllPageNames";
+import type { RoamBasicNode } from "roamjs-components/types";
+import { extractRef } from "roamjs-components/util";
+import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
+import { render as renderToast } from "roamjs-components/components/Toast";
+import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
+import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
+import {
+ getGlobalSetting,
+ setGlobalSetting,
+} from "~/components/settings/block-prop/utils/accessors";
+import { GlobalSettingsSchema } from "~/components/settings/block-prop/utils/zodSchema";
+import { FlagPanel } from "../settings/block-prop/components/FlagPanel";
+import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
+import { CollapsiblePanel } from "../settings/block-prop/components/CollapsiblePanel";
+
+const PageItem = memo(
+ ({
+ page,
+ index,
+ isFirst,
+ isLast,
+ onMove,
+ onRemove,
+ }: {
+ page: RoamBasicNode;
+ index: number;
+ isFirst: boolean;
+ isLast: boolean;
+ onMove: (index: number, direction: "up" | "down") => void;
+ onRemove: (page: RoamBasicNode) => void;
+ }) => {
+ const pageDisplayTitle =
+ getPageTitleByPageUid(page.text) ||
+ getTextByBlockUid(extractRef(page.text)) ||
+ page.text;
+
+ return (
+
+
{pageDisplayTitle}
+
+
+
+ );
+ },
+);
+
+PageItem.displayName = "PageItem";
+
+const LeftSidebarGlobalSectionsContent = () => {
+ const [pages, setPages] = useState([]);
+ const [newPageInput, setNewPageInput] = useState("");
+ const [autocompleteKey, setAutocompleteKey] = useState(0);
+ const [isInitializing, setIsInitializing] = useState(true);
+
+ const pageNames = useMemo(() => getAllPageNames(), []);
+
+ useEffect(() => {
+ setIsInitializing(true);
+
+ const leftSidebarSettings = GlobalSettingsSchema.shape[
+ "Left Sidebar"
+ ].parse(getGlobalSetting(["Left Sidebar"]) || {});
+
+ setPages(
+ (leftSidebarSettings.Children || []).map((uid) => ({
+ uid,
+ text: uid,
+ children: [],
+ })),
+ );
+ setIsInitializing(false);
+ }, []);
+
+ const movePage = useCallback(
+ (index: number, direction: "up" | "down") => {
+ if (direction === "up" && index === 0) return;
+ if (direction === "down" && index === pages.length - 1) return;
+
+ const newPages = [...pages];
+ const [removed] = newPages.splice(index, 1);
+ const newIndex = direction === "up" ? index - 1 : index + 1;
+ newPages.splice(newIndex, 0, removed);
+ void setGlobalSetting(
+ ["Left Sidebar", "Children"],
+ newPages.map((p) => p.text),
+ );
+ setPages(newPages);
+ },
+ [pages],
+ );
+
+ const addPage = useCallback(
+ (pageName: string) => {
+ if (!pageName) return;
+
+ const targetUid = getPageUidByPageTitle(pageName);
+ if (pages.some((p) => p.text === targetUid)) {
+ console.warn(`Page "${pageName}" already exists in global section`);
+ return;
+ }
+
+ try {
+ const newPage: RoamBasicNode = {
+ text: targetUid,
+ uid: targetUid,
+ children: [],
+ };
+
+ const nextPages = [...pages, newPage];
+ void setGlobalSetting(
+ ["Left Sidebar", "Children"],
+ [...nextPages.map((p) => p.text)],
+ );
+ setPages(nextPages);
+ setNewPageInput("");
+ setAutocompleteKey((prev) => prev + 1);
+ } catch (error) {
+ renderToast({
+ content: "Failed to add page",
+ intent: "danger",
+ id: "add-page-error",
+ });
+ }
+ },
+ [pages],
+ );
+
+ const removePage = useCallback(
+ (page: RoamBasicNode) => {
+ const next = pages.filter((p) => p.uid !== page.uid);
+ void setGlobalSetting(
+ ["Left Sidebar", "Children"],
+ next.map((p) => p.text),
+ );
+ setPages(next);
+ },
+ [pages],
+ );
+
+ const handlePageInputChange = useCallback((value: string) => {
+ setNewPageInput(value);
+ }, []);
+
+ const isAddButtonDisabled = useMemo(() => {
+ if (!newPageInput) return true;
+ const targetUid = getPageUidByPageTitle(newPageInput);
+ return !targetUid || pages.some((p) => p.text === targetUid);
+ }, [newPageInput, pages]);
+
+ if (isInitializing) {
+ return (
+
+ Loading...
+
+ );
+ }
+
+ return (
+
+
+
+
+ Children
+
+ {pages.length} {pages.length === 1 ? "page" : "pages"}
+
+
+ }
+ defaultOpen={true}
+ >
+
+
+ Add pages that will appear for all users
+
+
+
void addPage(newPageInput)}
+ />
+ void addPage(newPageInput)}
+ title="Add page"
+ />
+
+ {pages.length > 0 ? (
+
+ {pages.map((page, index) => (
+
void removePage(page)}
+ />
+ ))}
+
+ ) : (
+
+ No pages added yet
+
+ )}
+
+
+
+ );
+};
+
+export const LeftSidebarGlobalSections = () => {
+ return ;
+};
diff --git a/apps/roam/src/components/left-sidebar/ViewGlobalLeftSidebar.tsx b/apps/roam/src/components/left-sidebar/ViewGlobalLeftSidebar.tsx
new file mode 100644
index 000000000..4fe89db10
--- /dev/null
+++ b/apps/roam/src/components/left-sidebar/ViewGlobalLeftSidebar.tsx
@@ -0,0 +1,50 @@
+import { getGlobalSetting } from "~/components/settings/block-prop/utils/accessors";
+import { GlobalSettingsSchema } from "~/components/settings/block-prop/utils/zodSchema";
+import { CollapsiblePanel } from "~/components/settings/block-prop/components/CollapsiblePanel";
+import React from "react";
+import { SectionChildren } from "./utils";
+
+export const ViewGlobalLeftSidebar = () => {
+ const settings = GlobalSettingsSchema.shape["Left Sidebar"].parse(
+ getGlobalSetting(["Left Sidebar"]) || {},
+ );
+
+ const children = settings.Children || [];
+ const folded = settings.Settings.Folded;
+ const collapsable = settings.Settings.Collapsable;
+
+ if (!children.length) return null;
+
+ const childrenNodes = children.map((uid) => ({
+ uid,
+ text: uid,
+ }));
+
+ const header = (
+ GLOBAL
+ );
+
+ if (collapsable) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+ );
+};
diff --git a/apps/roam/src/components/left-sidebar/utils.tsx b/apps/roam/src/components/left-sidebar/utils.tsx
new file mode 100644
index 000000000..27d45d5a9
--- /dev/null
+++ b/apps/roam/src/components/left-sidebar/utils.tsx
@@ -0,0 +1,85 @@
+import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
+import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
+import extractRef from "roamjs-components/util/extractRef";
+import openBlockInSidebar from "roamjs-components/writes/openBlockInSidebar";
+import React from "react";
+
+export const parseReference = (text: string) => {
+ const extracted = extractRef(text);
+ if (text.startsWith("((") && text.endsWith("))")) {
+ return { type: "block" as const, uid: extracted, display: text };
+ } else {
+ return { type: "page" as const, display: text };
+ }
+};
+
+export const truncate = (s: string, max: number | undefined): string => {
+ if (!max || max <= 0) return s;
+ return s.length > max ? `${s.slice(0, max)}...` : s;
+};
+
+export const openTarget = async (e: React.MouseEvent, targetUid: string) => {
+ e.preventDefault();
+ e.stopPropagation();
+ const target = parseReference(targetUid);
+ if (target.type === "block") {
+ if (e.shiftKey) {
+ await openBlockInSidebar(target.uid);
+ return;
+ }
+ await window.roamAlphaAPI.ui.mainWindow.openBlock({
+ block: { uid: target.uid },
+ });
+ return;
+ }
+
+ if (e.shiftKey) {
+ await window.roamAlphaAPI.ui.rightSidebar.addWindow({
+ // @ts-expect-error - todo test
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ window: { type: "outline", "block-uid": targetUid },
+ });
+ } else {
+ await window.roamAlphaAPI.ui.mainWindow.openPage({
+ page: { uid: targetUid },
+ });
+ }
+};
+
+export const SectionChildren = ({
+ childrenNodes,
+ truncateAt,
+}: {
+ childrenNodes: { uid: string; text: string; alias?: { value: string } }[];
+ truncateAt?: number;
+}) => {
+ if (!childrenNodes?.length) return null;
+ return (
+ <>
+ {childrenNodes.map((child) => {
+ const ref = parseReference(child.text);
+ const alias = child.alias?.value;
+ const display =
+ ref.type === "page"
+ ? getPageTitleByPageUid(ref.display)
+ : getTextByBlockUid(ref.uid);
+ const label = alias || truncate(display, truncateAt);
+ const onClick = (e: React.MouseEvent) => {
+ return void openTarget(e, child.text);
+ };
+ return (
+
+ );
+ })}
+ >
+ );
+};
diff --git a/apps/roam/src/components/settings/GeneralSettings.tsx b/apps/roam/src/components/settings/GeneralSettings.tsx
index 0ab5a1ce9..1c3bacea8 100644
--- a/apps/roam/src/components/settings/GeneralSettings.tsx
+++ b/apps/roam/src/components/settings/GeneralSettings.tsx
@@ -3,9 +3,9 @@ import TextPanel from "roamjs-components/components/ConfigPanels/TextPanel";
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { DEFAULT_CANVAS_PAGE_FORMAT } from "~/index";
-import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/data/blockPropsSettingsConfig";
+import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
import { Alert, Intent } from "@blueprintjs/core";
-import { FlagPanel } from "./block-prop/FlagPanel";
+import { FlagPanel } from "./block-prop/components/FlagPanel";
const DiscourseGraphHome = () => {
const settings = useMemo(() => {
diff --git a/apps/roam/src/components/settings/LeftSidebarGlobalSettings.tsx b/apps/roam/src/components/settings/LeftSidebarGlobalSettings.tsx
deleted file mode 100644
index d9c8d739a..000000000
--- a/apps/roam/src/components/settings/LeftSidebarGlobalSettings.tsx
+++ /dev/null
@@ -1,381 +0,0 @@
-import React, { useCallback, useEffect, useMemo, useState, memo } from "react";
-import { Button, ButtonGroup, Collapse } from "@blueprintjs/core";
-import FlagPanel from "roamjs-components/components/ConfigPanels/FlagPanel";
-import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
-import getAllPageNames from "roamjs-components/queries/getAllPageNames";
-import createBlock from "roamjs-components/writes/createBlock";
-import deleteBlock from "roamjs-components/writes/deleteBlock";
-import type { RoamBasicNode } from "roamjs-components/types";
-import { extractRef, getSubTree } from "roamjs-components/util";
-import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
-import discourseConfigRef from "~/utils/discourseConfigRef";
-import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
-import { getLeftSidebarGlobalSectionConfig } from "~/utils/getLeftSidebarSettings";
-import { LeftSidebarGlobalSectionConfig } from "~/utils/getLeftSidebarSettings";
-import { render as renderToast } from "roamjs-components/components/Toast";
-import refreshConfigTree from "~/utils/refreshConfigTree";
-import { refreshAndNotify } from "~/components/LeftSidebarView";
-import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
-import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
-
-const PageItem = memo(
- ({
- page,
- index,
- isFirst,
- isLast,
- onMove,
- onRemove,
- }: {
- page: RoamBasicNode;
- index: number;
- isFirst: boolean;
- isLast: boolean;
- onMove: (index: number, direction: "up" | "down") => void;
- onRemove: (page: RoamBasicNode) => void;
- }) => {
- const pageDisplayTitle =
- getPageTitleByPageUid(page.text) ||
- getTextByBlockUid(extractRef(page.text)) ||
- page.text;
-
- return (
-
-
{pageDisplayTitle}
-
- onMove(index, "up")}
- title="Move up"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
- onMove(index, "down")}
- title="Move down"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
- onRemove(page)}
- title="Remove page"
- />
-
-
- );
- },
-);
-
-PageItem.displayName = "PageItem";
-
-const LeftSidebarGlobalSectionsContent = ({
- leftSidebar,
-}: {
- leftSidebar: RoamBasicNode;
-}) => {
- const [globalSection, setGlobalSection] =
- useState(null);
- const [pages, setPages] = useState([]);
- const [childrenUid, setChildrenUid] = useState(null);
- const [newPageInput, setNewPageInput] = useState("");
- const [autocompleteKey, setAutocompleteKey] = useState(0);
- const [isInitializing, setIsInitializing] = useState(true);
- const [isExpanded, setIsExpanded] = useState(true);
-
- const pageNames = useMemo(() => getAllPageNames(), []);
-
- useEffect(() => {
- const initialize = async () => {
- setIsInitializing(true);
- const globalSectionText = "Global-Section";
- const config = getLeftSidebarGlobalSectionConfig(leftSidebar.children);
-
- const existingGlobalSection = leftSidebar.children.find(
- (n) => n.text === globalSectionText,
- );
-
- if (!existingGlobalSection) {
- try {
- const globalSectionUid = await createBlock({
- parentUid: leftSidebar.uid,
- order: 0,
- node: { text: globalSectionText },
- });
- const settingsUid = await createBlock({
- parentUid: globalSectionUid,
- order: 0,
- node: { text: "Settings" },
- });
- const childrenUid = await createBlock({
- parentUid: globalSectionUid,
- order: 0,
- node: { text: "Children" },
- });
- setChildrenUid(childrenUid || null);
- setPages([]);
- setGlobalSection({
- uid: globalSectionUid,
- settings: {
- uid: settingsUid,
- collapsable: { uid: undefined, value: false },
- folded: { uid: undefined, value: false },
- },
- childrenUid,
- children: [],
- });
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to create global section",
- intent: "danger",
- id: "create-global-section-error",
- });
- }
- } else {
- setChildrenUid(config.childrenUid || null);
- setPages(config.children || []);
- setGlobalSection(config);
- }
- setIsInitializing(false);
- };
-
- void initialize();
- }, [leftSidebar]);
-
- const movePage = useCallback(
- (index: number, direction: "up" | "down") => {
- if (direction === "up" && index === 0) return;
- if (direction === "down" && index === pages.length - 1) return;
-
- const newPages = [...pages];
- const [removed] = newPages.splice(index, 1);
- const newIndex = direction === "up" ? index - 1 : index + 1;
- newPages.splice(newIndex, 0, removed);
-
- setPages(newPages);
-
- if (childrenUid) {
- const order = direction === "down" ? newIndex + 1 : newIndex;
-
- void window.roamAlphaAPI
- /* eslint-disable @typescript-eslint/naming-convention */
- .moveBlock({
- location: { "parent-uid": childrenUid, order },
- block: { uid: removed.uid },
- })
- .then(() => {
- refreshAndNotify();
- });
- }
- },
- [pages, childrenUid],
- );
-
- const addPage = useCallback(
- async (pageName: string) => {
- if (!pageName || !childrenUid) return;
-
- const targetUid = getPageUidByPageTitle(pageName);
- if (pages.some((p) => p.text === targetUid)) {
- console.warn(`Page "${pageName}" already exists in global section`);
- return;
- }
-
- try {
- const newPageUid = await createBlock({
- parentUid: childrenUid,
- order: "last",
- node: { text: targetUid },
- });
-
- const newPage: RoamBasicNode = {
- text: targetUid,
- uid: newPageUid,
- children: [],
- };
-
- setPages((prev) => [...prev, newPage]);
- setNewPageInput("");
- setAutocompleteKey((prev) => prev + 1);
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to add page",
- intent: "danger",
- id: "add-page-error",
- });
- }
- },
- [childrenUid, pages],
- );
-
- const removePage = useCallback(async (page: RoamBasicNode) => {
- try {
- await deleteBlock(page.uid);
- setPages((prev) => prev.filter((p) => p.uid !== page.uid));
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to remove page",
- intent: "danger",
- id: "remove-page-error",
- });
- }
- }, []);
-
- const handlePageInputChange = useCallback((value: string) => {
- setNewPageInput(value);
- }, []);
-
- const toggleChildren = useCallback(() => {
- setIsExpanded((prev) => !prev);
- }, []);
-
- const isAddButtonDisabled = useMemo(() => {
- if (!newPageInput) return true;
- const targetUid = getPageUidByPageTitle(newPageInput);
- return !targetUid || pages.some((p) => p.text === targetUid);
- }, [newPageInput, pages]);
-
- if (isInitializing || !globalSection) {
- return (
-
- Loading...
-
- );
- }
-
- return (
-
-
-
-
-
-
-
-
-
-
- Children
-
-
- {pages.length} {pages.length === 1 ? "page" : "pages"}
-
-
-
-
-
-
- Add pages that will appear for all users
-
-
-
void addPage(newPageInput)}
- />
- void addPage(newPageInput)}
- title="Add page"
- />
-
- {pages.length > 0 ? (
-
- {pages.map((page, index) => (
-
void removePage(page)}
- />
- ))}
-
- ) : (
-
- No pages added yet
-
- )}
-
-
-
-
- );
-};
-
-export const LeftSidebarGlobalSections = () => {
- const [leftSidebar, setLeftSidebar] = useState(null);
-
- useEffect(() => {
- const loadData = () => {
- refreshConfigTree();
-
- const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE);
- const updatedSettings = discourseConfigRef.tree;
- const leftSidebarNode = getSubTree({
- tree: updatedSettings,
- parentUid: configPageUid,
- key: "Left Sidebar",
- });
-
- setTimeout(() => {
- refreshAndNotify();
- }, 10);
- setLeftSidebar(leftSidebarNode);
- };
-
- void loadData();
- }, []);
-
- if (!leftSidebar) {
- return null;
- }
-
- return ;
-};
diff --git a/apps/roam/src/components/settings/LeftSidebarPersonalSettings.tsx b/apps/roam/src/components/settings/LeftSidebarPersonalSettings.tsx
deleted file mode 100644
index 3328482c9..000000000
--- a/apps/roam/src/components/settings/LeftSidebarPersonalSettings.tsx
+++ /dev/null
@@ -1,740 +0,0 @@
-import discourseConfigRef from "~/utils/discourseConfigRef";
-import React, { useCallback, useEffect, useMemo, useState } from "react";
-import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
-import getAllPageNames from "roamjs-components/queries/getAllPageNames";
-import {
- Button,
- ButtonGroup,
- Collapse,
- Dialog,
- InputGroup,
-} from "@blueprintjs/core";
-import createBlock from "roamjs-components/writes/createBlock";
-import deleteBlock from "roamjs-components/writes/deleteBlock";
-import type { RoamBasicNode } from "roamjs-components/types";
-import NumberPanel from "roamjs-components/components/ConfigPanels/NumberPanel";
-import TextPanel from "roamjs-components/components/ConfigPanels/TextPanel";
-import {
- LeftSidebarPersonalSectionConfig,
- getLeftSidebarPersonalSectionConfig,
- PersonalSectionChild,
-} from "~/utils/getLeftSidebarSettings";
-import { extractRef, getSubTree } from "roamjs-components/util";
-import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
-import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
-import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
-import { render as renderToast } from "roamjs-components/components/Toast";
-import refreshConfigTree from "~/utils/refreshConfigTree";
-import { refreshAndNotify } from "~/components/LeftSidebarView";
-import { memo, Dispatch, SetStateAction } from "react";
-import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
-
-const SectionItem = memo(
- ({
- section,
- setSettingsDialogSectionUid,
- pageNames,
- setSections,
- index,
- isFirst,
- isLast,
- onMoveSection,
- }: {
- section: LeftSidebarPersonalSectionConfig;
- setSections: Dispatch>;
- setSettingsDialogSectionUid: (uid: string | null) => void;
- pageNames: string[];
- index: number;
- isFirst: boolean;
- isLast: boolean;
- onMoveSection: (index: number, direction: "up" | "down") => void;
- }) => {
- const ref = extractRef(section.text);
- const blockText = getTextByBlockUid(ref);
- const originalName = blockText || section.text;
- const [childInput, setChildInput] = useState("");
- const [childInputKey, setChildInputKey] = useState(0);
-
- const [expandedChildLists, setExpandedChildLists] = useState>(
- new Set(),
- );
- const isExpanded = expandedChildLists.has(section.uid);
- const [childSettingsUid, setChildSettingsUid] = useState(
- null,
- );
- const toggleChildrenList = useCallback((sectionUid: string) => {
- setExpandedChildLists((prev) => {
- const next = new Set(prev);
- if (next.has(sectionUid)) {
- next.delete(sectionUid);
- } else {
- next.add(sectionUid);
- }
- return next;
- });
- }, []);
-
- const convertToComplexSection = useCallback(
- async (section: LeftSidebarPersonalSectionConfig) => {
- try {
- const settingsUid = await createBlock({
- parentUid: section.uid,
- order: 0,
- node: { text: "Settings" },
- });
- const foldedUid = await createBlock({
- parentUid: settingsUid,
- order: 0,
- node: { text: "Folded" },
- });
- const truncateSettingUid = await createBlock({
- parentUid: settingsUid,
- order: 1,
- node: { text: "Truncate-result?", children: [{ text: "75" }] },
- });
-
- const childrenUid = await createBlock({
- parentUid: section.uid,
- order: 1,
- node: { text: "Children" },
- });
-
- setSections((prev) =>
- prev.map((s) => {
- if (s.uid === section.uid) {
- return {
- ...s,
- settings: {
- uid: settingsUid,
- folded: { uid: foldedUid, value: false },
- truncateResult: { uid: truncateSettingUid, value: 75 },
- },
- childrenUid,
- children: [],
- };
- }
- return s;
- }),
- );
-
- setExpandedChildLists((prev) => new Set([...prev, section.uid]));
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to convert to complex section",
- intent: "danger",
- id: "convert-to-complex-section-error",
- });
- }
- },
- [setSections],
- );
-
- const removeSection = useCallback(
- async (section: LeftSidebarPersonalSectionConfig) => {
- try {
- await deleteBlock(section.uid);
-
- setSections((prev) => prev.filter((s) => s.uid !== section.uid));
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to remove section",
- intent: "danger",
- id: "remove-section-error",
- });
- }
- },
- [setSections],
- );
-
- const addChildToSection = useCallback(
- async (
- section: LeftSidebarPersonalSectionConfig,
- childrenUid: string,
- childName: string,
- ) => {
- if (!childName || !childrenUid) return;
-
- const targetUid = getPageUidByPageTitle(childName) || childName.trim();
-
- try {
- const newChild = await createBlock({
- parentUid: childrenUid,
- order: "last",
- node: { text: targetUid },
- });
-
- setSections((prev) =>
- prev.map((s) => {
- if (s.uid === section.uid) {
- return {
- ...s,
- children: [
- ...(s.children || []),
- {
- text: targetUid,
- uid: newChild,
- children: [],
- alias: { value: "" },
- },
- ],
- };
- }
- return s;
- }),
- );
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to add child",
- intent: "danger",
- id: "add-child-error",
- });
- }
- },
- [setSections],
- );
- const removeChild = useCallback(
- async (
- section: LeftSidebarPersonalSectionConfig,
- child: PersonalSectionChild,
- ) => {
- try {
- await deleteBlock(child.uid);
-
- setSections((prev) =>
- prev.map((s) => {
- if (s.uid === section.uid) {
- return {
- ...s,
- children: s.children?.filter((c) => c.uid !== child.uid),
- };
- }
- return s;
- }),
- );
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to remove child",
- intent: "danger",
- id: "remove-child-error",
- });
- }
- },
- [setSections],
- );
-
- const moveChild = useCallback(
- (
- section: LeftSidebarPersonalSectionConfig,
- index: number,
- direction: "up" | "down",
- ) => {
- if (!section.children) return;
- if (direction === "up" && index === 0) return;
- if (direction === "down" && index === section.children.length - 1)
- return;
-
- const newChildren = [...section.children];
- const [removed] = newChildren.splice(index, 1);
- const newIndex = direction === "up" ? index - 1 : index + 1;
- newChildren.splice(newIndex, 0, removed);
-
- setSections((prev) =>
- prev.map((s) => {
- if (s.uid === section.uid) {
- return {
- ...s,
- children: newChildren,
- };
- }
- return s;
- }),
- );
-
- if (section.childrenUid) {
- const order = direction === "down" ? newIndex + 1 : newIndex;
-
- void window.roamAlphaAPI
- /* eslint-disable @typescript-eslint/naming-convention */
- .moveBlock({
- location: { "parent-uid": section.childrenUid, order },
- block: { uid: removed.uid },
- })
- .then(() => {
- refreshAndNotify();
- });
- }
- },
- [setSections],
- );
-
- const handleAddChild = useCallback(async () => {
- if (childInput && section.childrenUid) {
- await addChildToSection(section, section.childrenUid, childInput);
- setChildInput("");
- setChildInputKey((prev) => prev + 1);
- refreshAndNotify();
- }
- }, [childInput, section, addChildToSection]);
-
- const sectionWithoutSettingsAndChildren =
- (!section.settings && section.children?.length === 0) ||
- !section.children;
-
- return (
-
-
- {!sectionWithoutSettingsAndChildren && (
-
toggleChildrenList(section.uid)}
- />
- )}
-
- !sectionWithoutSettingsAndChildren &&
- toggleChildrenList(section.uid)
- }
- >
- {originalName}
-
-
- onMoveSection(index, "up")}
- title="Move section up"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
- onMoveSection(index, "down")}
- title="Move section down"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
-
- sectionWithoutSettingsAndChildren
- ? void convertToComplexSection(section)
- : void setSettingsDialogSectionUid(section.uid)
- }
- />
- void removeSection(section)}
- title="Remove section"
- />
-
-
-
- {!sectionWithoutSettingsAndChildren && (
-
-
-
-
void handleAddChild()}
- />
- void handleAddChild()}
- title="Add child"
- />
-
-
- {(section.children || []).length > 0 && (
-
- {(section.children || []).map((child, index) => {
- const childAlias = child.alias?.value;
- const isSettingsOpen = childSettingsUid === child.uid;
- const childDisplayTitle =
- getPageTitleByPageUid(child.text) ||
- getTextByBlockUid(extractRef(child.text)) ||
- child.text;
- return (
-
-
-
- {childAlias ? (
-
-
- {childAlias}
-
-
- ({childDisplayTitle})
-
-
- ) : (
- childDisplayTitle
- )}
-
-
- setChildSettingsUid(child.uid)}
- title="Child Settings"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
- moveChild(section, index, "up")}
- title="Move child up"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
- moveChild(section, index, "down")}
- title="Move child down"
- className="opacity-0 transition-opacity group-hover:opacity-100"
- />
- void removeChild(section, child)}
- title="Remove child"
- />
-
-
-
-
- );
- })}
-
- )}
-
- {(!section.children || section.children.length === 0) && (
-
- No children added yet
-
- )}
-
-
- )}
-
- );
- },
-);
-
-SectionItem.displayName = "SectionItem";
-
-const LeftSidebarPersonalSectionsContent = ({
- leftSidebar,
-}: {
- leftSidebar: RoamBasicNode;
-}) => {
- const [sections, setSections] = useState(
- [],
- );
- const [personalSectionUid, setPersonalSectionUid] = useState(
- null,
- );
- const [newSectionInput, setNewSectionInput] = useState("");
- const [settingsDialogSectionUid, setSettingsDialogSectionUid] = useState<
- string | null
- >(null);
-
- useEffect(() => {
- const initialize = async () => {
- const userUid = window.roamAlphaAPI.user.uid();
- const personalSectionText = userUid + "/Personal-Section";
-
- const personalSection = leftSidebar.children.find(
- (n) => n.text === personalSectionText,
- );
-
- if (!personalSection) {
- const newSectionUid = await createBlock({
- parentUid: leftSidebar.uid,
- order: 0,
- node: {
- text: personalSectionText,
- },
- });
- setPersonalSectionUid(newSectionUid);
- setSections([]);
- } else {
- setPersonalSectionUid(personalSection.uid);
- const loadedSections = getLeftSidebarPersonalSectionConfig(
- leftSidebar.children,
- ).sections;
- setSections(loadedSections);
- }
- };
-
- void initialize();
- }, [leftSidebar]);
-
- const addSection = useCallback(
- async (sectionName: string) => {
- if (!sectionName || !personalSectionUid) return;
- if (sections.some((s) => s.text === sectionName)) return;
-
- try {
- const newBlock = await createBlock({
- parentUid: personalSectionUid,
- order: "last",
- node: { text: sectionName },
- });
-
- setSections((prev) => [
- ...prev,
- {
- text: sectionName,
- uid: newBlock,
- settings: undefined,
- children: undefined,
- childrenUid: undefined,
- } as LeftSidebarPersonalSectionConfig,
- ]);
-
- setNewSectionInput("");
- refreshAndNotify();
- } catch (error) {
- renderToast({
- content: "Failed to add section",
- intent: "danger",
- id: "add-section-error",
- });
- }
- },
- [personalSectionUid, sections],
- );
-
- const handleNewSectionInputChange = useCallback((value: string) => {
- setNewSectionInput(value);
- }, []);
-
- const moveSection = useCallback(
- (index: number, direction: "up" | "down") => {
- if (direction === "up" && index === 0) return;
- if (direction === "down" && index === sections.length - 1) return;
-
- const newSections = [...sections];
- const [removed] = newSections.splice(index, 1);
- const newIndex = direction === "up" ? index - 1 : index + 1;
- newSections.splice(newIndex, 0, removed);
-
- setSections(newSections);
-
- if (personalSectionUid) {
- const order = direction === "down" ? newIndex + 1 : newIndex;
-
- void window.roamAlphaAPI
- /* eslint-disable @typescript-eslint/naming-convention */
- .moveBlock({
- location: { "parent-uid": personalSectionUid, order },
- block: { uid: removed.uid },
- })
- .then(() => {
- refreshAndNotify();
- });
- }
- },
- [sections, personalSectionUid],
- );
-
- const activeDialogSection = useMemo(() => {
- return sections.find((s) => s.uid === settingsDialogSectionUid) || null;
- }, [sections, settingsDialogSectionUid]);
-
- const pageNames = useMemo(() => getAllPageNames(), []);
-
- if (!personalSectionUid) {
- return null;
- }
-
- return (
-
-
-
- Add pages or create custom sections with settings and children
-
-
- handleNewSectionInputChange(e.target.value)}
- placeholder="Add section …"
- onKeyDown={(e) => {
- if (e.key === "Enter" && newSectionInput) {
- e.preventDefault();
- e.stopPropagation();
- void addSection(newSectionInput);
- }
- }}
- />
- s.text === newSectionInput)
- }
- onClick={() => void addSection(newSectionInput)}
- />
-
-
-
-
- {sections.map((section, index) => (
-
-
-
- ))}
-
-
- {activeDialogSection && activeDialogSection.settings && (
-
- )}
-
- );
-};
-
-export const LeftSidebarPersonalSections = () => {
- const [leftSidebar, setLeftSidebar] = useState(null);
-
- useEffect(() => {
- const loadData = () => {
- refreshConfigTree();
-
- const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE);
- const updatedSettings = discourseConfigRef.tree;
- const leftSidebarNode = getSubTree({
- tree: updatedSettings,
- parentUid: configPageUid,
- key: "Left Sidebar",
- });
-
- setTimeout(() => {
- refreshAndNotify();
- }, 10);
- setLeftSidebar(leftSidebarNode);
- };
-
- void loadData();
- }, []);
-
- if (!leftSidebar) {
- return null;
- }
-
- return ;
-};
diff --git a/apps/roam/src/components/settings/Settings.tsx b/apps/roam/src/components/settings/Settings.tsx
index 7e6069b96..93f5b80b7 100644
--- a/apps/roam/src/components/settings/Settings.tsx
+++ b/apps/roam/src/components/settings/Settings.tsx
@@ -26,8 +26,8 @@ import HomePersonalSettings from "./HomePersonalSettings";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { FeedbackWidget } from "~/components/BirdEatsBugs";
import { getVersionWithDate } from "~/utils/getVersion";
-import { LeftSidebarPersonalSections } from "./LeftSidebarPersonalSettings";
-import { LeftSidebarGlobalSections } from "./LeftSidebarGlobalSettings";
+import { LeftSidebarPersonalSections } from "../left-sidebar/LeftSidebarPersonalSettings";
+import { LeftSidebarGlobalSections } from "../left-sidebar/LeftSidebarGlobalSettings";
type SectionHeaderProps = {
children: React.ReactNode;
diff --git a/apps/roam/src/components/settings/block-prop/components/CollapsiblePanel.tsx b/apps/roam/src/components/settings/block-prop/components/CollapsiblePanel.tsx
new file mode 100644
index 000000000..876eef00a
--- /dev/null
+++ b/apps/roam/src/components/settings/block-prop/components/CollapsiblePanel.tsx
@@ -0,0 +1,71 @@
+import React, { useState, ReactNode, useCallback } from "react";
+import { Button, Collapse } from "@blueprintjs/core";
+import { getGlobalSetting, setGlobalSetting } from "~/components/settings/block-prop/utils/accessors";
+import z from "zod";
+
+type Props = {
+ header: ReactNode;
+ children: ReactNode;
+ settingKey?: string[];
+ defaultOpen?: boolean;
+ className?: string;
+};
+
+export const CollapsiblePanel = ({
+ header,
+ children,
+ settingKey,
+ defaultOpen = false,
+ className = "",
+}: Props) => {
+ const getPersistedValue = useCallback(() => {
+ if (!settingKey || settingKey.length === 0) return undefined;
+ const current = getGlobalSetting(settingKey);
+ const parsed = z.boolean().safeParse(current);
+ return parsed.success ? parsed.data : undefined;
+ }, [settingKey]);
+
+ const [isOpen, setIsOpen] = useState(() => {
+ const persisted = getPersistedValue();
+ return persisted !== undefined ? persisted : defaultOpen;
+ });
+
+ const handleToggle = () => {
+ const newState = !isOpen;
+ setIsOpen(newState);
+ if (settingKey && settingKey.length > 0) {
+ setGlobalSetting(settingKey, newState);
+ }
+ };
+
+ return (
+
+
+
+
{
+ e.stopPropagation();
+ handleToggle();
+ }}
+ />
+ {header}
+
+
+
+
+ {children}
+
+
+ );
+};
diff --git a/apps/roam/src/components/settings/block-prop/FlagPanel.tsx b/apps/roam/src/components/settings/block-prop/components/FlagPanel.tsx
similarity index 89%
rename from apps/roam/src/components/settings/block-prop/FlagPanel.tsx
rename to apps/roam/src/components/settings/block-prop/components/FlagPanel.tsx
index a7dc00990..c6b2745da 100644
--- a/apps/roam/src/components/settings/block-prop/FlagPanel.tsx
+++ b/apps/roam/src/components/settings/block-prop/components/FlagPanel.tsx
@@ -7,10 +7,10 @@ import {
getGlobalSetting,
setFeatureFlag,
setGlobalSetting,
-} from "~/utils/Settings/accessors";
-import { type FeatureFlags } from "~/utils/Settings/zodSchema";
+} from "~/components/settings/block-prop/utils/accessors";
+import { type FeatureFlags } from "~/components/settings/block-prop/utils/zodSchema";
import z from "zod";
-import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/data/blockPropsSettingsConfig";
+import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
type FeatureFlagPath = [
typeof TOP_LEVEL_BLOCK_PROP_KEYS.featureFlags,
diff --git a/apps/roam/src/data/blockPropsSettingsConfig.ts b/apps/roam/src/components/settings/block-prop/data/blockPropsSettingsConfig.ts
similarity index 100%
rename from apps/roam/src/data/blockPropsSettingsConfig.ts
rename to apps/roam/src/components/settings/block-prop/data/blockPropsSettingsConfig.ts
diff --git a/apps/roam/src/utils/Settings/accessors.ts b/apps/roam/src/components/settings/block-prop/utils/accessors.ts
similarity index 91%
rename from apps/roam/src/utils/Settings/accessors.ts
rename to apps/roam/src/components/settings/block-prop/utils/accessors.ts
index 4e81a09a5..61eaf581b 100644
--- a/apps/roam/src/utils/Settings/accessors.ts
+++ b/apps/roam/src/components/settings/block-prop/utils/accessors.ts
@@ -1,16 +1,16 @@
-import getBlockProps, { type json } from "../getBlockProps";
+import getBlockProps, { type json } from "~/utils/getBlockProps";
import getBlockUidByTextOnPage from "roamjs-components/queries/getBlockUidByTextOnPage";
-import setBlockProps from "../setBlockProps";
+import setBlockProps from "~/utils/setBlockProps";
import {
DG_BLOCK_PROP_SETTINGS_PAGE_TITLE,
TOP_LEVEL_BLOCK_PROP_KEYS,
-} from "~/data/blockPropsSettingsConfig";
+} from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
import z from "zod";
import {
FeatureFlags,
FeatureFlagsSchema,
GlobalSettingsSchema,
-} from "./zodSchema";
+} from "~/components/settings/block-prop/utils/zodSchema";
const isRecord = (value: unknown): value is Record =>
typeof value === "object" && value !== null && !Array.isArray(value);
@@ -77,7 +77,7 @@ export const setBlockPropBasedSettings = ({
});
if (keys.length === 1) {
- setBlockProps(blockUid, value as Record, true);
+ setBlockProps(blockUid, value as Record, false);
return;
}
@@ -110,7 +110,7 @@ export const setBlockPropBasedSettings = ({
updatedProps,
);
- setBlockProps(blockUid, updatedProps, true);
+ setBlockProps(blockUid, updatedProps, false);
};
export const getFeatureFlag = (key: keyof FeatureFlags): boolean => {
diff --git a/apps/roam/src/utils/Settings/pullWatch.ts b/apps/roam/src/components/settings/block-prop/utils/pullWatch.ts
similarity index 69%
rename from apps/roam/src/utils/Settings/pullWatch.ts
rename to apps/roam/src/components/settings/block-prop/utils/pullWatch.ts
index 49760fb1b..4dc7f5960 100644
--- a/apps/roam/src/utils/Settings/pullWatch.ts
+++ b/apps/roam/src/components/settings/block-prop/utils/pullWatch.ts
@@ -1,5 +1,5 @@
-import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/data/blockPropsSettingsConfig";
-import { json, normalizeProps } from "~/utils/getBlockProps";
+import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
+import { type json, normalizeProps } from "~/utils/getBlockProps";
export const setupPullWatchBlockPropsBasedSettings = (
blockUids: Record,
@@ -9,6 +9,8 @@ export const setupPullWatchBlockPropsBasedSettings = (
const featureFlagsBlockUid =
blockUids[TOP_LEVEL_BLOCK_PROP_KEYS.featureFlags];
+ const globalSettingsBlockUid = blockUids[TOP_LEVEL_BLOCK_PROP_KEYS.global];
+
if (featureFlagsBlockUid) {
window.roamAlphaAPI.data.addPullWatch(
"[:block/props]",
@@ -35,4 +37,14 @@ export const setupPullWatchBlockPropsBasedSettings = (
},
);
}
+
+ if (globalSettingsBlockUid) {
+ window.roamAlphaAPI.data.addPullWatch(
+ "[:block/props]",
+ `[:block/uid "${globalSettingsBlockUid}"]`,
+ () => {
+ updateLeftSidebar(leftSidebarContainer);
+ },
+ );
+ }
};
diff --git a/apps/roam/src/utils/Settings/init.ts b/apps/roam/src/utils/Settings/init.ts
deleted file mode 100644
index 38f027b86..000000000
--- a/apps/roam/src/utils/Settings/init.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import {
- TOP_LEVEL_BLOCK_PROP_KEYS,
- DG_BLOCK_PROP_SETTINGS_PAGE_TITLE,
-} from "~/data/blockPropsSettingsConfig";
-import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
-import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeByParentUid";
-import { createPage, createBlock } from "roamjs-components/writes";
-
-const ensurePageExists = async (pageTitle: string): Promise => {
- let pageUid = getPageUidByPageTitle(pageTitle);
-
- if (!pageUid) {
- pageUid = window.roamAlphaAPI.util.generateUID();
- await createPage({
- title: pageTitle,
- uid: pageUid,
- });
- }
-
- return pageUid;
-};
-
-const ensureBlocksExist = async (
- pageUid: string,
-): Promise> => {
- const blockTexts = Object.values(TOP_LEVEL_BLOCK_PROP_KEYS);
- const existingChildren = getShallowTreeByParentUid(pageUid);
-
- const blockMap: Record = {};
- existingChildren.forEach((child) => {
- blockMap[child.text] = child.uid;
- });
-
- const missingBlocks = blockTexts.filter((blockText) => !blockMap[blockText]);
-
- if (missingBlocks.length > 0) {
- const createdBlocks = await Promise.all(
- missingBlocks.map(async (blockText) => {
- const uid = await createBlock({
- parentUid: pageUid,
- node: { text: blockText },
- });
- return { text: blockText, uid };
- }),
- );
-
- createdBlocks.forEach((block) => {
- blockMap[block.text] = block.uid;
- });
- }
-
- return blockMap;
-};
-
-export const initSchema = async (): Promise> => {
- const pageUid = await ensurePageExists(DG_BLOCK_PROP_SETTINGS_PAGE_TITLE);
- return await ensureBlocksExist(pageUid);
-};
diff --git a/apps/roam/src/utils/Settings/zodSchema.ts b/apps/roam/src/utils/Settings/zodSchema.ts
deleted file mode 100644
index ecab73e52..000000000
--- a/apps/roam/src/utils/Settings/zodSchema.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import { z } from "zod";
-
-/* eslint-disable @typescript-eslint/naming-convention */
-export const FeatureFlagsSchema = z.object({
- "Enable Left Sidebar": z.boolean().default(false),
-});
-
-export const GlobalSettingsSchema = z.object({
- "Left Sidebar": z.object({
- Children: z.array(z.string()).default([]),
- Settings: z.object({
- Collapsable: z.boolean().default(false),
- Folded: z.boolean().default(false),
- }),
- }),
-});
-/* eslint-disable @typescript-eslint/naming-convention */
-
-export type FeatureFlags = z.infer;
-export type GlobalSettings = z.infer;
diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts
index b08dd6858..59c116552 100644
--- a/apps/roam/src/utils/initializeObserversAndListeners.ts
+++ b/apps/roam/src/utils/initializeObserversAndListeners.ts
@@ -56,9 +56,9 @@ import {
import { getCleanTagText } from "~/components/settings/NodeConfig";
import getPleasingColors from "@repo/utils/getPleasingColors";
import { colord } from "colord";
-import { getFeatureFlag } from "./Settings/accessors";
-import { setupPullWatchBlockPropsBasedSettings } from "~/utils/Settings/pullWatch";
-import { initSchema } from "./Settings/init";
+import { getFeatureFlag } from "~/components/settings/block-prop/utils/accessors";
+import { setupPullWatchBlockPropsBasedSettings } from "~/components/settings/block-prop/utils/pullWatch";
+import { initSchema } from "../components/settings/block-prop/utils/init";
const debounce = (fn: () => void, delay = 250) => {
let timeout: number;