Skip to content

Conversation

@trangdoan982
Copy link
Collaborator

@trangdoan982 trangdoan982 commented Nov 14, 2025

https://www.loom.com/share/18e6cc45d59640479091d9722ca846de?focus_title=1&muted=1&from_recorder=1

Summary by CodeRabbit

  • New Features

    • Canvas nodes now support selectable font size and font family with updated default typography.
    • Text measurement and layout adapt dynamically to chosen typography for better rendering.
  • UI Changes

    • The canvas side panel behavior and extension point for sharing/styling has been updated to a new share-oriented panel.
  • Defaults

    • New default style values introduced for consistent text sizing and spacing.

@linear
Copy link

linear bot commented Nov 14, 2025

@supabase
Copy link

supabase bot commented Nov 14, 2025

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@trangdoan982
Copy link
Collaborator Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

✅ Actions performed

Full review triggered.

1 similar comment
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2025

📝 Walkthrough

Walkthrough

This pull request updates the Tldraw canvas UI to replace the StylePanel with SharePanel for discourse-specific tools, and adds dynamic font styling support throughout the discourse node system by introducing configurable size and fontFamily properties that propagate through shape rendering, sizing calculations, and text measurement utilities.

Changes

Cohort / File(s) Summary
UI Panel Replacement
apps/obsidian/src/components/canvas/TldrawViewComponent.tsx
Replaces StylePanel override with SharePanel; updates rendering logic to show DiscourseToolPanel when discourse tools are selected, otherwise DefaultSharePanel; updates tool-selection flag names from isDiscourseNodeSelected to isDiscourseNodeToolSelected and similar for relation tool.
Shape Typography Support
apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx
Adds size and fontFamily props to DiscourseNodeShape and DiscourseNodeUtil with defaults ("s" and "draw"); implements dynamic font sizing and family application in title and node-type text rendering based on configured style values.
Style Constants
apps/obsidian/src/constants.ts
Introduces TEXT_PROPS, FONT_SIZES (keyed by TLDefaultSizeStyle), and DEFAULT_STYLE_PROPS exports; adds TLDefaultSizeStyle import from tldraw.
Node Size Calculation
apps/obsidian/src/utils/calcDiscourseNodeSize.ts
Extends CalcNodeSizeParams with optional size and fontFamily fields; destructures these values with defaults ("s" and "draw") and propagates them to measureNodeText.
Text Measurement
apps/obsidian/src/utils/measureNodeText.ts
Adds size and fontFamily parameters with defaults; replaces static font-size constants with dynamic values computed from FONT_SIZES and FONT_FAMILIES; applies computed fontFamily to text elements and scales subtitle fontSize to 0.75× title fontSize.

Sequence Diagram(s)

sequenceDiagram
    participant Shape as DiscourseNodeShape
    participant Calc as calcDiscourseNodeSize
    participant Measure as measureNodeText
    participant Render as Text Rendering

    Shape->>Calc: pass size, fontFamily
    Calc->>Measure: propagate size, fontFamily
    Measure->>Measure: compute fontSize from FONT_SIZES<br/>compute fontFamily from FONT_FAMILIES
    Measure->>Render: apply computed fontSize & fontFamily<br/>title: fontSize | subtitle: fontSize × 0.75
    Render->>Render: measure & layout text with styles
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Points requiring attention:
    • Verify the font scaling logic in measureNodeText (subtitle at 0.75× is a fixed ratio; confirm this is intentional across all size variants)
    • Confirm FONT_SIZES and FONT_FAMILIES mappings are complete and match Tldraw's available sizes/families
    • Check that the SharePanel selection logic (isDiscourseNodeToolSelected and isDiscourseRelationToolSelected) correctly replaces the prior isDiscourseNodeSelected semantics
    • Ensure backward compatibility: existing nodes without explicit size/fontFamily props properly receive defaults in all code paths

Possibly related PRs

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title '[ENG-872] Add ability to change font style and sizing for dn' directly and clearly summarizes the main changes: adding font style and sizing customization support for discourse nodes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
apps/obsidian/src/utils/measureNodeText.ts (1)

49-49: Extract magic number 0.75 to a named constant.

The subtitle font size multiplier 0.75 appears in multiple places (lines 49, 89, 298) as a magic number. This makes the relationship between title and subtitle sizing less explicit.

Extract to a named constant for clarity and maintainability:

+const SUBTITLE_FONT_SIZE_RATIO = 0.75;
+
 export const measureNodeText = ({
   title,
   subtitle,
   size = "s",
   fontFamily = "draw",
 }: {
   title: string;
   subtitle: string;
   size?: TLDefaultSizeStyle;
   fontFamily?: TLDefaultFontStyle;
 }): { w: number; h: number } => {
   const fontSize = FONT_SIZES[size];
   const fontFamilyValue = FONT_FAMILIES[fontFamily];
-  const subtitleFontSize = fontSize * 0.75;
+  const subtitleFontSize = fontSize * SUBTITLE_FONT_SIZE_RATIO;

Apply the same constant in DiscourseNodeShape.tsx at line 298.

Also applies to: 89-89, 298-298

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6721a47 and 6b7db03.

📒 Files selected for processing (5)
  • apps/obsidian/src/components/canvas/TldrawViewComponent.tsx (2 hunks)
  • apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx (7 hunks)
  • apps/obsidian/src/constants.ts (2 hunks)
  • apps/obsidian/src/utils/calcDiscourseNodeSize.ts (2 hunks)
  • apps/obsidian/src/utils/measureNodeText.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/obsidian/src/constants.ts
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/obsidian/src/constants.ts
🔇 Additional comments (4)
apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx (2)

39-41: Good: Font styling props properly integrated.

The addition of size and fontFamily props to the DiscourseNodeShape is well-structured with appropriate types, prop definitions, and sensible defaults. The props flow correctly through the shape lifecycle.

Also applies to: 62-63, 74-75


273-274: Verify tldraw exports for FONT_SIZES and FONT_FAMILIES.

Same import verification issue as in measureNodeText.ts. This file imports FONT_SIZES and FONT_FAMILIES from tldraw.

See verification request in measureNodeText.ts review. Ensure consistent import source across all files.

apps/obsidian/src/utils/calcDiscourseNodeSize.ts (1)

10-10: No issues found — "draw" is a valid TLDefaultFontStyle value.

The valid TLDefaultFontStyle values in tldraw 3.14.2 are: 'draw', 'mono', 'sans', 'serif'. The code correctly uses "draw" as the default font family, so no changes are required.

apps/obsidian/src/utils/measureNodeText.ts (1)

13-18: The review comment is based on incorrect reasoning and should be disregarded.

The web search confirmed that tldraw 3.14.2 does export FONT_SIZES and FONT_FAMILIES. The codebase investigation reveals that while constants.ts does define a local FONT_SIZES at line 95, it is not exported and is not used anywhere—making it unused dead code. The files that use FONT_SIZES (measureNodeText.ts and DiscourseNodeShape.tsx) correctly import it from tldraw with no ambiguity. The import statement in measureNodeText.ts is valid and correct.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
apps/obsidian/src/constants.ts (1)

85-105: Remove unused local FONT_SIZES and stale TODO / SVG font comments.

This block introduces:

  • A local FONT_SIZES: Record<TLDefaultSizeStyle, number>
  • A TODO pointing to an old tldraw PR
  • Commented SVG_FONT_FAMILY notes

Given that:

  • FONT_SIZES here is not exported or used in this file
  • Other code (e.g. measureNodeText.ts) already imports FONT_SIZES and FONT_FAMILIES directly from tldraw

this local definition and related comments are dead/duplicated state and a likely source of confusion about the single source of truth for font sizes.

Recommend deleting the local FONT_SIZES, the TODO, and the commented SVG_FONT_FAMILY block, and then removing the now‑unused TLDefaultSizeStyle import.

Example diff:

-import { TLDefaultSizeStyle } from "tldraw";
+// import { TLDefaultSizeStyle } from "tldraw"; // (no longer needed if local FONT_SIZES is removed)

@@
-// TODO REPLACE WITH TLDRAW DEFAULTS
-// https://github.com/tldraw/tldraw/pull/1580/files
-
-const TEXT_PROPS = {
+const TEXT_PROPS = {
   lineHeight: 1.35,
   fontWeight: "normal",
   fontVariant: "normal",
   fontStyle: "normal",
   padding: "0px",
   maxWidth: "auto",
 };
-const FONT_SIZES: Record<TLDefaultSizeStyle, number> = {
-  m: 25,
-  l: 38,
-  xl: 48,
-  s: 16,
-};
-// // 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 = `"Inter", "sans-serif"`;

Then remove the TLDefaultSizeStyle import entirely once the local FONT_SIZES is gone.

apps/obsidian/src/components/canvas/TldrawViewComponent.tsx (1)

15-15: SharePanel override cleanly routes to DiscourseToolPanel; verify it now exposes font controls.

The new SharePanel override:

  • Correctly uses useTools / useIsToolSelected inside the component, matching tldraw’s hooks patterns.
  • Shows DiscourseToolPanel when either discourse tool is active, and otherwise defers to <DefaultSharePanel />, so default share UI isn’t lost.

This looks structurally sound. The remaining question is UX/functionality: given the PR goal (change font size and style for discourse nodes), please confirm that DiscourseToolPanel now exposes controls wired to DiscourseNodeShape’s size and fontFamily props (and triggers any necessary node‑size recalculation) so users actually gain font editing capabilities via this panel.

Also applies to: 380-397

apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx (1)

156-171: Ensure font changes also trigger node size recalculation (not just image changes).

In loadNodeData, the call to calcDiscourseNodeSize is guarded by didImageChange, so the size recalculation currently only runs when the key image changes:

if (didImageChange) {
  const { w, h } = await calcDiscourseNodeSize({ ... , size: shape.props.size, fontFamily: shape.props.fontFamily });
  // ...
}

If size or fontFamily are changed via the UI without any image change, this effect alone won’t recalculate w/h, which could leave text clipped or cramped unless some other code path (e.g. in DiscourseToolPanel) explicitly calls calcDiscourseNodeSize and updates the shape dimensions.

Please confirm that:

  • The code that updates shape.props.size / shape.props.fontFamily also recomputes w/h (e.g. by calling calcDiscourseNodeSize), or
  • You extend this effect (or add another) so that font‑only changes result in a size recalculation, including for nodes without images.

If no such path exists yet, adding a dedicated recalculation triggered by font props would be important for UX.

Also applies to: 222-246, 260-271

🧹 Nitpick comments (1)
apps/obsidian/src/utils/measureNodeText.ts (1)

13-18: Dynamic font size/family measurement is aligned with the rendered node; consider a small defensive fallback.

  • Importing FONT_SIZES / FONT_FAMILIES and threading size / fontFamily through measureNodeText gives you consistent measurement with DiscourseNodeShape’s runtime styling.
  • Using subtitleFontSize = fontSize * 0.75 and matching the opacity-80 behavior for the subtitle keeps the visual + measured layout in sync.

Given the TS types, size and fontFamily should always be valid keys. If you want extra robustness against corrupted data, you could add a small fallback:

-  const fontSize = FONT_SIZES[size];
-  const fontFamilyValue = FONT_FAMILIES[fontFamily];
+  const fontSize = FONT_SIZES[size] ?? FONT_SIZES.s;
+  const fontFamilyValue = FONT_FAMILIES[fontFamily] ?? FONT_FAMILIES.draw;

Not required, but it would harden the function against unexpected values.

Also applies to: 33-35, 39-46, 47-50, 77-93

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6721a47 and 6b7db03.

📒 Files selected for processing (5)
  • apps/obsidian/src/components/canvas/TldrawViewComponent.tsx (2 hunks)
  • apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx (7 hunks)
  • apps/obsidian/src/constants.ts (2 hunks)
  • apps/obsidian/src/utils/calcDiscourseNodeSize.ts (2 hunks)
  • apps/obsidian/src/utils/measureNodeText.ts (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/obsidian/src/constants.ts
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/obsidian/src/constants.ts
🔇 Additional comments (4)
apps/obsidian/src/constants.ts (2)

83-84: Auto‑save delay remains consistent with existing behavior.

Keeping DEFAULT_SAVE_DELAY at 500ms aligns with the debounce logic in TldrawViewComponent and looks fine.


106-112: DEFAULT_STYLE_PROPS is reasonable as a central typography default.

The structure (spreading TEXT_PROPS then overriding fontSize, fontFamily, width, and padding) is clear and gives you a single default source for text styling. Looks good, assuming downstream components (e.g. DiscourseNodeShape) either use these values or are deliberately diverging.

apps/obsidian/src/utils/calcDiscourseNodeSize.ts (1)

10-19: Plumbing size and fontFamily through node size calculation looks correct.

  • Extending CalcNodeSizeParams with size?: TLDefaultSizeStyle and fontFamily?: TLDefaultFontStyle, and defaulting them to "s" / "draw" in the function signature, matches the new DiscourseNodeShape defaults.
  • Forwarding these into measureNodeText is exactly what’s needed so typography choices influence measured width/height.

No issues spotted here; the function remains backward‑compatible while enabling dynamic typography.

Also applies to: 30-41

apps/obsidian/src/components/canvas/shapes/DiscourseNodeShape.tsx (1)

9-15: Wiring size / fontFamily through shape props and rendering looks correct.

  • Extending DiscourseNodeShape with size: TLDefaultSizeStyle and fontFamily: TLDefaultFontStyle, backed by DefaultSizeStyle / DefaultFontStyle in static props, matches tldraw’s style patterns.
  • Defaults of "s" and "draw" line up with the defaults used in calcDiscourseNodeSize and measureNodeText.
  • Using FONT_SIZES / FONT_FAMILIES at render time and applying fontSize / fontFamily via inline styles to the title and the 0.75x subtitle keeps the visual output consistent with measurement.

This part of the integration looks solid.

Also applies to: 39-42, 62-64, 74-76, 273-275, 286-303

@trangdoan982 trangdoan982 force-pushed the eng-872-add-ability-to-change-font-style-and-sizing-for-dn branch from 673f4fe to 7192937 Compare November 18, 2025 23:01
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdroidian mdroidian self-requested a review November 24, 2025 00:53
Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed this comment in my review, so re-reviewed.

Original review video:
#551 (review)

title: file.basename,
nodeTypeId: nodeTypeId,
size: "s",
fontFamily: "draw",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default needs to be Sans throughout. This was requested when we did this in Roam. Double check that when a new node is added to the canvas or created for the firs time that is defaults to sans. This was a issue in Roam.

It is also default m in Roam, but we can leave that until we consolidate further.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, default should be s for nodes. Relations might be m
#432

@trangdoan982
Copy link
Collaborator Author

next action: address PR review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants