diff --git a/MIGRATION.md b/MIGRATION.md index 5dc5594..b60c8d1 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -8,6 +8,8 @@ Two migrations live here: - **[Part 2: adopting the shared brand mark](#part-2-adopting-the-shared-brand-mark-047)** is for a site already on the theme that still carries its own copy of the logo and its own navbar/footer logo config. Added in 0.4.7. +- **[Part 3: small screens](#part-3-small-screens-049)** is for a site that + papered over the theme's phone and tablet defects itself. Added in 0.4.9. ## Part 1: adopting the theme @@ -252,3 +254,66 @@ npm run serve - [ ] The navbar mark links to `https://docs.vantagecompute.ai` in the same tab - [ ] The footer mark links to `https://vantagecompute.ai` - [ ] No `static/img/vantage-logo-color.svg` remains in your repo + +## Part 3: small screens (0.4.9) + +0.4.9 makes the theme behave on phones and tablets: the search control is a +bare icon below 1200px, the logo is never hidden, markdown tables scroll, +tab strips wrap, the 997 to 1199 band drops the right-hand TOC for the +collapsible one, touch targets are 44px, and every muted label moved from +`--ink-400` to `--ink-500` for contrast. A site that fixed any of this itself +now has two copies of the fix, and one of them is wrong. + +### Step 1: Upgrade the package + +```bash +npm install @vantagecompute/docusaurus-theme@^0.4.9 +``` + +### Step 2: Delete your own table wrapper + +The theme now routes every markdown `table` through a scroll region from its +own `src/theme/MDXComponents`. A site that did the same wraps every table +twice. Delete the site's `src/theme/MDXComponents` (or its `table` entry) and +the component it pointed at. + +### Step 3: Delete the overrides the theme now carries + +Search `src/css/custom.css` for rules that touch any of these and remove them; +the theme's own version is what you want: + +- `.DocSearch-Button` below 1200, and `[class*="navbarSearchContainer"]` +- `.navbar__logo` visibility at small widths +- `.navbar__center-title` when there is no title +- `[data-navbar-ask-ai]` visibility and size +- `.markdown table` display, overflow, border and radius +- `.markdown .tabs` wrapping +- `.pagination-nav` columns below 600 +- `--ifm-navbar-sidebar-width` +- `.navbar__toggle`, `.navbar-sidebar__close`, `.menu__link`, `.menu__caret`, + `.breadcrumbs__link`, `.theme-doc-toc-mobile` sizing below 997 +- `--doc-sidebar-width`, `.col--3:has(.theme-doc-toc-desktop)`, + `.theme-doc-toc-mobile` between 997 and 1199 +- `.DocSearch-Modal`, `.DocSearch-Input`, `.DocSearch-Close` below 768 +- `h2` and `h3` margins below 600 +- `body.chat-open` (removed from the theme; it was dead) + +### Step 4: Check your own muted text + +If the site sets `color: var(--ink-400)` on anything a reader is meant to +read, change it to `--ink-500`. The token page explains the numbers. + +### Step 5: Verify + +```bash +npm run build +npm run serve +``` + +At 375, 768 and 1024 wide: + +- [ ] No horizontal scroll on any page +- [ ] The navbar shows the logo, a magnifying glass and (if the site has one) the Ask AI sparkle, all the same size +- [ ] A wide reference table scrolls inside its frame rather than squeezing +- [ ] Every tab in a tab strip is visible +- [ ] At 1024 the article has no right-hand TOC column and shows the "On this page" collapsible instead diff --git a/docusaurus/docs/design-system/tokens.md b/docusaurus/docs/design-system/tokens.md index 294c62a..7352c80 100644 --- a/docusaurus/docs/design-system/tokens.md +++ b/docusaurus/docs/design-system/tokens.md @@ -18,13 +18,22 @@ A slate-blue neutral rather than a pure grey. Light mode: | `--ink-900` | `#0b1020` | Headings, code block background | | `--ink-700` | `#1f2547` | Body text | | `--ink-500` | `#4a5375` | Secondary text, sidebar and TOC links | -| `--ink-400` | `#6b7494` | Muted text | +| `--ink-400` | `#6b7494` | Decoration only: list markers, separators, chevrons. Never text (see below) | | `--ink-300` | `#9aa1bd` | Disabled text, placeholders | | `--ink-200` | `#c8cce0` | Strong borders | | `--ink-100` | `#e6e8f2` | Borders, rules, TOC border | | `--ink-50` | `#f4f5fb` | Inline code background, hover fills | | `--paper` | `#fbfbfd` | Page background | +`--ink-400` is the one step that is not mirrored: it is `#6b7494` in both +modes, the ramp's fixed point. As text it measures 4.46:1 on the light page, +4.24:1 on a light `--ink-50` surface and 3.68 to 4.10:1 on every dark surface, +all under the 4.5:1 floor for text. Use `--ink-500` for muted text: it is +mirrored (`#4a5375` light, `#9aa1bd` dark) and clears 6.6:1 everywhere. Keep +`--ink-400` for things that are not read: list markers, breadcrumb separators, +chevrons, where the 3:1 non-text floor is what applies and it passes (4.6:1 +light, 4.1:1 dark). + ## Iris: the accent scale | Token | Value | Typical use | diff --git a/docusaurus/docs/reference/components.md b/docusaurus/docs/reference/components.md index b8216ee..bea88c7 100644 --- a/docusaurus/docs/reference/components.md +++ b/docusaurus/docs/reference/components.md @@ -16,6 +16,7 @@ per-site swizzling. | `Navbar/Logo` | A centered site title with a version badge beside it | | `Tabs` | A workaround for a Docusaurus 3.10 crash | | `Navbar/MobileSidebar/SecondaryMenu` | A clean secondary-menu render | +| `MDXComponents` | Every markdown `table` renders inside a horizontal scroll region (0.4.9) | ## `Tabs`: the one that is a bugfix @@ -60,6 +61,20 @@ without bound and exhausts the heap during static site generation. If you wrap a component from inside a theme package, use `@theme-init`. ::: +## `MDXComponents`: tables that scroll + +The theme frames tables with a border and a radius. Doing that on the table +itself needed `overflow: hidden`, which threw away the horizontal scrolling +Docusaurus gives wide tables, so on a phone a four-column reference table +squeezed into 61px columns. Since 0.4.9 the theme maps the markdown `table` +element to `TableScroll`, a `div.table-scroll` with `role="region"` around the +table. The wrapper carries the frame and scrolls; the table keeps its natural +width, with cells capped at 60ch. + +A site that already wraps `table` in its own `MDXComponents` must remove that +entry, or every table renders in two scroll regions. See `MIGRATION.md`, +Part 3. + ## Overriding an override Docusaurus resolves themes in layers, and a site's own `src/theme/` wins over diff --git a/src/css/custom.css b/src/css/custom.css index 9c5db51..ec4e17f 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -366,20 +366,49 @@ div[class^='codeBlockTitle'] { } /* ── Tables ────────────────────────────────────────────────────────── */ +/* Every markdown table renders inside `.table-scroll` (src/theme/MDXComponents), + which carries the rounded frame and scrolls horizontally. The table itself + keeps its natural width. The old `display: table; overflow: hidden` on the + table removed Docusaurus's own overflow scrolling, and a four-column + reference table on a 345px phone column squeezed to 61px columns with + 171px rows. Cells are capped at 60ch so one long description cannot force + a 3000px scroll. */ +.markdown .table-scroll, +article .table-scroll { + margin: 14px 0; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + background: var(--ifm-background-surface-color); + border: 1px solid var(--ink-100); + border-radius: 8px; +} + +.markdown .table-scroll:focus-visible, +article .table-scroll:focus-visible { + outline: 2px solid var(--ifm-color-primary); + outline-offset: 2px; +} + .markdown table, article table { display: table; width: 100%; + min-width: max-content; border-collapse: collapse; font-size: 13px; - margin: 14px 0; + margin: 0; background: var(--ifm-background-surface-color); - border: 1px solid var(--ink-100); - border-radius: 8px; - overflow: hidden; + border: 0; box-shadow: none; } +.markdown table td, +.markdown table th, +article table td, +article table th { + max-width: 60ch; +} + .markdown table th, article table th { font-weight: 600; @@ -441,7 +470,11 @@ article table td code { } .markdown li::marker { - color: var(--ink-300); + /* ink-300 was 2.5:1 against the page in both modes. ink-400 is the ramp's + fixed point (#6b7494 in both modes) and clears the 3:1 non-text floor: + 4.6:1 light, 4.1:1 dark. It stays decoration-only; see the note on + .sidebar-section-label for why it is not used for text. */ + color: var(--ink-400); } /* Tab lists should have no left padding (override .markdown ul) */ @@ -450,6 +483,17 @@ article table td code { margin-bottom: 0; } +/* Infima scrolls the strip, and a strip that ends flush with the edge hides + the tabs past it with nothing to say they exist: two of six on a phone. + Wrap instead, so every tab is on screen in at most two rows. */ +@media (max-width: 996px) { + .markdown .tabs { + flex-wrap: wrap; + overflow-x: visible; + row-gap: 2px; + } +} + /* ── Provider showcase (On-Premises clusters) ───────────────────────── */ .provider-showcase { display: grid; @@ -645,7 +689,7 @@ html[data-theme='dark'] .provider-showcase-item { .guide-meta-label { display: block; margin-bottom: 0.25rem; - color: var(--ink-400); + color: var(--ink-500); font-size: 0.75rem; font-weight: 700; letter-spacing: 0.08em; @@ -877,8 +921,66 @@ html[data-theme='dark'] .provider-showcase-item { color: var(--vantage-navbar-link-hover) !important; } -@media (max-width: 1024px) { - .navbar__logo { display: none !important; } +/* The logo used to be hidden at <=1024px, which with an empty navbar.title + left every phone and tablet with no brand at all. Keep it; shrink it a + little where the hamburger shares the row. */ +@media (max-width: 996px) { + .navbar__logo { + height: 28px; + } +} + +/* Touch targets below the layout break. WCAG 2.5.8 asks for 24px minimum; + 44px is the comfortable size. The drawer close button measured 21px, + sidebar rows and carets 30px, the hamburger 30px. Padding, not larger + glyphs, so the visuals do not change. Infima's drawer is also 83vw, which + on a 768px tablet is a 637px menu for a list of 14px rows. */ +@media (max-width: 996px) { + :root { + --ifm-navbar-sidebar-width: min(83vw, 360px); + } + + .navbar__toggle { + padding: 7px; + margin: -7px 0; + } + + .navbar-sidebar__close { + padding: 12px; + margin-right: -12px; + } + + .navbar-sidebar .menu__link { + padding: 10px 12px; + } + + .navbar-sidebar .menu__caret { + padding: 12px 10px; + } + + .breadcrumbs__link { + display: inline-flex; + align-items: center; + min-height: 32px; + } + + .theme-doc-toc-mobile > button { + min-height: 44px; + } +} + +/* Two 165px pagination cards side by side on a phone truncate their titles. + Infima pins the next card to `grid-column: 2 / 3`, which would open an + implicit second track even with one column declared, so it is reset too. */ +@media (max-width: 600px) { + .pagination-nav { + grid-template-columns: 1fr; + } + + .pagination-nav__link--next { + grid-column: auto; + text-align: left; + } } /* ── Sidebar (left) ────────────────────────────────────────────────── */ @@ -1029,7 +1131,7 @@ html[data-theme='dark'] .provider-showcase-item { font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; - color: var(--ink-400); + color: var(--ink-500); margin-bottom: 10px; content: 'On this page'; } @@ -1085,7 +1187,7 @@ html[data-theme='dark'] .provider-showcase-item { } .breadcrumbs__link { - color: var(--ink-400); + color: var(--ink-500); font-weight: 500; border-bottom: 0 !important; } @@ -1210,7 +1312,7 @@ a.button--secondary:focus { } .pagination-nav__sublabel { - color: var(--ink-400); + color: var(--ink-500); font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; @@ -1378,7 +1480,7 @@ details summary[onclick]:hover { --docsearch-spacing: 12px; --docsearch-icon-stroke-width: 1.4; --docsearch-highlight-color: var(--iris-700); - --docsearch-muted-color: var(--ink-400); + --docsearch-muted-color: var(--ink-500); /* Backdrop */ --docsearch-container-background: rgba(11, 16, 32, 0.48); /* Modal */ @@ -1407,7 +1509,7 @@ details summary[onclick]:hover { --docsearch-primary-color: #818cf8; --docsearch-text-color: var(--ink-700); --docsearch-highlight-color: #818cf8; - --docsearch-muted-color: var(--ink-400); + --docsearch-muted-color: var(--ink-500); /* Backdrop */ --docsearch-container-background: rgba(0, 0, 0, 0.65); /* Modal */ @@ -1501,7 +1603,8 @@ button.DocSearch-Button { .DocSearch-Button-Key { background: transparent !important; box-shadow: none !important; - color: rgba(255, 255, 255, 0.7) !important; + /* .7 measured 3.91:1 on the keys' doubly tinted background; .85 is 5.1:1. */ + color: rgba(255, 255, 255, 0.85) !important; font-family: var(--ifm-font-family-monospace) !important; font-size: 10px !important; font-weight: 500 !important; @@ -1510,30 +1613,6 @@ button.DocSearch-Button { line-height: 1 !important; } -/* Medium: hide AskAI, shrink search pill */ -@media (max-width: 1050px) { - .navbar__items [data-navbar-ask-ai] { display: none !important; } - - .DocSearch-Button { - min-width: 180px !important; - } -} - -/* Small: search pill drops to icon-only */ -@media (max-width: 800px) { - .DocSearch-Button { - min-width: 0 !important; - width: 36px !important; - padding: 0 !important; - justify-content: center !important; - } - .DocSearch-Button-Placeholder, - .DocSearch-Button-Keys { display: none !important; } - .DocSearch-Button .DocSearch-Search-Icon { - color: rgba(255, 255, 255, 0.9) !important; - } -} - /* Dark mode: same squared style */ [data-theme='dark'] .DocSearch-Button, [data-theme='dark'] button.DocSearch-Button { @@ -1558,9 +1637,103 @@ button.DocSearch-Button { } [data-theme='dark'] .DocSearch-Button-Key { - color: rgba(255, 255, 255, 0.7) !important; + /* Same 3.91:1 to 5.1:1 lift as the light rule above. */ + color: rgba(255, 255, 255, 0.85) !important; +} + + +/* ── Search below 1200: a bare magnifying glass ─────────────────────── */ +/* The 400px pill above is a desktop design. Below 1200 the navbar also holds + the hamburger or the logo, Ask AI and the theme toggle, and below 997 + Docusaurus parks the search container in a zero-width absolute box at the + right edge, which centred the pill on that edge and hung it 185px off + screen. Here search is a 44px transparent box with an 18px white icon at + 85% opacity, the same treatment the Ask AI sparkle uses, so the two read + as one row of icon controls. Selectors are (0,3,1) so they outrank the + dark-mode rules above, which are (0,2,1). */ +@media (max-width: 1199px) { + .navbar .navbar__items button.DocSearch-Button { + width: 44px !important; + min-width: 0 !important; + height: 44px !important; + padding: 0 !important; + justify-content: center !important; + position: static !important; + left: auto !important; + top: auto !important; + transform: none !important; + background: transparent !important; + border: 0 !important; + border-radius: 0 !important; + box-shadow: none !important; + color: rgba(255, 255, 255, 0.85) !important; + } + + .navbar .navbar__items button.DocSearch-Button:hover, + .navbar .navbar__items button.DocSearch-Button:focus-visible { + background: transparent !important; + border-color: transparent !important; + color: #ffffff !important; + } + + .navbar .navbar__items button.DocSearch-Button .DocSearch-Button-Container { + flex: 0 0 auto; + } + + .navbar .navbar__items button.DocSearch-Button .DocSearch-Button-Placeholder, + .navbar .navbar__items button.DocSearch-Button .DocSearch-Button-Keys { + display: none !important; + } + + .navbar .navbar__items button.DocSearch-Button .DocSearch-Search-Icon { + width: 18px !important; + height: 18px !important; + color: inherit !important; + } + + /* Let the container flow with the other right-hand items instead of + Docusaurus's `position: absolute; right: 15px`. */ + .navbar .navbar__items--right [class*="navbarSearchContainer"] { + position: static !important; + right: auto !important; + } + + /* A site's Ask AI navbar item (data-navbar-ask-ai) takes the same box. It + used to be hidden at <=1050px, which below 997 left phones with no + persistent entry point to the assistant. */ + .navbar .navbar__items [data-navbar-ask-ai] { + display: inline-flex !important; + } + + .navbar .navbar__items [data-navbar-ask-ai] button { + width: 44px; + height: 44px; + } } +/* DocSearch goes full screen below 768. The modal keeps no radius there, the + input is 16px so iOS does not zoom on focus, and the Cancel control and the + result rows reach touch size. */ +@media (max-width: 768px) { + .DocSearch-Container .DocSearch-Modal { + border-radius: 0 !important; + max-width: none !important; + } + + .DocSearch-Container .DocSearch-Input { + font-size: 16px !important; + } + + .DocSearch-Container .DocSearch-Close { + min-width: 44px; + min-height: 44px; + justify-content: center; + } + + .DocSearch-Container .DocSearch-Hit a { + min-height: 48px; + } +} /* ── Search modal ───────────────────────────────────────────────────── */ .DocSearch-Modal { border-radius: 12px !important; @@ -1583,7 +1756,7 @@ button.DocSearch-Button { } [data-theme='dark'] .DocSearch-Hit-source { - color: #6b7494 !important; + color: var(--ink-500) !important; } .DocSearch-Form { @@ -1733,7 +1906,7 @@ button.DocSearch-Button { box-shadow: none !important; border: 1px solid var(--ink-300) !important; border-radius: 4px !important; - color: var(--ink-400) !important; + color: var(--ink-500) !important; font-family: var(--ifm-font-family-monospace) !important; font-size: 10px !important; padding: 2px 5px !important; @@ -1744,12 +1917,12 @@ button.DocSearch-Button { [data-theme='dark'] .DocSearch-Commands-Key { border-color: #2a3157 !important; - color: #6b7494 !important; + color: var(--ink-500) !important; } .DocSearch-Label { font-size: 11px !important; - color: var(--ink-400) !important; + color: var(--ink-500) !important; } /* Empty / no results state */ @@ -1846,12 +2019,18 @@ article { *::-webkit-scrollbar-thumb:hover { background: var(--ink-300); } /* ── Sidebar section labels (Products / Platform / Reference / About) ─ */ +/* ink-500, not ink-400, for every muted label in the theme. ink-400 is the + ramp's fixed point, #6b7494 in both modes, and as text it measures 4.46:1 + on the light page, 4.24:1 on a light ink-50 surface and 3.68 to 4.10:1 + everywhere in dark, all under the 4.5:1 floor. ink-500 is mirrored + (#4a5375 light, #9aa1bd dark) and clears 6.6:1 on every surface it is + used on. ink-400 stays for decoration only: markers, separators, chevrons. */ .sidebar-section-label { font-size: 14px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em; - color: var(--ink-400); + color: var(--ink-500); padding: 14px 0 6px; margin-top: 8px; border-top: 1px solid var(--ink-100); @@ -1863,7 +2042,7 @@ article { padding: 10px 0 4px; text-transform: uppercase; letter-spacing: 0.06em; - color: var(--ink-400); + color: var(--ink-500); text-align: left; } .menu > .menu__list > li:first-child .sidebar-section-label, @@ -1937,17 +2116,55 @@ article { } } -/* Chat sidebar - push layout (navbar excluded) */ -.main-wrapper { - transition: margin-right 0.3s ease-in-out; +/* A site with no navbar.title still gets the version badge, alone in the + centre. Between 997 and 1024 that is a bare git hash beside the logo on a + tablet; hide it there. On wider screens the lone centred badge stays. */ +@media (max-width: 1024px) { + .navbar__center-title:not(:has(.navbar__center-title-text)) { + display: none; + } } -body.chat-open .main-wrapper { - margin-right: 400px; +/* ── Tablet landscape (997 to 1199) ────────────────────────────────── */ +/* Docusaurus treats this band as desktop: a 300px sidebar, a right-hand TOC + column and the article between them. At 1024 the article is 505px and the + TOC has about 60px of text, so headings break letter by letter. Treat the + band as a wide tablet: a narrower sidebar, and the collapsible TOC in the + article instead of the right column. The column is hidden through :has so + the article regains the 25% it held. */ +@media (min-width: 997px) and (max-width: 1199px) { + .theme-doc-sidebar-container, + [class*="docsWrapper"] { + --doc-sidebar-width: 260px; + } + + .row > .col.col--3:has(.theme-doc-toc-desktop) { + display: none; + } + + [class*="docItemCol"] { + max-width: 100% !important; + } + + /* theme-classic hides the collapsible TOC from 997 up (tocMobile module). + It is server-rendered on every page, so showing it here costs nothing. */ + article .theme-doc-toc-mobile { + display: block; + } } -@media (max-width: 480px) { - body.chat-open .main-wrapper { - margin-right: 0; +/* ── Phone rhythm ──────────────────────────────────────────────────── */ +/* The 3rem h2 and 2rem h3 top margins above are sized for a wide screen. On + a 375px phone a 45px gap before every section reads as a page break. */ +@media (max-width: 600px) { + .theme-doc-markdown .markdown h2, + .theme-doc-markdown article h2 { + margin-top: 2.25rem; + font-size: 1.45rem; + } + + .theme-doc-markdown .markdown h3, + .theme-doc-markdown article h3 { + margin-top: 1.5rem; } } diff --git a/src/theme/MDXComponents/TableScroll.jsx b/src/theme/MDXComponents/TableScroll.jsx new file mode 100644 index 0000000..165820d --- /dev/null +++ b/src/theme/MDXComponents/TableScroll.jsx @@ -0,0 +1,19 @@ +/** + * A markdown table inside a horizontal scroll region. + * + * The theme frames tables with a border and a radius. Doing that on the table + * itself needed `overflow: hidden`, which removed the `display: block; + * overflow-x: auto` Docusaurus ships for wide tables, and on a 345px phone + * column a four-column reference table squeezed to 61px columns and 171px + * rows. The wrapper carries the frame now (see `.table-scroll` in + * src/css/custom.css); the table keeps its natural width and scrolls. + * + * `role="region"` plus `tabIndex` so a keyboard user can reach and scroll it. + */ +export default function TableScroll(props) { + return ( +
+ + + ); +} diff --git a/src/theme/MDXComponents/index.js b/src/theme/MDXComponents/index.js new file mode 100644 index 0000000..b27e424 --- /dev/null +++ b/src/theme/MDXComponents/index.js @@ -0,0 +1,17 @@ +// Routes every markdown `table` through TableScroll. Docusaurus's own map has +// no `table` entry, so this adds one rather than replacing anything. +// +// @theme-init, not @theme-original: this file ships inside a theme package that +// sits in the theme stack, so @theme-original/MDXComponents would resolve back +// to this same module and recurse. See src/theme/Navbar/Logo for the same note. +// +// A site that already wraps `table` itself (vantage-docs did, before this +// shipped) must drop its own wrapper, or every table renders in two scroll +// regions. MIGRATION.md, Part 3. +import MDXComponents from '@theme-init/MDXComponents'; +import TableScroll from './TableScroll'; + +export default { + ...MDXComponents, + table: TableScroll, +};