Skip to content

Commit

Permalink
Style dgraph nodes in Graph Overview (#175)
Browse files Browse the repository at this point in the history
* add to config

* add graph callback

* modify color to save with hex

* minor fixes

* PR Feedback: add callback to rm graph view styling

* 1.13.0
  • Loading branch information
mdroidian authored Nov 21, 2023
1 parent 29840b4 commit 2b54dea
Show file tree
Hide file tree
Showing 7 changed files with 164 additions and 42 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "query-builder",
"version": "1.12.0",
"version": "1.13.0",
"description": "Introduces new user interfaces for building queries in Roam",
"main": "./build/main.js",
"author": {
Expand Down
64 changes: 44 additions & 20 deletions src/components/DiscourseNodeCanvasSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
Switch,
Tooltip,
Icon,
ControlGroup,
} from "@blueprintjs/core";
import React, { useRef, useState, useMemo } from "react";
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
Expand All @@ -14,9 +15,17 @@ import setInputSetting from "roamjs-components/util/setInputSetting";

const DiscourseNodeCanvasSettings = ({ uid }: { uid: string }) => {
const tree = useMemo(() => getBasicTreeByParentUid(uid), [uid]);
const [color, setColor] = useState<string>(() =>
getSettingValueFromTree({ tree, key: "color" })
);
const [color, setColor] = useState<string>(() => {
const color = getSettingValueFromTree({ tree, key: "color" });
const COLOR_TEST = /^[0-9a-f]{6}$/i;
if (color.startsWith("#")) {
return color;
// handle legacy color format
} else if (COLOR_TEST.test(color)) {
return "#" + color;
}
return "";
});
const [alias, setAlias] = useState<string>(() =>
getSettingValueFromTree({ tree, key: "alias" })
);
Expand All @@ -31,21 +40,38 @@ const DiscourseNodeCanvasSettings = ({ uid }: { uid: string }) => {
);
return (
<div>
<Label style={{ width: 120 }}>
Color Picker
<InputGroup
type={"color"}
value={color}
onChange={(e) => {
setColor(e.target.value);
setInputSetting({
blockUid: uid,
key: "color",
value: e.target.value,
});
}}
/>
</Label>
<div className="mb-4">
<Label style={{ marginBottom: "4px" }}>Color Picker</Label>
<ControlGroup>
<InputGroup
style={{ width: 120 }}
type={"color"}
value={color}
onChange={(e) => {
setColor(e.target.value);
setInputSetting({
blockUid: uid,
key: "color",
value: e.target.value.replace("#", ""), // remove hash to not create roam link
});
}}
/>
<Tooltip content={color ? "Unset" : "Color not set"}>
<Icon
className={"align-middle opacity-80 ml-2"}
icon={color ? "delete" : "info-sign"}
onClick={() => {
setColor("");
setInputSetting({
blockUid: uid,
key: "color",
value: "",
});
}}
/>
</Tooltip>
</ControlGroup>
</div>
<Label style={{ width: 240 }}>
Display Alias
<InputGroup
Expand All @@ -60,9 +86,7 @@ const DiscourseNodeCanvasSettings = ({ uid }: { uid: string }) => {
}}
/>
</Label>
{/* <Tooltip content="Add an image to each Discourse Node"> */}
<Switch
// label="Use Key Images"
style={{ width: 240, lineHeight: "normal" }}
alignIndicator="right"
checked={isKeyImage}
Expand Down
22 changes: 18 additions & 4 deletions src/components/TldrawCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
TLTextShape,
TEXT_PROPS,
FONT_SIZES,
FONT_FAMILIES,
MenuItem,
} from "@tldraw/tldraw";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
Expand Down Expand Up @@ -234,10 +235,15 @@ const DEFAULT_WIDTH = 160;
const DEFAULT_HEIGHT = 64;
export const MAX_WIDTH = "400px";

// FONT_FAMILIES.sans or tldraw_sans not working in toSvg()
// maybe check getSvg()
// in node_modules\@tldraw\tldraw\node_modules\@tldraw\editor\dist\cjs\lib\app\App.js
const SVG_FONT_FAMILY = "sans-serif";

export const DEFAULT_STYLE_PROPS = {
...TEXT_PROPS,
fontSize: FONT_SIZES.m,
fontFamily: "sans",
fontFamily: FONT_FAMILIES.sans,
width: "fit-content",
padding: "40px",
};
Expand Down Expand Up @@ -414,8 +420,16 @@ class DiscourseNodeUtil extends TLBoxUtil<DiscourseNodeShape> {
? discourseNodeIndex
: 0
];
const backgroundInfo = backgroundColor
? { backgroundColor, backgroundCss: backgroundColor }
const formattedBackgroundColor =
backgroundColor && !backgroundColor.startsWith("#")
? `#${backgroundColor}`
: backgroundColor;

const backgroundInfo = formattedBackgroundColor
? {
backgroundColor: formattedBackgroundColor,
backgroundCss: formattedBackgroundColor,
}
: {
backgroundColor: COLOR_PALETTE[paletteColor],
backgroundCss: `var(--palette-${paletteColor})`,
Expand Down Expand Up @@ -637,7 +651,7 @@ class DiscourseNodeUtil extends TLBoxUtil<DiscourseNodeShape> {
});

// set attributes for the text
text.setAttribute("font-family", DEFAULT_STYLE_PROPS.fontFamily);
text.setAttribute("font-family", SVG_FONT_FAMILY);
text.setAttribute("font-size", DEFAULT_STYLE_PROPS.fontSize + "px");
text.setAttribute("font-weight", DEFAULT_STYLE_PROPS.fontWeight);
text.setAttribute("fill", textColor);
Expand Down
18 changes: 3 additions & 15 deletions src/components/TldrawCanvasLabelDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import {
import fireQuery from "../utils/fireQuery";
import fuzzy from "fuzzy";
import { RoamOverlayProps } from "roamjs-components/util/renderOverlay";
import { QBClause, Result } from "../utils/types";
import { Result } from "../utils/types";
import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
import { DiscourseContextType } from "./TldrawCanvas";
import { getPlainTitleFromSpecification } from "../discourseGraphsMode";

const LabelDialogAutocomplete = ({
setLabel,
Expand Down Expand Up @@ -124,20 +125,7 @@ const LabelDialog = ({
if (_label) return _label;
const { specification, text } = discourseContext.nodes[nodeType];
if (!specification.length) return "";
// CURRENT ASSUMPTIONS:
// - conditions are properly ordered
// - there is a has title condition somewhere
const titleCondition = specification.find(
(s): s is QBClause =>
s.type === "clause" && s.relation === "has title" && s.source === text
);
if (!titleCondition) return "";
return titleCondition.target
.replace(/^\/(\^)?/, "")
.replace(/(\$)?\/$/, "")
.replace(/\\\[/g, "[")
.replace(/\\\]/g, "]")
.replace(/\(\.[\*\+](\?)?\)/g, "");
return getPlainTitleFromSpecification({ specification, text });
}, [_label, nodeType]);
const initialValue = useMemo(() => {
return { text: initialLabel, uid: initialUid };
Expand Down
93 changes: 93 additions & 0 deletions src/discourseGraphsMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
import {
CustomField,
Field,
FieldPanel,
FlagField,
SelectField,
TextField,
Expand Down Expand Up @@ -52,6 +53,7 @@ import DiscourseNodeCanvasSettings from "./components/DiscourseNodeCanvasSetting
import CanvasReferences from "./components/CanvasReferences";
import fireQuery from "./utils/fireQuery";
import { render as renderGraphOverviewExport } from "./components/ExportDiscourseContext";
import { Condition, QBClause } from "./utils/types";

export const SETTING = "discourse-graphs";

Expand Down Expand Up @@ -237,13 +239,43 @@ export const renderDiscourseNodeTypeConfigPage = ({
component: DiscourseNodeCanvasSettings,
},
} as Field<CustomField>,
// @ts-ignore
{
title: "Graph Overview",
Panel: FlagPanel,
description: `Whether to color the node in the graph overview based on canvas color`,
defaultValue: true,
} as FieldPanel<FlagField>,
],
});

renderNode();
}
};

export const getPlainTitleFromSpecification = ({
specification,
text,
}: {
specification: Condition[];
text: string;
}) => {
// Assumptions:
// - Conditions are properly ordered
// - There is a 'has title' condition somewhere
const titleCondition = specification.find(
(s): s is QBClause =>
s.type === "clause" && s.relation === "has title" && s.source === text
);
if (!titleCondition) return "";
return titleCondition.target
.replace(/^\/(\^)?/, "")
.replace(/(\$)?\/$/, "")
.replace(/\\\[/g, "[")
.replace(/\\\]/g, "]")
.replace(/\(\.[\*\+](\?)?\)/g, "");
};

const initializeDiscourseGraphsMode = async (args: OnloadArgs) => {
const unloads = new Set<() => void>();
const toggle = async (flag: boolean) => {
Expand Down Expand Up @@ -760,6 +792,67 @@ const initializeDiscourseGraphsMode = async (args: OnloadArgs) => {
unloads.delete(removeQueryPage);
});

type SigmaRenderer = {
setSetting: (settingName: string, value: any) => void;
getSetting: (settingName: string) => any;
};
type nodeData = {
x: number;
y: number;
label: string;
size: number;
};

window.roamAlphaAPI.ui.graphView.wholeGraph.addCallback({
label: "discourse-node-styling",
callback: ({ "sigma-renderer": sigma }) => {
const sig = sigma as SigmaRenderer;
const allNodes = getDiscourseNodes();
const prefixColors = allNodes.map((n) => {
const formattedTitle = getPlainTitleFromSpecification({
specification: n.specification,
text: n.text,
});
const formattedBackgroundColor =
n.canvasSettings.color && !n.canvasSettings.color.startsWith("#")
? `#${n.canvasSettings.color}`
: n.canvasSettings.color;

return {
prefix: formattedTitle,
color: formattedBackgroundColor,
showInGraphOverview: n.graphOverview,
};
});

const originalReducer = sig.getSetting("nodeReducer");
sig.setSetting("nodeReducer", (id: string, nodeData: nodeData) => {
let modifiedData = originalReducer
? originalReducer(id, nodeData)
: nodeData;

const { label } = modifiedData;

for (const { prefix, color, showInGraphOverview } of prefixColors) {
if (showInGraphOverview && label.startsWith(prefix)) {
return {
...modifiedData,
color,
};
}
}

return modifiedData;
});
},
});
unloads.add(function removeGraphViewCallback() {
window.roamAlphaAPI.ui.graphView.wholeGraph.removeCallback({
label: "discourse-node-styling",
});
unloads.delete(removeGraphViewCallback);
});

window.roamAlphaAPI.ui.commandPalette.addCommand({
label: "Export Discourse Graph",
callback: () => {
Expand Down
3 changes: 3 additions & 0 deletions src/utils/getDiscourseNodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type DiscourseNode = {
};
// @deprecated - use specification instead
format: string;
graphOverview?: boolean;
};

const DEFAULT_NODES: DiscourseNode[] = [
Expand Down Expand Up @@ -78,6 +79,8 @@ const getDiscourseNodes = (relations = getDiscourseRelations()) => {
(c) => [c.text, c.children[0]?.text || ""] as const
)
),
graphOverview:
children.filter((c) => c.text === "Graph Overview").length > 0,
};
})
.concat(
Expand Down

0 comments on commit 2b54dea

Please sign in to comment.