Skip to content

fix/lesson-content-styles - #118

Merged
ebouchut merged 8 commits into
devfrom
fix/lesson-content-styles
Jul 28, 2026
Merged

fix/lesson-content-styles#118
ebouchut merged 8 commits into
devfrom
fix/lesson-content-styles

Conversation

@ebouchut

Copy link
Copy Markdown
Owner

This PR make changes to the lessoned content and handles duplicate headings (do not generate the h1 page title when it is the same as the level-1 heading in the lesson Markdown).
It adds support for tables via a Common Markdown extension.

  • Wrap lesson HTML in a lesson block
  • Add scoped element CSS styles (code blocks scrollable cards, inline code chips, blockquote accents tables, lists deep headings, horizontal rules).
  • Add GFM pipe table support:
    • Use this package into the parser/renderer so that pipe tables render as real tables
    • Render GFM admonitions and Obsidian-style alerts (aka. callouts or admonitions, that basically look like info boxes):
      • Add the common-ext-gfm-alerts maven dependency,
      • Register GFM + **Obsidian alert types,
      • Support custom titles ,
      • Support nested alerts,
      • Sanitize safely.
      • Style lesson alerts with CSS (the only BEM exception) with per-type accent colors and Octicon masks (no inline SVG nested alert visuals and theme token support).
  • Upgrade commonmark-java to version 0.29.0, which is required to use the alerts extension and related parser features.
  • Skip duplicated leading title heading: drop a leading level-1/setext heading that matches the lesson title before rendering to avoid duplicate titles.
  • Fix unstyled Markdown output and ensure rendered match site typography and accessibility.
  • Prevent duplicated titles when the Markdown repeats the lesson title.
  • ADRs and docs added/updated for alert rendering and title dedup behavior.
  • Sanitizer allowlist widened then narrowed to class spoofing; icons delivered as CSS masks to avoid SVG in sanitized HTML.

ebouchut added 8 commits July 27, 2026 22:06
The lesson body looked unstyled next to the rest of the site: base.css
only covered h1 to h3, p, a, img, and bare code, so everything else the
Markdown produces (fenced code blocks, blockquotes, lists, tables,
deep headings, horizontal rules) fell back to raw browser defaults.
And since the sanitizer strips class attributes (ADR-0013), the
rendered HTML can never carry BEM classes, so nothing class-based
could ever reach it.

The lesson template now wraps the content in a lesson-content block,
and base.css styles it with element selectors scoped under that
wrapper (a deliberate, documented BEM exception, the only mechanism
the sanitized markup allows): code blocks become bordered cards that
scroll horizontally instead of stretching the page (RGAA 10.11),
inline code gets a chip, blockquotes an accent border, tables the
house table look, lists and deep headings the site rhythm, with h4 to
h6 joining the display typeface the global rule reserves for h1 to h3.
Pipe tables are a GFM extension, not core CommonMark, so a table typed
in a lesson rendered as literal pipe-separated text; the fresh
lesson-content table styles had nothing to apply to. ADR-0013 planned
for exactly this: extensions join on demand, and a lesson demanded one.

