-
Notifications
You must be signed in to change notification settings - Fork 401
Fix unequal spacing in simple untitled callouts #13934
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
cderv
wants to merge
4
commits into
main
Choose a base branch
from
fix/issue-13883
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+354
−0
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
42c591b
Fix unequal spacing in simple untitled callouts
cderv 9b2f6a8
docs: Add HTML callout styling architecture guide
cderv 674a513
test: Add Playwright tests for callout spacing
cderv 8addfb4
docs: Fix date typo and add date-checking guidance
cderv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| # LLM Documentation | ||
|
|
||
| This directory contains documentation written for LLM assistants working on the Quarto codebase. | ||
|
|
||
| ## Staleness Check | ||
|
|
||
| Each document has YAML frontmatter with analysis metadata: | ||
|
|
||
| ```yaml | ||
| --- | ||
| main_commit: abc1234 # merge-base with main (stable reference) | ||
| analyzed_date: 2025-01-22 | ||
| key_files: | ||
| - path/to/file1.ts | ||
| - path/to/file2.lua | ||
| --- | ||
| ``` | ||
|
|
||
| **Why merge-base?** Branch commits can be rebased or disappear. The merge-base with main is stable and represents the baseline from main that was analyzed. | ||
|
|
||
| **Before relying on a document**, check if key files have changed: | ||
|
|
||
| ```bash | ||
| git log --oneline <main_commit>..main -- <key_files> | ||
| ``` | ||
|
|
||
| If there are significant changes, re-explore the codebase and update the document. | ||
|
|
||
| ## Updating Documents | ||
|
|
||
| After re-analyzing, update the frontmatter: | ||
|
|
||
| ```bash | ||
| # Get merge-base with main (use upstream/main if that's the main remote) | ||
| git merge-base HEAD main | cut -c1-9 | ||
| ``` | ||
|
|
||
| Then update `main_commit`, `analyzed_date`, and verify `key_files` list is complete. | ||
|
|
||
| **Date verification:** Before writing dates, check today's date from the system environment (shown at conversation start). This avoids year typos like writing 2025 when it's 2026. | ||
|
|
||
| ## Document Purpose | ||
|
|
||
| These docs capture architectural understanding that would otherwise require extensive codebase exploration. They are NOT: | ||
| - User documentation (that's at quarto.org) | ||
| - Code comments (those live in source files) | ||
| - Issue-specific notes (those go in PR descriptions) | ||
|
|
||
| They ARE: | ||
| - Architectural overviews for AI assistants | ||
| - File location maps for common tasks | ||
| - Pattern documentation for consistency |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,228 @@ | ||
| --- | ||
| main_commit: 50db5a5b0 | ||
| analyzed_date: 2026-01-22 | ||
| key_files: | ||
| - src/resources/formats/html/bootstrap/_bootstrap-rules.scss | ||
| - src/resources/formats/revealjs/quarto.scss | ||
| - src/resources/formats/html/styles-callout.html | ||
| - src/resources/filters/customnodes/callout.lua | ||
| --- | ||
|
|
||
| # HTML Callout Styling Architecture | ||
|
|
||
| This document describes the CSS architecture for Quarto callouts across HTML-based output formats. | ||
|
|
||
| ## Overview | ||
|
|
||
| Quarto uses a **three-tier callout styling architecture** depending on the output format: | ||
|
|
||
| | Tier | Formats | CSS Location | Features | | ||
| |------|---------|--------------|----------| | ||
| | Bootstrap HTML | `html` (with themes) | `formats/html/bootstrap/_bootstrap-rules.scss` | Full theming, collapsible, dark mode | | ||
| | RevealJS | `revealjs` | `formats/revealjs/quarto.scss` | Presentation-specific scaling, slide-aware | | ||
| | Standalone HTML | `epub`, `gfm`, plain html | `formats/html/styles-callout.html` | Inline CSS, no dependencies | | ||
|
|
||
| All HTML callouts support three **appearance** values: | ||
| - **default**: Full-featured with colored header background | ||
| - **simple**: Lightweight with left border only | ||
| - **minimal**: Maps to simple with `icon=false` | ||
|
|
||
| ## Format Detection (Lua Filter) | ||
|
|
||
| The Lua filter `src/resources/filters/customnodes/callout.lua` selects the appropriate renderer: | ||
|
|
||
| ``` | ||
| Renderer selection order: | ||
| 1. hasBootstrap() → Bootstrap HTML renderer | ||
| 2. isEpubOutput() || isRevealJsOutput() → Simpler HTML structure | ||
| 3. isGfmOutput() → GitHub markdown alerts | ||
| 4. Default → BlockQuote fallback | ||
| ``` | ||
|
|
||
| The `hasBootstrap()` function (in `filters/common/pandoc.lua`) checks the `has-bootstrap` parameter set by TypeScript during format initialization. | ||
|
|
||
| ## HTML Structure by Format | ||
|
|
||
| ### Bootstrap HTML | ||
|
|
||
| ```html | ||
| <div class="callout callout-style-default callout-note callout-titled"> | ||
| <div class="callout-header d-flex align-content-center"> | ||
| <div class="callout-icon-container"><i class='callout-icon'></i></div> | ||
| <div class="callout-title-container flex-fill">Title</div> | ||
| </div> | ||
| <div class="callout-body-container"> | ||
| <div class="callout-body">Content</div> | ||
| </div> | ||
| </div> | ||
| ``` | ||
|
|
||
| ### EPUB/RevealJS HTML | ||
|
|
||
| ```html | ||
| <div class="callout callout-note callout-style-default"> | ||
| <div class="callout-body"> | ||
| <div class="callout-icon-container"><i class='callout-icon'></i></div> | ||
| <div class="callout-title">Title</div> | ||
| <div class="callout-content">Content</div> | ||
| </div> | ||
| </div> | ||
| ``` | ||
|
|
||
| Note: Bootstrap uses `callout-body-container` wrapper and Bootstrap utility classes (`d-flex`, `flex-fill`). EPUB/RevealJS uses a flatter structure. | ||
|
|
||
| ## Feature Comparison | ||
|
|
||
| | Feature | Bootstrap | RevealJS | Standalone | | ||
| |---------|-----------|----------|------------| | ||
| | Collapsible | Yes | No | No | | ||
| | Icon type | SVG (dynamic color) | SVG (dynamic color) | PNG (base64) | | ||
| | Theming | Full Bootstrap vars | Presentation vars | Fixed colors | | ||
| | Dark mode | Yes | Slide background aware | No | | ||
| | Font scaling | Responsive | Presentation-specific (0.7em) | Fixed (0.9rem) | | ||
|
|
||
| --- | ||
|
|
||
| ## Bootstrap HTML Styling | ||
|
|
||
| File: `src/resources/formats/html/bootstrap/_bootstrap-rules.scss` | ||
|
|
||
| ### Callout States | ||
|
|
||
| | State | CSS Class | Description | | ||
| |-------|-----------|-------------| | ||
| | Titled | `.callout-titled` | Has a title/header | | ||
| | Untitled | `:not(.callout-titled)` | Content only, no header | | ||
| | Collapsed | `.callout-header.collapsed` | Collapsible, currently closed | | ||
| | Empty content | `.callout-empty-content` | No body content | | ||
|
|
||
| ### Styling Patterns | ||
|
|
||
| **Base callout:** | ||
| ```scss | ||
| .callout { | ||
| margin-top: $callout-margin-top; | ||
| margin-bottom: $callout-margin-bottom; | ||
| border-radius: $border-radius; | ||
| } | ||
| ``` | ||
|
|
||
| **Simple vs Default appearance:** | ||
| - `.callout-style-simple`: Left border only, lighter styling | ||
| - `.callout-style-default`: Full border, colored header background | ||
|
|
||
| **Body margins** vary by appearance (simple/default) and titled state (titled/untitled). The margin rules handle edge cases like collapsed callouts and empty content states. | ||
|
|
||
| ### Theming Variables | ||
|
|
||
| Bootstrap callouts use SCSS variables (in `_bootstrap-variables.scss`): | ||
|
|
||
| ```scss | ||
| $callout-border-width: 0.4rem !default; | ||
| $callout-border-scale: 0% !default; | ||
| $callout-icon-scale: 10% !default; | ||
| $callout-margin-top: 1.25rem !default; | ||
| $callout-margin-bottom: 1.25rem !default; | ||
| ``` | ||
|
|
||
| Colors are defined per callout type (note, warning, important, tip, caution) using Bootstrap's color functions. | ||
|
|
||
| --- | ||
|
|
||
| ## RevealJS Styling | ||
|
|
||
| File: `src/resources/formats/revealjs/quarto.scss` | ||
|
|
||
| ### Presentation-Specific Adjustments | ||
|
|
||
| ```scss | ||
| // Variables | ||
| $callout-border-width: 0.3rem; | ||
| $callout-margin-top: 1rem; | ||
| $callout-margin-bottom: 1rem; | ||
|
|
||
| // Font scaling for slide readability | ||
| .reveal div.callout { | ||
| font-size: 0.7em; | ||
| } | ||
| ``` | ||
|
|
||
| ### Light/Dark Slide Awareness | ||
|
|
||
| RevealJS callouts adjust colors based on slide background using the `shift_to_dark` mixin: | ||
|
|
||
| ```scss | ||
| .has-dark-background div.callout-note { | ||
| // Lighter colors for dark backgrounds | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Standalone/EPUB Styling | ||
|
|
||
| File: `src/resources/formats/html/styles-callout.html` | ||
|
|
||
| ### Characteristics | ||
|
|
||
| - **Inline CSS** embedded in HTML template | ||
| - **PNG icons** (base64-encoded) instead of SVG | ||
| - **Fixed colors**: Uses hardcoded `#acacac`, `silver` borders | ||
| - **No collapsible support** | ||
| - **No theming** - works without Bootstrap or any CSS framework | ||
|
|
||
| ### Key Selectors | ||
|
|
||
| ```css | ||
| .callout /* Base container */ | ||
| .callout.callout-style-simple /* Simple bordered style */ | ||
| .callout.callout-style-default /* Default style with header */ | ||
| .callout-title /* Title container */ | ||
| .callout-body /* Content container */ | ||
| .callout-icon::before /* Icon pseudo-element */ | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## CSS Class Reference | ||
|
|
||
| Classes applied across all HTML formats: | ||
|
|
||
| | Class | Applied When | Purpose | | ||
| |-------|--------------|---------| | ||
| | `.callout` | Always | Base container | | ||
| | `.callout-{type}` | Always | Type: note, warning, important, tip, caution | | ||
| | `.callout-style-{appearance}` | Always | Style: default, simple | | ||
| | `.callout-titled` | Has title | Structural indicator | | ||
| | `.no-icon` | `icon=false` | Suppress icon | | ||
| | `.callout-empty-content` | No body | Empty state (Bootstrap only) | | ||
|
|
||
| --- | ||
|
|
||
| ## Related Files | ||
|
|
||
| ### CSS/SCSS | ||
|
|
||
| | File | Purpose | | ||
| |------|---------| | ||
| | `src/resources/formats/html/bootstrap/_bootstrap-rules.scss` | Bootstrap HTML callout styles | | ||
| | `src/resources/formats/html/bootstrap/_bootstrap-variables.scss` | Bootstrap callout variables | | ||
| | `src/resources/formats/revealjs/quarto.scss` | RevealJS callout styles | | ||
| | `src/resources/formats/html/styles-callout.html` | Standalone HTML template | | ||
| | `src/resources/formats/dashboard/quarto-dashboard.scss` | Dashboard margin overrides | | ||
|
|
||
| ### Lua Filters | ||
|
|
||
| | File | Purpose | | ||
| |------|---------| | ||
| | `src/resources/filters/customnodes/callout.lua` | Renderer selection and AST processing | | ||
| | `src/resources/filters/modules/callouts.lua` | Bootstrap renderer implementation | | ||
| | `src/resources/filters/common/pandoc.lua` | `hasBootstrap()` function | | ||
|
|
||
| ### Tests | ||
|
|
||
| | File | Purpose | | ||
| |------|---------| | ||
| | `tests/docs/callouts.qmd` | All callout types and appearances | | ||
| | `tests/docs/playwright/html/callouts/` | Playwright test documents | | ||
| | `tests/integration/playwright/tests/html-callouts.spec.ts` | Playwright CSS tests | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| --- | ||
| title: Callout Spacing Test | ||
| --- | ||
|
|
||
| ## Simple Untitled {#simple-untitled} | ||
|
|
||
| ::: {.callout-note appearance="simple"} | ||
| Content without title to test spacing symmetry. | ||
| ::: | ||
|
|
||
| ## Simple Titled {#simple-titled} | ||
|
|
||
| ::: {.callout-note appearance="simple"} | ||
| ## Note Title | ||
| Content with title. | ||
| ::: | ||
|
|
||
| ## Default Untitled {#default-untitled} | ||
|
|
||
| ::: {.callout-note appearance="default"} | ||
| Content without title in default appearance. | ||
| ::: | ||
|
|
||
| ## Default Titled {#default-titled} | ||
|
|
||
| ::: {.callout-note appearance="default"} | ||
| ## Note Title | ||
| Content with title in default appearance. | ||
| ::: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { test, expect } from '@playwright/test'; | ||
| import { getCSSProperty } from '../src/utils'; | ||
|
|
||
| test('Simple untitled callout has symmetric spacing', async ({ page }) => { | ||
| await page.goto('./html/callouts/callout-spacing.html'); | ||
|
|
||
| // Simple untitled callout structure: | ||
| // .callout-style-simple > .callout-body > .callout-body-container > p | ||
| const simpleUntitledSection = page.locator('#simple-untitled'); | ||
| const lastChild = simpleUntitledSection.locator('.callout-style-simple:not(.callout-titled) .callout-body-container > p:last-child'); | ||
|
|
||
| // Verify margin-bottom > 0 (compensation for -0.4em body margin is applied) | ||
| const marginBottom = await getCSSProperty(lastChild, 'margin-bottom', true) as number; | ||
| expect(marginBottom).toBeGreaterThan(0); | ||
| }); | ||
|
|
||
| test('Simple titled callout spacing is handled by padding', async ({ page }) => { | ||
| await page.goto('./html/callouts/callout-spacing.html'); | ||
|
|
||
| // Simple titled callout structure: | ||
| // .callout-style-simple.callout-titled > .callout-body-container.callout-body > p | ||
| const simpleTitledSection = page.locator('#simple-titled'); | ||
| const lastChild = simpleTitledSection.locator('.callout-style-simple.callout-titled .callout-body > p:last-child'); | ||
|
|
||
| const paddingBottom = await getCSSProperty(lastChild, 'padding-bottom', true) as number; | ||
| expect(paddingBottom).toBeGreaterThan(0); | ||
| }); | ||
|
|
||
| test('Default callout spacing is handled by padding', async ({ page }) => { | ||
| await page.goto('./html/callouts/callout-spacing.html'); | ||
|
|
||
| // Default callouts always have .callout-titled class (even without explicit title) | ||
| // Structure: .callout-style-default.callout-titled > .callout-body > p | ||
| const defaultSection = page.locator('#default-untitled'); | ||
| const lastChild = defaultSection.locator('.callout-style-default .callout-body > p:last-child'); | ||
|
|
||
| const paddingBottom = await getCSSProperty(lastChild, 'padding-bottom', true) as number; | ||
| expect(paddingBottom).toBeGreaterThan(0); | ||
| }); |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really like this idea, but could we add the dates to the filename somehow? And note that Claude thinks it's 2025 :D
We could say
2026/01/22/callout-styling-html.mdor2026-01/2026-01-22-callout-styling-htmlor something like that. I just think that if we don't put date on the files and start accumulating them, it will get overwhelming quite quickly. And my experience with the kyoto repository makes me want to have at least monthly subdirectories, because you end up with a lot of them!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there are two types of doc:
(1) The design doc for some problem which makes sense to have date in filename. Usually you write them once, and then you don't update them I would say. Only consult them for history.
(2) Generic doc about the codebase to explain part of if, some features, concepts or design. And I would say that we need to keep updated those ones.
I have seen the kyoto ones, and I think there of type (1) right ?
Or type (2) ?
For
llm-docs/folder I thought this was type 2 and I wanted to store knowledge about callout design for HTML for next time we need to work on it. I was thinking we would need to update it, hence the YAML header to keep track of it.If we were to have date in file, then we would have a lot outdated one right ? or do you update them if needed ?