Add WireframeDslParser for markdown-ui-dsl wireframe diagrams#135
Add WireframeDslParser for markdown-ui-dsl wireframe diagrams#135jongalloway merged 5 commits intomainfrom
Conversation
Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com> Agent-Logs-Url: https://github.com/jongalloway/DiagramForge/sessions/944314c7-50c9-4e41-9fb1-1781e58761f5
…e variable names Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com> Agent-Logs-Url: https://github.com/jongalloway/DiagramForge/sessions/944314c7-50c9-4e41-9fb1-1781e58761f5
…, docs - Add WireframePalette derived from theme's BackgroundColor, TextColor, SubtleTextColor, and AccentColor so all 25 built-in themes work - Fix inline badge parsing: '(( Badge )) trailing text' now emits badge + text wrapped in an implicit row for side-by-side rendering - Remove diagram.Title from wireframe parser (use ::: HEADER ::: instead) - Restructure E2E fixtures into 3 feature-focused wireframes: wireframe-form (default), wireframe-dashboard (dracula), wireframe-showcase (catppuccin-latte) - Update PRD with Wireframe DSL scope (section 5.3) - Update README: gallery thumbnails, Wireframe DSL section with component syntax table, 'If You Want This' entry, link to markdown-ui-dsl - Update Build-Gallery.ps1 wireframe label handling
There was a problem hiding this comment.
Pull request overview
Adds first-class support for “wireframe” diagrams by introducing a dedicated Wireframe DSL parser, a custom wireframe layout pass, and bespoke SVG rendering for wireframe UI components—integrated into the default DiagramRenderer pipeline and documented via PRD/README + snapshot fixtures.
Changes:
- Introduces
WireframeDslParser(SyntaxId = "wireframe") with unit tests and new E2E fixtures/snapshots. - Adds a wireframe-specific layout implementation (
DefaultLayoutEngine.Wireframe.cs) and dispatch fromDefaultLayoutEngine. - Extends rendering to support wireframe nodes and suppress wireframe containment edges from SVG output.
Reviewed changes
Copilot reviewed 13 out of 16 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/DiagramForge/Parsers/Wireframe/WireframeDslParser.cs |
New parser for markdown-ui-dsl-inspired wireframes; emits containment edges and node metadata. |
src/DiagramForge/Layout/DefaultLayoutEngine.cs |
Adds wireframe layout dispatch in the main layout pipeline. |
src/DiagramForge/Layout/DefaultLayoutEngine.Wireframe.cs |
New multi-pass wireframe box-model layout (leaf sizing, container sizing, stretch, positioning). |
src/DiagramForge/Rendering/SvgNodeWriter.cs |
Adds wireframe rendering dispatch and component renderers. |
src/DiagramForge/Rendering/SvgRenderer.cs |
Suppresses wireframe:containment edges from both edge render passes. |
src/DiagramForge/DiagramRenderer.cs |
Registers WireframeDslParser in the default parser set. |
tests/DiagramForge.Tests/Parsers/WireframeDslParserTests.cs |
Adds comprehensive unit tests for wireframe parsing + render smoke tests. |
tests/DiagramForge.E2ETests/Fixtures/wireframe-*.input/.expected.svg |
Adds wireframe snapshot fixtures/baselines. |
doc/prd.md |
Documents Wireframe DSL scope and selection guidance. |
README.md |
Documents Wireframe DSL and adds gallery entries/examples. |
scripts/Build-Gallery.ps1 |
Updates gallery labeling to handle wireframe fixtures. |
| private static void AppendWireframeNode(StringBuilder sb, Node node, string kind, Theme theme) | ||
| { | ||
| var p = WireframePalette.FromTheme(theme); | ||
|
|
There was a problem hiding this comment.
WireframePalette.FromTheme(theme) is recomputed for every wireframe node render. Since it performs many ColorUtils.Blend calls, this can add noticeable overhead for larger wireframes. Consider computing the palette once per render/theme and reusing it across nodes (e.g., cache by Theme instance, or thread it through from the renderer).
| if (diagram.Nodes.Count == 0) | ||
| return; | ||
|
|
||
| if (!diagram.Nodes.TryGetValue(Parsers.Wireframe.WireframeDslParser.RootNodeId, out var root)) |
There was a problem hiding this comment.
RootNodeId is referenced as Parsers.Wireframe.WireframeDslParser.RootNodeId, but there is no Parsers namespace in scope here. This won’t compile unless you fully-qualify it (e.g., DiagramForge.Parsers.Wireframe.WireframeDslParser.RootNodeId) or add a using DiagramForge.Parsers.Wireframe; and reference WireframeDslParser.RootNodeId.
| if (!diagram.Nodes.TryGetValue(Parsers.Wireframe.WireframeDslParser.RootNodeId, out var root)) | |
| if (!diagram.Nodes.TryGetValue(DiagramForge.Parsers.Wireframe.WireframeDslParser.RootNodeId, out var root)) |
|
|
||
| badgeLabel = line[2..closeIdx].Trim(); | ||
| trailingText = line[(closeIdx + 2)..].Trim(); | ||
| return badgeLabel.Length > 0; |
There was a problem hiding this comment.
TrySplitInlineBadge will treat a standalone badge with trailing whitespace (e.g., "(( Info )) ") as an inline badge row, creating an extra implicit row and changing layout. After trimming the substring, consider returning false when trailingText is empty/whitespace so standalone badges remain standalone even with trailing spaces.
| return badgeLabel.Length > 0; | |
| // After trimming, require non-empty trailing text so standalone badges | |
| // with only whitespace after the closing delimiters are not treated as inline. | |
| return badgeLabel.Length > 0 && trailingText.Length > 0; |
|
@copilot apply changes based on the comments in this thread |
…fix inline badge whitespace edge case Co-authored-by: jongalloway <68539+jongalloway@users.noreply.github.com> Agent-Logs-Url: https://github.com/jongalloway/DiagramForge/sessions/04fdb593-36fa-43ae-a853-641cef1743a0
Applied all three changes in commit a7c207b:
|
Adds a dedicated
WireframeDslParser(SyntaxId = "wireframe") that parses a subset of the markdown-ui-dsl spec into SVG wireframe mockups, keeping it separate from the Conceptual DSL per the PRD category distinction.Parser
First non-empty line must be
wireframeorwireframe: <title>. Supported syntax:Containers (
||| COLUMN |||,=== ROW ===,::: CARD :::,::: HEADER :::,::: FOOTER :::) are closed with--- END ---and nest arbitrarily. Layout-only containment edges (wireframe:containment) are suppressed from SVG output.Layout (
DefaultLayoutEngine.Wireframe.cs)Three-pass recursive box model:
Rendering (
SvgNodeWriter.cs)Dedicated
AppendWireframeNodedispatch with grayscale wireframe palette. Each component type has its own renderer: filled rounded-rect buttons, outlined input fields with placeholder text, checkbox squares with tick marks, radio circles with center dot, pill toggles, dropdowns with chevron+separator, tab bars with active highlight, badge pills, image placeholders with diagonal cross lines, and plain/bold text at heading-appropriate sizes.Files
Parsers/Wireframe/WireframeDslParser.csLayout/DefaultLayoutEngine.Wireframe.csRendering/SvgNodeWriter.csRendering/SvgRenderer.cswireframe:containmentedges in both render passesDiagramRenderer.csWireframeDslParserin default constructorLayout/DefaultLayoutEngine.csTryLayoutWireframeDiagramdispatchTests/Parsers/WireframeDslParserTests.csE2ETests/Fixtures/wireframe-*.input/.expected.svg📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.