You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
memos/docs/issues/2026-03-23-memo-detail-outline/definition.md

3.2 KiB

Background & Context

The MemoDetail page (web/src/pages/MemoDetail.tsx) renders a memo's full content with a right sidebar (MemoDetailSidebar) on desktop. The sidebar currently shows share controls, timestamps, property badges (links, to-do, code), and tags. Memo content is rendered via react-markdown with custom heading components (h1h6) in MemoContent/markdown/Heading.tsx. The page already has hash-based scroll-to-element infrastructure for comments (lines 3943 of MemoDetail.tsx).

Issue Statement

When viewing a memo with structured headings, there is no outline or table of contents in the MemoDetail sidebar, so readers cannot see the document structure at a glance or jump to specific sections. Heading elements rendered by the Heading component do not have id attributes, preventing any anchor-based navigation to them.

Current State

  • web/src/pages/MemoDetail.tsx (93 lines) — MemoDetail page. Hash-based scrollIntoView logic exists at lines 3943 but only targets comment elements. The sidebar is rendered at lines 8286 as <MemoDetailSidebar>.
  • web/src/components/MemoDetailSidebar/MemoDetailSidebar.tsx (109 lines) — Desktop sidebar. Contains sections: Share (lines 5865), Created-at (lines 6776), Properties (lines 7889), Tags (lines 91102). Uses a reusable SidebarSection helper (lines 2432). No outline section exists.
  • web/src/components/MemoDetailSidebar/MemoDetailSidebarDrawer.tsx (36 lines) — Mobile drawer wrapper for the sidebar.
  • web/src/components/MemoContent/markdown/Heading.tsx (30 lines) — Renders h1h6 with Tailwind classes. Does not generate id attributes on heading elements.
  • web/src/components/MemoContent/index.tsx (157 lines) — ReactMarkdown renderer. Maps h1h6 to the Heading component (lines 72101). No rehype-slug or equivalent plugin is installed.
  • web/src/utils/markdown-manipulation.ts (143 lines) — Contains fromMarkdown() MDAST parsing with GFM extensions. Used for task extraction; no heading extraction exists.

Non-Goals

  • Redesigning the overall MemoDetail layout or sidebar structure beyond adding the outline section.
  • Supporting outline for the mobile drawer — the outline section should appear in the desktop sidebar only for now.
  • Adding active heading highlighting on scroll (scroll-spy behavior).
  • Supporting outline in the memo list/timeline view (compact mode).
  • Changing the existing heading visual styles in the content area.

Open Questions

  • Which heading levels to include in the outline? (default: h1h4, matching user request)
  • How to generate slug IDs — install rehype-slug or custom implementation? (default: lightweight custom slug generation in the Heading component to avoid a new dependency)
  • Should the outline section be hidden when no headings exist? (default: yes, hide entirely like Properties/Tags sections)
  • Should duplicate heading text produce unique slugs (e.g. my-heading, my-heading-1)? (default: yes, append numeric suffix for duplicates)

Scope

M — Touches 34 files (Heading component, MemoDetailSidebar, possibly a new outline component, and a slug utility). Existing patterns (SidebarSection, hash scrolling) apply directly. No new subsystem or novel approach required.