commonmark-ext-gfm-tables now plugs into the parser and the renderer;
the sanitizer allowlist already lets table markup through, proven by
the new renderer test asserting a pipe table survives rendering and
sanitization as a real HTML table.
Two lesson-rendering improvements land on this branch: alert/callout
blocks in the GitHub/Obsidian syntax (issue #116) and skipping a leading
heading that duplicates the lesson title (issue #117). The plan records
the commit map, the decisions involved, and the verification steps.
Lessons should render the alert/callout syntax GitHub and Obsidian
share. ADR-0015 chooses the official commonmark-ext-gfm-alerts
extension over a custom parser or a post-processing pass, accepts the
commonmark 0.24.0 => 0.29.0 upgrade it forces, keeps the five GFM types
on their GitHub identity while the Obsidian set joins with all aliases,
ships octicons as CSS masks so no SVG crosses the sanitizer, and
narrows the widened class allowlist with an exact-value second pass.

Refs #116
The upcoming alerts extension (commonmark-ext-gfm-alerts) is version-
locked to its same-version core, and its configuration API (custom
types, custom titles, nested alerts) only exists in 0.29.0, so the
whole commonmark stack moves up from 0.24.0 in one step.

Changelog reviewed from 0.25.0 to 0.29.0: no API removals; the notable
parser change is that GFM tables no longer require a preceding blank
line. The full test suite (tables, heading demotion, render caching)
stays green on the new version.

Refs #116
Alert markers in lesson Markdown ("> [!note]") used to degrade into
plain blockquotes with the marker as literal text. The official
commonmark-ext-gfm-alerts extension now plugs into the parser and
renderer with every option enabled, as decided in ADR-0015.

Registered types: the five GFM types keep their GitHub identity
(IMPORTANT and CAUTION stay standalone), and the full Obsidian callout
set joins them with all aliases, 27 types in total, matched case-
insensitively. Custom titles are inline-parsed and nested alerts
render as alerts instead of degrading to literal text.

The sanitizer allowlist widens to admit class on div/p and
data-alert-type so the alert markup stays styleable, and a second
sanitization pass immediately narrows it: any class value the alert
renderer does not emit is stripped, so raw HTML in a lesson cannot
borrow site classes. Renderer tests cover default and custom titles,
aliases, nesting, and the class-spoofing case.

Refs #116
The alert markup from the previous commit carried classes with no
styles behind them. The lesson-content section of base.css now styles
markdown-alert blocks: an accent border and title color per type
family, driven by the existing theme tokens so both themes work, and
an Octicon per type (the icon set GitHub uses for alerts, matched
against Obsidian's icon semantics).

Icons ship as mask-image data URIs painted with currentColor, so the
sanitized HTML never needs to carry SVG markup and the sanitizer
allowlist stays free of SVG tags. Nested alerts inset with a margin
and swap to the page background to stay visually distinct from their
parent. All 27 registered type classes are covered.

Fixes #116
A lesson whose Markdown starts with a level-1 heading equal to the
lesson title rendered the same text twice: the page h1 (the title from
the database) followed by an identical h2, the authored heading after
ADR-0014's demotion.

MarkdownRenderer gains a pure static, stripLeadingTitleHeading, that
drops the first non-blank heading when it is a level-1 ATX heading
(closing hashes tolerated) or a setext heading whose text equals the
lesson title, trimmed and case-insensitive. The lesson route applies
it before render() so the renderer stays cacheable by exact input and
the stored Markdown is never modified. A heading with different text,
or any deeper level, is kept as authored.

The lesson form now hints that the page already shows the title, and
ADR-0014 records the behavior as an amendment.

Fixes #117
@ebouchut ebouchut self-assigned this Jul 28, 2026
@ebouchut ebouchut added dependencies backend accessibility Accessibility (RGAA, WCAG) course Course/Lesson labels Jul 28, 2026
@ebouchut ebouchut added this to the v1.0- Certification - DWWM milestone Jul 28, 2026
@ebouchut ebouchut moved this to In Review in learn-dev-project Jul 28, 2026
@ebouchut
ebouchut merged commit 70f2c56 into dev Jul 28, 2026
5 checks passed
@ebouchut
ebouchut deleted the fix/lesson-content-styles branch July 28, 2026 14:15
@github-project-automation github-project-automation Bot moved this from In Review to Done in learn-dev-project Jul 28, 2026
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.04762% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.57%. Comparing base (47af933) to head (945631a).
⚠️ Report is 9 commits behind head on dev.

Files with missing lines Patch % Lines
.../ericbouchut/learndev/course/MarkdownRenderer.java 93.82% 1 Missing and 4 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##                dev     #118      +/-   ##
============================================
+ Coverage     80.33%   81.57%   +1.24%     
- Complexity      186      201      +15     
============================================
  Files            38       38              
  Lines           783      863      +80     
  Branches         42       53      +11     
============================================
+ Hits            629      704      +75     
- Misses          124      125       +1     
- Partials         30       34       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

accessibility Accessibility (RGAA, WCAG) backend course Course/Lesson dependencies

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant