Skip to content

Commit d210b77

Browse files
IEvangelistCopilot
andauthored
Fix Markdown table rendering (#1216)
Enable GFM rendering for the docs pipeline and add a Playwright regression test that validates common Markdown renders as semantic HTML on the contributor guide. Co-authored-by: David Pine <7679720+IEvangelist@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 7408cff commit d210b77

6 files changed

Lines changed: 87 additions & 79 deletions

File tree

.agents/skills/doc-writer/SKILL.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ When you introduce or change a custom component that is used by docs pages:
146146
- Prefer moving heavier shared logic into colocated `.ts` helpers when the `.astro` frontmatter becomes large or is duplicated across components.
147147
- Treat user-visible behavior, accessibility, and responsive behavior as part of the documentation contract, not as optional polish.
148148

149+
### Common Markdown syntax
150+
151+
Use the rendered examples in `src/frontend/src/content/docs/community/contributor-guide.mdx` as the canonical reference for common Markdown syntax. When adding tables, use padded pipes, a separator row with at least three hyphens per cell, and blank lines before and after the table:
152+
153+
```md
154+
| Feature | Description | Status |
155+
| ------- | ----------- | ------ |
156+
| Dashboard | Web-based monitoring | Available |
157+
```
158+
159+
Do not replace standard Markdown with ad hoc HTML unless a component or layout requirement cannot be expressed clearly in Markdown.
160+
149161
#### Aside (Callouts)
150162

151163
Prefer fenced `:::` callouts for tips, notes, cautions, and warnings. Use the `Aside` component only when a JSX-only composition pattern is required.

src/frontend/astro.config.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { socialConfig } from './config/socials.config.ts';
1010
import catppuccin from '@catppuccin/starlight';
1111
import lunaria from './config/lunaria-starlight.mjs';
1212
import mermaid from 'astro-mermaid';
13+
import mdx from '@astrojs/mdx';
1314
import starlight from '@astrojs/starlight';
1415
import starlightGitHubAlerts from 'starlight-github-alerts';
1516
import starlightImageZoom from 'starlight-image-zoom';
@@ -224,6 +225,10 @@ export default defineConfig({
224225
}),
225226
],
226227
}),
228+
mdx({
229+
optimize: true,
230+
gfm: true,
231+
}),
227232
jopSoftwarecookieconsent(cookieConfig),
228233
...(isBuildTimingEnabled ? [buildTiming()] : []),
229234
],

src/frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
"dependencies": {
6060
"@astro-community/astro-embed-vimeo": "^0.3.12",
6161
"@astro-community/astro-embed-youtube": "^0.5.10",
62+
"@astrojs/mdx": "^5.0.6",
6263
"@astrojs/rss": "^4.0.18",
6364
"@astrojs/starlight": "^0.39.3",
6465
"@catppuccin/starlight": "^2.0.1",

src/frontend/pnpm-lock.yaml

Lines changed: 4 additions & 70 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/frontend/src/content/docs/community/contributor-guide.mdx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -391,23 +391,23 @@ Renders as:
391391
392392
### Tables
393393

394-
Create tables using pipes `|` and hyphens `-`:
394+
Create tables using pipes `|` and hyphens `-`. Keep a blank line before and after the table, include one separator cell for each heading, and use at least three hyphens in each separator cell:
395395

396396
```md title="src/content/docs/example.md"
397397
| Feature | Description | Status |
398-
|--|--|--|
399-
| Dashboard | Web-based monitoring | Available |
400-
| Telemetry | OpenTelemetry support | Available |
401-
| Deployment | Kubernetes deployment | 🚧 Preview |
398+
| ------- | ----------- | ------ |
399+
| Dashboard | Web-based monitoring | Available |
400+
| Telemetry | OpenTelemetry support | Available |
401+
| Deployment | Kubernetes deployment | Preview |
402402
```
403403

404404
Renders as:
405405

406406
| Feature | Description | Status |
407-
|--|--|--|
408-
| Dashboard | Web-based monitoring | Available |
409-
| Telemetry | OpenTelemetry support | Available |
410-
| Deployment | Kubernetes deployment | 🚧 Preview |
407+
| ------- | ----------- | ------ |
408+
| Dashboard | Web-based monitoring | Available |
409+
| Telemetry | OpenTelemetry support | Available |
410+
| Deployment | Kubernetes deployment | Preview |
411411

412412
<Aside type="tip">
413413
You can align columns using colons: `| :--- |` for left, `| :---: |` for center, and `| ---: |` for right alignment.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { expect, test } from '@playwright/test';
2+
3+
import { dismissCookieConsentIfVisible } from '@tests/e2e/helpers';
4+
5+
test('contributor guide renders common Markdown as semantic HTML', async ({ page }) => {
6+
await page.goto('/community/contributor-guide/#write-markdown');
7+
await dismissCookieConsentIfVisible(page);
8+
9+
const main = page.locator('main');
10+
await expect(page.getByRole('heading', { name: /Write Markdown/i })).toBeVisible();
11+
12+
const markdownTable = main
13+
.locator('table')
14+
.filter({ hasText: 'Dashboard' })
15+
.filter({ hasText: 'OpenTelemetry support' })
16+
.first();
17+
18+
await expect(markdownTable).toBeVisible();
19+
await expect(markdownTable.locator('thead th')).toHaveText([
20+
'Feature',
21+
'Description',
22+
'Status',
23+
]);
24+
await expect(markdownTable.locator('tbody tr')).toHaveCount(3);
25+
await expect(markdownTable).toContainText('Kubernetes deployment');
26+
27+
await expect(main.locator('p').filter({ hasText: /^\|\s*Feature\s*\|/ })).toHaveCount(0);
28+
await expect(main.getByRole('complementary', { name: 'Tip' }).first()).toBeVisible();
29+
await expect(main.getByRole('link', { name: 'David Pine' })).toHaveAttribute(
30+
'href',
31+
/https:\/\/davidpine\.net\/?/
32+
);
33+
await expect(main.locator('p code').filter({ hasText: 'Inline code' })).toBeVisible();
34+
await expect(
35+
main.locator('pre code').filter({ hasText: 'builder.AddProject<Projects.ApiService>' }).first()
36+
).toBeVisible();
37+
await expect(
38+
main.locator('blockquote').filter({ hasText: 'This is a note or important callout.' })
39+
).toBeVisible();
40+
await expect(main.locator('hr')).toHaveCount(1);
41+
await expect(main.locator('del').filter({ hasText: 'This text is crossed out' })).toBeVisible();
42+
43+
const completedTask = main
44+
.locator('li')
45+
.filter({ hasText: 'Add Aspire to your project' })
46+
.locator('input[type="checkbox"]');
47+
const pendingTask = main
48+
.locator('li')
49+
.filter({ hasText: 'Deploy to Azure' })
50+
.locator('input[type="checkbox"]');
51+
52+
await expect(completedTask).toBeChecked();
53+
await expect(pendingTask).not.toBeChecked();
54+
await expect(main.locator('ul').filter({ hasText: 'First item' }).first()).toBeVisible();
55+
await expect(main.locator('ol').filter({ hasText: 'First step' }).first()).toBeVisible();
56+
});

0 commit comments

Comments
 (0)