Skip to content

Commit ffc313a

Browse files
authored
[ENG-877] Initial Implementation node tags for Obsidian (#455)
* feature complete * reorganize * rm box shadow style * address some PR comments * some problem sovled * address all PR comments * sm fix * address PR comments
1 parent 126b2ff commit ffc313a

File tree

4 files changed

+697
-1
lines changed

4 files changed

+697
-1
lines changed

apps/obsidian/src/index.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Plugin, Editor, Menu, TFile, Events } from "obsidian";
1+
import { Plugin, Editor, Menu, TFile } from "obsidian";
22
import { SettingsTab } from "~/components/Settings";
33
import { Settings } from "~/types";
44
import { registerCommands } from "~/utils/registerCommands";
@@ -10,10 +10,12 @@ import {
1010
} from "~/utils/createNode";
1111
import { DEFAULT_SETTINGS } from "~/constants";
1212
import { CreateNodeModal } from "~/components/CreateNodeModal";
13+
import { TagNodeHandler } from "~/utils/tagNodeHandler";
1314

1415
export default class DiscourseGraphPlugin extends Plugin {
1516
settings: Settings = { ...DEFAULT_SETTINGS };
1617
private styleElement: HTMLStyleElement | null = null;
18+
private tagNodeHandler: TagNodeHandler | null = null;
1719

1820
async onload() {
1921
await this.loadSettings();
@@ -32,6 +34,15 @@ export default class DiscourseGraphPlugin extends Plugin {
3234
// Initialize frontmatter CSS
3335
this.updateFrontmatterStyles();
3436

37+
// Initialize tag node handler
38+
try {
39+
this.tagNodeHandler = new TagNodeHandler(this);
40+
this.tagNodeHandler.initialize();
41+
} catch (error) {
42+
console.error("Failed to initialize TagNodeHandler:", error);
43+
this.tagNodeHandler = null;
44+
}
45+
3546
this.registerEvent(
3647
// @ts-ignore - file-menu event exists but is not in the type definitions
3748
this.app.workspace.on("file-menu", (menu: Menu, file: TFile) => {
@@ -200,6 +211,11 @@ export default class DiscourseGraphPlugin extends Plugin {
200211
this.styleElement.remove();
201212
}
202213

214+
if (this.tagNodeHandler) {
215+
this.tagNodeHandler.cleanup();
216+
this.tagNodeHandler = null;
217+
}
218+
203219
this.app.workspace.detachLeavesOfType(VIEW_TYPE_DISCOURSE_CONTEXT);
204220
}
205221
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { DiscourseNode } from "~/types";
2+
3+
// Color palette similar to Roam's implementation
4+
const COLOR_PALETTE: Record<string, string> = {
5+
black: "#1d1d1d",
6+
blue: "#4263eb",
7+
green: "#099268",
8+
grey: "#adb5bd",
9+
lightBlue: "#4dabf7",
10+
lightGreen: "#40c057",
11+
lightRed: "#ff8787",
12+
lightViolet: "#e599f7",
13+
orange: "#f76707",
14+
red: "#e03131",
15+
violet: "#ae3ec9",
16+
white: "#ffffff",
17+
yellow: "#ffc078",
18+
};
19+
20+
const COLOR_ARRAY = Object.keys(COLOR_PALETTE);
21+
22+
// TODO switch to colord - https://linear.app/discourse-graphs/issue/ENG-836/button-like-css-styling-for-node-tag
23+
export const getContrastColor = (bgColor: string): string => {
24+
const hex = bgColor.replace("#", "");
25+
26+
if (hex.length !== 6) return "#000000";
27+
28+
const r = parseInt(hex.substring(0, 2), 16);
29+
const g = parseInt(hex.substring(2, 4), 16);
30+
const b = parseInt(hex.substring(4, 6), 16);
31+
32+
if (isNaN(r) || isNaN(g) || isNaN(b)) return "#000000";
33+
34+
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
35+
36+
return luminance > 0.5 ? "#000000" : "#ffffff";
37+
};
38+
39+
export const getNodeTagColors = (
40+
nodeType: DiscourseNode,
41+
nodeIndex: number,
42+
): { backgroundColor: string; textColor: string } => {
43+
const customColor = nodeType.color || "";
44+
45+
const safeIndex =
46+
nodeIndex >= 0 && nodeIndex < COLOR_ARRAY.length ? nodeIndex : 0;
47+
const paletteColorKey = COLOR_ARRAY[safeIndex];
48+
const paletteColor = paletteColorKey
49+
? COLOR_PALETTE[paletteColorKey]
50+
: COLOR_PALETTE.blue;
51+
52+
const backgroundColor = customColor || paletteColor || "#4263eb";
53+
const textColor = getContrastColor(backgroundColor);
54+
55+
return { backgroundColor, textColor };
56+
};
57+
58+
59+
export const getAllDiscourseNodeColors = (
60+
nodeTypes: DiscourseNode[],
61+
): Array<{
62+
nodeType: DiscourseNode;
63+
colors: { backgroundColor: string; textColor: string };
64+
}> => {
65+
return nodeTypes.map((nodeType, index) => ({
66+
nodeType,
67+
colors: getNodeTagColors(nodeType, index),
68+
}));
69+
};

0 commit comments

Comments
 (0)