Prohlížeč zdrojového kódu

docs/specs/example-content.md

Náhled Zdrojový kód

80# Spec: Rich Example Content

  • Status: draft
  • Created: 2026-03-12
  • Related code: app/examples/, app/services/example_entry.rb, app/views/examples/show.html.erb

Overview

Each example has a rich content file (example.md) that defines the detail page layout. The Markdown file is the single source of truth for how the example's detail page is structured — authors write free-form Czech prose and embed the source code and scenario forms at the desired positions using placeholder tags. This lets each example tell its own story with the code and interactive elements woven in naturally.

Behaviour

Content file

  • Every example directory must include an example.md file.
  • example.md drives the detail page layout entirely on the detail page.
  • The description field in example.yml remains — it is used on the index page (example cards) but not on the detail page.
  • ExampleEntry exposes the raw Markdown content (read from disk on each request, same pattern as source code).

Placeholder tags

The Markdown content supports these placeholder tags, written on their own line:

  • <!-- source --> — replaced with the syntax-highlighted source code block. Raises an error if the example has no source_file.
  • <!-- scenario:INDEX --> — replaced with the scenario form and result frame for the scenario at position INDEX (0-based), e.g. <!-- scenario:0 -->.
  • <!-- scenarios --> — replaced with all scenario forms in order (equivalent to listing each one individually). Cannot be combined with individual <!-- scenario:N --> tags in the same file.

Rendering

  • The Markdown is rendered to HTML using the existing Redcarpet pipeline.
  • After Markdown rendering, placeholder tags (which survive as HTML comments) are replaced with the corresponding rendered partials.
  • If a placeholder references a scenario index that doesn't exist, it is silently removed.
  • The title and tags are still rendered from example.yml above the content, same as today.
  • Code blocks in example content (both fenced Markdown blocks and the <!-- source --> placeholder) are vertically constrained to 80% of the viewport height. When content exceeds this height, the block scrolls vertically. This prevents tall code blocks from dominating the page layout.
  • Two consecutive fenced code blocks separated by a <!-- compare --> or <!-- compare:LabelA:LabelB --> tag are rendered side by side in a 50/50 split. When labels are provided (colon-delimited), each pane displays its label above the block. Both panes' scroll positions are linked — scrolling either pane horizontally or vertically moves the other to match.

Migration

  • All existing examples get an example.md file reproducing the current detail page layout (description text, then source placeholder, then scenarios placeholder).

Implementation Notes

  • ExampleEntry#content_markdown reads example.md from @base_path on each request (same pattern as source_code).
  • HighlightHelper#render_example_content renders the Markdown via render_markdown, then replaces placeholder HTML comments via gsub with rendered partials and highlighted code. The result is wrapped in raw to mark it as HTML-safe for output. The <!-- source --> gsub raises ArgumentError when example.source_code is nil.
  • HighlightHelper#render_scenario_block renders the examples/scenario_block partial for each scenario.
  • _scenario_block.html.erb was extracted from the old show.html.erb — wraps scenario name, description, form, and Turbo Frame result tag.
  • show.html.erb wraps render_example_content(@example) in <div class="example-content"> — this scopes code block height limiting to example pages only, leaving the source browser unaffected.
  • compare_scroll_controller.js (Stimulus) — on connect, collects both pre elements within the .code-compare wrapper and syncs scrollTop/scrollLeft on each scroll event. Auto-registered via eagerLoadControllersFrom.
  • _code.scss.code-compare is a flex container with gap: 1rem; each .code-compare__pane is flex: 1; min-width: 0 (prevents flex blowout on wide code); .code-compare__label is small muted text. The <!-- compare --> post-processing is a gsub step inside render_example_content.
  • _code.scss scopes the height constraint to .example-content .code-block: the outer .code-block is set to overflow: hidden (overriding its base overflow-x: auto) and the inner pre becomes the 2D scroll container (max-height: 80vh; overflow: auto). This ensures both horizontal and vertical scrollbars are simultaneously visible at the edges of the pre element, rather than the horizontal bar being hidden below the vertical overflow clip.

Tests

  • spec/services/example_entry_spec.rbcontent_markdown reads from disk
  • spec/helpers/highlight_helper_spec.rb — Markdown rendering, source placeholder replacement, invalid scenario index removal, compare block rendering (unlabelled and labelled)
  • spec/requests/examples_spec.rb — integration: detail page renders syntax-highlighted code and scenario forms

See Also

Change Log

  • 2026-03-12: Initial prospective spec.
  • 2026-03-17: Added behaviour: code blocks in example content are height-limited to 80vh with vertical scroll.
  • 2026-03-17: Added side-by-side code comparison via <!-- compare --> tag with linked scrolling.
  • 2026-03-23: <!-- source --> silently removed when example has no source_file.