Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions apps/roam/src/components/canvas/DgSubpageBreadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Screen-fixed breadcrumb + back bar for nested sub-pages. Real UI chrome, not
// a drawn shape: registered as the tldraw `HelperButtons` UI component (the
// slot under the page menu, verified visible in 2.4.6), composed with the
// default helper buttons rather than replacing them.
import React from "react";
import { DefaultHelperButtons, useEditor, useValue } from "tldraw";
import { enterPage, getLineage } from "./nestedPageNavigation";

const DgSubpageBreadcrumb = () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Several new functions omit explicit return types required by the repository style guide

The new breadcrumb components and navigation helpers are declared without explicit return types (for example the component declaration at apps/roam/src/components/canvas/DgSubpageBreadcrumb.tsx:9), which the repository style guide requires for all functions.
Impact: Contributors lose the guaranteed, self-documenting signatures the project standardises on, making accidental signature changes easier to miss.

Affected declarations and the rule

Root AGENTS.md → TypeScript Guidelines: "Use explicit return types for functions".

Missing return types in this PR:

  • DgSubpageBreadcrumb (apps/roam/src/components/canvas/DgSubpageBreadcrumb.tsx:9) and the go helper (:17)
  • NestedPageHelperButtons (apps/roam/src/components/canvas/DgSubpageBreadcrumb.tsx:109)
  • enterPage (apps/roam/src/components/canvas/nestedPageNavigation.ts:24)
  • DgSubpageUtil.readPreviewModel / component / indicator (apps/roam/src/components/canvas/DgSubpageUtil.tsx:269, :275, :707)

Existing code in the same area follows the rule (e.g. SyncModeMenuSwitchItem returns ReactElement in apps/roam/src/components/canvas/uiOverrides.tsx:85-96).

Suggested change
const DgSubpageBreadcrumb = () => {
const DgSubpageBreadcrumb = (): React.ReactElement | null => {
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

const editor = useEditor();
const chain = useValue("dg-subpage-breadcrumb", () => getLineage(editor), [
editor,
]);
// Root page (no dgNested.parentPageId): render nothing.
if (chain.length <= 1) return null;

const go = (id: string) => {
if (id !== editor.getCurrentPageId()) enterPage(editor, id);
};
const parent = chain[chain.length - 2];

return (
<div
style={{
pointerEvents: "all",
display: "flex",
alignItems: "center",
gap: 8,
margin: "6px 0 0 8px",
padding: "5px 10px",
background: "rgba(255,255,255,0.94)",
border: "1px solid #e3e5e9",
borderRadius: 9,
boxShadow: "0 1px 6px rgba(20,20,40,0.10)",
font: "13px var(--tl-font-sans, Inter, system-ui, sans-serif)",
backdropFilter: "blur(6px)",
maxWidth: "70vw",
overflow: "hidden",
width: "fit-content",
}}
Comment on lines +24 to +40

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 New canvas breadcrumb bar introduces its own colors and hand-rolled styling instead of the host app's design system

The nested sub-page breadcrumb bar is styled with a brand-new inline color/shadow palette (background: "rgba(255,255,255,0.94)"boxShadow/backdropFilter at apps/roam/src/components/canvas/DgSubpageBreadcrumb.tsx:24-40) rather than Tailwind classes or platform-native components, so the new UI looks like a separate visual language from the rest of the extension.
Impact: Users see canvas chrome that does not match Roam's look and feel, and future style changes have to be maintained twice.

Repository styling rules that this violates

apps/roam/AGENTS.md states: "Platform-native UI - use BlueprintJS 3 components and Tailwind CSS" and "Do not introduce arbitrary visual styling, new shading colors, background palettes, gradients, accent colors, border colors, or text colors unless the user explicitly asks for them." The root AGENTS.md adds "Use Tailwind CSS for styling where possible" and "When refactoring inline styles, use tailwind classes".

The breadcrumb container (DgSubpageBreadcrumb.tsx:24-40), the back button (DgSubpageBreadcrumb.tsx:48-58) and the crumb buttons (DgSubpageBreadcrumb.tsx:83-95) all hard-code hex colors (#e3e5e9, #f7f8fa, #3a3d42, #5b6bd6, #b9bdc4), a custom shadow and a blur filter. The same pattern is repeated in the portal shape chrome (apps/roam/src/components/canvas/DgSubpageUtil.tsx:409-427). Existing canvas UI in this repo composes tldraw UI primitives (TldrawUiButton, TldrawUiIcon in apps/roam/src/components/canvas/uiOverrides.tsx:97-116) or Tailwind classes instead.

Prompt for agents
The new nested-page UI chrome introduces a bespoke inline visual palette, which apps/roam/AGENTS.md forbids ("Do not introduce arbitrary visual styling, new shading colors, background palettes, gradients, accent colors, border colors, or text colors unless the user explicitly asks for them") and the root AGENTS.md asks for Tailwind/platform-native components. Rework DgSubpageBreadcrumb.tsx (container at lines 24-40, back button 48-58, crumb buttons 83-95) so the bar is built from tldraw UI primitives (e.g. TldrawUiButton, as uiOverrides.tsx already does) and/or Tailwind utility classes that reuse existing repo styling patterns, instead of hard-coded hex colors, custom box-shadow and backdrop-filter. Do the same for the portal header/body chrome in DgSubpageUtil.tsx (lines 409-468) where practical, keeping only the layout styles tldraw requires for absolutely positioned shape content.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

>
<button
title={`Back to ${parent.name}`}
onPointerDown={(e) => {
e.stopPropagation();
go(parent.id);
}}
style={{
border: "1px solid #dfe1e6",
background: "#f7f8fa",
borderRadius: 7,
padding: "3px 9px",
cursor: "pointer",
font: "inherit",
fontWeight: 600,
color: "#3a3d42",
whiteSpace: "nowrap",
}}
>
⬅ back
</button>
<div
style={{
display: "flex",
alignItems: "center",
flexWrap: "nowrap",
overflow: "hidden",
}}
>
{chain.map((page, i) => {
const isLast = i === chain.length - 1;
return (
<span
key={page.id}
style={{ display: "inline-flex", alignItems: "center", gap: 6 }}
>
{i > 0 ? <span style={{ color: "#b9bdc4" }}>▸</span> : null}
<button
onPointerDown={(e) => {
e.stopPropagation();
if (!isLast) go(page.id);
}}
style={{
border: "none",
background: "transparent",
padding: "2px 4px",
font: "inherit",
cursor: isLast ? "default" : "pointer",
color: isLast ? "#1d1d1f" : "#5b6bd6",
fontWeight: isLast ? 600 : 500,
maxWidth: 220,
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
{page.name}
</button>
</span>
);
})}
</div>
</div>
);
};

// The HelperButtons slot override: keep the default content (back-to-content
// etc.) and add the breadcrumb under it.
export const NestedPageHelperButtons = () => (
<>
<DefaultHelperButtons />
<DgSubpageBreadcrumb />
</>
);
Loading
Loading