Skip to content

T-98EU-md-ui-toolbar-insert-frontmatter

State: closed/done · Impact: high · Complexity: medium

The engine now has one typed command list, but no product has a toolbar, an insert menu, a frontmatter panel or a palette entry over it. This task adds the command-driven chrome to the markdown-ui layer: MdToolbar, MdInsertMenu, MdFrontmatterPanel, useMarkdownCommands, the chord and icon utilities, and the ⌘K palette projection.

LocationRole today
packages/ts/ui/app/components/DToolbar.vueToolbar container primitive
packages/ts/ui/app/components/DIconButton.vueIcon button primitive the toolbar buttons use
packages/ts/ui/app/components/DKbd.vueKeyboard hint chip for tooltips and menu rows
packages/ts/ui/app/components/DMenu.vueMenu body used inside UPopover — the sanctioned dropdown idiom
packages/ts/app-frame/app/composables/useContributions.ts#CommandContributionPalette entry shape the projection matches structurally; the layer never imports app-frame
packages/ts/app-frame/app/utils/chords.tsPortable chord grammar; T-6OI8-ui-extract-anchored-position-and-chords moves it to @determined/ui
solutions/determined/experiences/notes/app/components/NotesPropertiesPanel.vue#inferKindKind inference (with dateParts) the frontmatter panel generalises

The layer, MdSurface, MdModeToggle and the plugin registry come from T-A0HT-md-ui-layer-skeleton; commands, commandStates, runCommand and chordLabel from the engine (T-EXQ7-md-engine-command-catalogue).

PieceDesign
MdToolbarFixed bar driven by the catalogue and commandStates: groups of DIconButton (size="xs", ghost intent) with aria-pressed from active, disabled from enabled, UTooltip label plus DKbd chord hint; dropdowns (heading level, MdInsertMenu, more actions) as UPopover + DMenu; a ResizeObserver collapses overflowing groups into a trailing DMenu; MdModeToggle renders in #trailing. Layout is MD_TOOLBAR_DEFAULT_LAYOUT, an ordered list of command ids per group, overridable by prop and extended by MarkdownPlugin.toolbar entries
MdInsertMenuGrouped menu from commands.filter(group === 'insert') — the same subset the engine’s slash source lists, so the two cannot drift; an “Attachment…” item opens a hidden file input and calls insertAttachments, hidden when provider.saveAttachment is absent
MdFrontmatterPanelCollapsible “Properties (n)” over the raw YAML string: read-only rows typed by inferKind/dateParts, which move to app/utils/mdFrontmatter.ts; the default slot lets a host substitute its own panel (notes keeps NotesPropertiesPanel)
useMarkdownCommands(view, extra?){ commands, states, run } — the engine catalogue merged with MarkdownPlugin.commands from the registry
projectMarkdownCommands(commands, run, { titlePrefix: 'Markdown: ' })Structurally a CommandContribution[] for the ⌘K palette; a shell or product plugin registers it and routes run to useActiveMarkdownSurface() — no layer dependency on app-frame
app/utils/mdChords.tsChord labels for DKbd hints over the chord utilities @determined/ui gains in T-6OI8-ui-extract-anchored-position-and-chords
app/utils/mdIcons.tsLiteral map of Lucide icon classes per command id (literal so Tailwind scans them) and a renderIcon(name) factory MdSurface hands to the engine’s autocomplete icon hook

MdSurface gains the toolbar: boolean | 'fixed' | 'floating' and frontmatter-panel props, the #toolbar-leading / #toolbar-trailing / #frontmatter slots, and run(id) on its exposed API.

  1. Write packages/ts/markdown-ui/tests/useMarkdownCommands.test.ts first: merge order (plugin commands after catalogue, id collision throws), states recompute, run dispatches on the view.
  2. Write packages/ts/markdown-ui/tests/mdFrontmatter.test.ts by porting the inferKind / dateParts cases from the notes panel; write mdFrontmatter.ts.
  3. Write packages/ts/markdown-ui/tests/mdToolbar.test.ts (happy-dom): buttons render per MD_TOOLBAR_DEFAULT_LAYOUT; aria-pressed mirrors a stubbed states; a click calls run with the command id; every id in the layout resolves in the catalogue.
  4. Implement mdToolbarLayout.ts, mdIcons.ts, mdChords.ts, useMarkdownCommands.ts, projectMarkdownCommands (with a type-level test against a local copy of the CommandContribution interface).
  5. Implement MdToolbar.vue, MdInsertMenu.vue, MdFrontmatterPanel.vue with stories; wire the MdSurface props and slots.
  6. Add a toolbar playground page; moon run markdown-ui:check markdown-ui:test; bun run storybook:build; just ci-guards.
LocationKindChange
packages/ts/markdown-ui/app/components/MdToolbar.vuenewCatalogue-driven toolbar with overflow
packages/ts/markdown-ui/app/components/MdToolbar.stories.tsnewFixed and floating stories
packages/ts/markdown-ui/app/components/MdInsertMenu.vuenewInsert group menu with attachment input
packages/ts/markdown-ui/app/components/MdInsertMenu.stories.tsnewStory
packages/ts/markdown-ui/app/components/MdFrontmatterPanel.vuenewRead-only properties panel
packages/ts/markdown-ui/app/components/MdFrontmatterPanel.stories.tsnewStory
packages/ts/markdown-ui/app/components/MdSurface.vuenewCreated by T-A0HT-md-ui-layer-skeleton; gains toolbar and frontmatter wiring
packages/ts/markdown-ui/app/composables/useMarkdownCommands.tsnewMerge, states, run
packages/ts/markdown-ui/app/utils/mdChords.tsnewChord labels for hints
packages/ts/markdown-ui/app/utils/mdIcons.tsnewLiteral icon map, renderIcon factory
packages/ts/markdown-ui/app/utils/mdFrontmatter.tsnewinferKind, dateParts
packages/ts/markdown-ui/app/utils/mdToolbarLayout.tsnewMD_TOOLBAR_DEFAULT_LAYOUT, projectMarkdownCommands
packages/ts/markdown-ui/tests/mdToolbar.test.tsnewToolbar tests
packages/ts/markdown-ui/tests/useMarkdownCommands.test.tsnewMerge and run tests
packages/ts/markdown-ui/tests/mdFrontmatter.test.tsnewPorted kind-inference tests
packages/ts/markdown-ui/playground/app/pages/toolbar.vuenewToolbar over the fixture vault
  • AC-1: moon run markdown-ui:check markdown-ui:test passes with the three new suites.
  • AC-2: projectMarkdownCommands(...) is assignable to CommandContribution[] (type-level test over a local copy of the app-frame interface).
  • AC-3: every id in MD_TOOLBAR_DEFAULT_LAYOUT resolves to a command in the engine catalogue (asserted by iterating the exported layout in the toolbar test).
  • AC-4: the insert menu’s option ids equal the ids the engine slash source lists for the same compiled commands (both computed in the test from one command list).
  • AC-5: the “Attachment…” item is absent when the provider lacks saveAttachment and present with it.
  • AC-6: aria-pressed on the bold button follows states['format.bold'].active across a stubbed state flip.
  • AC-7: MdFrontmatterPanel renders “Properties (3)” and three typed rows for a three-key YAML fixture; the ported inferKind/dateParts cases pass.
  • AC-8: just ci-guards passes (icon classes literal, colors --d-* only) and bun run storybook:build succeeds with the three new stories.

Member of milestone M-931L; chrome step C5 of decision D-K3EM-markdown-editor-chrome-and-plugin-environment.

T-EXQ7-md-engine-command-catalogue


← Back to Tasks