T-I4V6-sdf-entity-body-viewer
State: closed/done · Impact: high · Complexity: small
The SDF dashboard renders entity and task bodies with marked plus DOMPurify into v-html,
while the package already depends on obsidian-md. This task routes those bodies through
MdViewer, deletes the second markdown implementation, and wires @sksizer/markdown-ui into the
file:-linked SDF host so the later edit wave has a layer to build on.
| Location | Role today |
|---|---|
solutions/ontological/desktop/src-nuxt/app/components/entities/MarkdownBody.vue | marked.parse then DOMPurify.sanitize into v-html; 100 lines of :deep() CSS |
solutions/ontological/desktop/src-nuxt/app/components/entities/MarkdownBody.stories.ts | Storybook story over MarkdownBody |
solutions/ontological/desktop/src-nuxt/app/components/entities/EntityDetailPanel.vue | Mounts MarkdownBody for detail.body |
solutions/ontological/desktop/src-nuxt/app/pages/model/tasks/[id].vue | Mounts MarkdownBody for detail.body |
solutions/ontological/desktop/src-nuxt/package.json | marked, dompurify; @sksizer/obsidian-md and @determined/ui by file:; overrides for workspace:* transitives; unified, extend, debug devDependencies for pre-bundling |
solutions/ontological/desktop/src-nuxt/nuxt.config.ts | Extends app-frame, suspenders, system-graph, @determined/ui; vite.optimizeDeps.include; allowImportingTsExtensions |
solutions/ontological/desktop/package.json | Root overrides mapping @sksizer/* to file: paths |
solutions/ontological/desktop/bun.lock | Isolated lockfile, checked by .github/workflows/lockfile-drift.yml |
.github/workflows/sdf-ci.yml | SDF CI |
Proposed
Section titled “Proposed”SDF nuxt.config.ts extends @sksizer/markdown-ui between @sksizer/app-frame and the
experience layers. MarkdownBody.vue stays as the SDF-local wrapper but its body is
<MdViewer :source="source" highlight />: the marked and DOMPurify imports, the v-html and
the :deep() CSS are deleted, so both call sites and the story keep working. marked and
dompurify leave src-nuxt/package.json; the layer and its workspace:* transitives
(@sksizer/obsidian-editor, @sksizer/markdown-util) are wired by file: with matching
overrides, and bun.lock is regenerated in the same PR.
Approach
Section titled “Approach”src-nuxt/package.json: add@sksizer/markdown-uibyfile:; addfile:entries andoverridesfor everyworkspace:*dependency the layer declares that is not already mapped (@sksizer/obsidian-editor,@sksizer/markdown-util); mirror theoverridesin the rootsolutions/ontological/desktop/package.json; deletemarkedanddompurify.src-nuxt/nuxt.config.ts: add@sksizer/markdown-uitoextends; addvite.resolve.dedupe: ['vue', '@codemirror/state', '@codemirror/view', '@lezer/common'].MarkdownBody.vue: replace the script and template withMdViewer(highlighton,mathandmermaiddefault off); delete the scoped:deep()styles.cd solutions/ontological/desktop && bun install; commitbun.lock;bun install --frozen-lockfilepasses.- Verify:
moon run sdf:check sdf:test;bun run buildinsrc-nuxt(CJS and transpile problems surface in build, not dev);nuxi analyzeshows nomarkedchunk and the layer plus engines under 150 KB gzip in the main chunk; open a task whose body has a fence, a table and a wikilink in light and dark and attach screenshots;moon run :check :test --affected. - Flip the SDF row of the duplicates ledger in
docs/LIBRARIES.mdto resolved.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
solutions/ontological/desktop/package.json | modify | Every overridden package as a direct file: dep AND an override, byte-identical specifiers, in the manifest beside bun.lock |
solutions/ontological/desktop/src-nuxt/package.json | modify | Delete marked, dompurify; declare none of the overridden packages (a member declaration mints a second, dependency-less identity) |
solutions/ontological/desktop/src-nuxt/nuxt.config.ts | modify | Extend the layer between the experiences and @determined/ui |
solutions/ontological/desktop/src-nuxt/app/components/entities/MarkdownBody.vue | delete | Nothing left to be once the body is MdViewer |
solutions/ontological/desktop/src-nuxt/app/components/entities/MarkdownBody.stories.ts | delete | Replaced by EntityBody.stories.ts over the viewer |
solutions/ontological/desktop/src-nuxt/app/components/entities/EntityBody.stories.ts | new | Stories over MdViewer with the call sites’ options |
solutions/ontological/desktop/src-nuxt/app/utils/entityBodyRenderOptions.ts | new | Shared render options (highlight, missing resolver) and the read-only task-checkbox override |
solutions/ontological/desktop/src-nuxt/app/components/entities/EntityDetailPanel.vue | modify | Mounts MdViewer directly, imported by path for Storybook |
solutions/ontological/desktop/src-nuxt/app/pages/model/tasks/[id].vue | modify | Same |
solutions/ontological/desktop/src-nuxt/.storybook/* | modify | Layer stylesheets and a vue dedupe, since this Storybook is not Nuxt-aware |
solutions/ontological/desktop/bun.lock | modify | Regenerated incrementally |
docs/LIBRARIES.md | modify | Duplicates ledger row for the SDF render site flips to resolved |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
solutions/ontological/desktop/src-nuxt/package.jsonandsolutions/ontological/desktop/bun.lockcontain nomarkedordompurifyentry. - AC-2:
MarkdownBody.vueis deleted. Both call sites mountMdViewerdirectly, with nov-htmland no markdown:deep()CSS anywhere in the app. - AC-3:
EntityDetailPanel.vueandpages/model/tasks/[id].vueimportMdViewerby path — SDF’s Storybook is plain Vite with no Nuxt auto-import, so an implicit component renders as nothing there — andEntityBody.stories.tsreplacesMarkdownBody.stories.ts(moon run sdf:checkpasses). - AC-4:
bun install --frozen-lockfilepasses insolutions/ontological/desktop; the lockfile-drift workflow is green. - AC-5:
bun run buildinsrc-nuxtpasses andnuxi analyzelists nomarkedchunk. The gzip budget is NOT met and is not chased here: the entry grew past 150 KB gzip, which the engine-perf track owns (B-1JZA). - AC-6: Light and dark screenshots of a task body with a fence, a table and a wikilink are attached to the PR.
- AC-7:
moon run sdf:testpasses. - AC-8: A read-only body renders no live affordance: task checkboxes are
disabled, and wikilinks the app cannot resolve carry nohrefand thewikilink-missingclass.
Out of scope
Section titled “Out of scope”- Editing entity bodies (T-WUVP-sdf-entity-body-swap-write).
- The suspenders skill body (T-UQCN-suspenders-skill-body-viewer); it inherits the layer this task wires.
- Resolving wikilinks in entity bodies to dashboard routes; links render as
missingin this wave.
Dependencies
Section titled “Dependencies”- T-A0HT-md-ui-layer-skeleton supplies
MdViewerand the layer’sfile:-host guidance. - Gate: the sanitize and routing fixes from T-8H57-obsidian-md-review-bug-triage land before this viewer ships.
D-7VMX-markdown-ecosystem-strategyd.10:markedanddompurifyare deleted here.- S-0010-design-language-consumption: viewer colours ride
--d-*through the layer bridge.
Discovery context
Section titled “Discovery context”Member of milestone M-931L; wave 2a of D-K3EM-markdown-editor-chrome-and-plugin-environment.