mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-27 14:17:25 -05:00
feat: restyle the site for contrast and phones
Header keeps the brand indigo in dark mode, buttons and inline code in links take the link colour, badges get darker backgrounds: axe reports no contrast failure left on nine pages in both schemes (617 nodes before). Admonitions keep one meaning per colour. On a phone, tables with a download button stack one block per row, other tables hold their first column, and commands wrap. Card grid, numbered steps, level label, terminal panel and path chip classes for the generated pages.
This commit is contained in:
1 parent
4366db574a
commit
f1c58820d1
2 files changed
+748
-38
No files matched your search
+673
-26
@@ -1,52 +1,230 @@
|
||||
/* RetroBIOS theme on top of mkdocs-material */
|
||||
/* RetroBIOS theme on top of mkdocs-material.
|
||||
|
||||
Classes the generator and the wiki pages can use:
|
||||
.rb-lead first paragraph under a page title
|
||||
.rb-level-* level label (start, setup, explore, reference, contribute)
|
||||
.rb-page-header logo or image beside the title block of an entity page
|
||||
.rb-cards, .rb-card card grid without Material's list markup
|
||||
.grid.cards Material card grid, restyled here
|
||||
.rb-card-logo 40 px logo tile inside a card
|
||||
.rb-steps ordered list drawn as numbered steps
|
||||
.rb-terminal wraps a code block that shows terminal output
|
||||
.rb-cmd wraps a command that must wrap instead of scrolling
|
||||
code.rb-path a folder path shown as a chip
|
||||
.rb-figure a generated diagram (scripts/sitediagrams.py)
|
||||
.rb-bar inline coverage bar, width from --v
|
||||
*/
|
||||
|
||||
:root {
|
||||
--rb-primary: #4a4e8a;
|
||||
--rb-primary-light: #6366a0;
|
||||
--rb-primary-dark: #363870;
|
||||
--rb-primary: #3b3f7a;
|
||||
--rb-primary-dark: #2b2e5c;
|
||||
--rb-accent: #b42318;
|
||||
--rb-link: #273c8f;
|
||||
--rb-fg: rgba(0, 0, 0, 0.87);
|
||||
--rb-surface: #f5f6fa;
|
||||
--rb-border: #e0e3eb;
|
||||
--rb-border-strong: #b8bdcc;
|
||||
--rb-text-secondary: #546e7a;
|
||||
--rb-ok-fg: #1b5e20;
|
||||
--rb-ok-bg: #e8f5e9;
|
||||
--rb-warn-fg: #a33f00;
|
||||
--rb-warn-bg: #fff3e0;
|
||||
--rb-err-fg: #b71c1c;
|
||||
--rb-err-bg: #ffebee;
|
||||
--rb-info-fg: #0d47a1;
|
||||
--rb-info-bg: #e3f2fd;
|
||||
--rb-muted-fg: #455a64;
|
||||
--rb-muted-bg: #eceff1;
|
||||
--rb-level-start: #1b5e20;
|
||||
--rb-level-setup: #0d47a1;
|
||||
--rb-level-explore: #6a1b9a;
|
||||
--rb-level-reference: #455a64;
|
||||
--rb-level-contribute: #a33f00;
|
||||
--rb-terminal-bg: #1b1d2e;
|
||||
--rb-terminal-fg: #e6e6f0;
|
||||
--rb-terminal-label: #9aa0c3;
|
||||
--rb-diagram-fill: #f5f6fa;
|
||||
--rb-diagram-stroke: #8c92ac;
|
||||
--rb-diagram-accent: #3b3f7a;
|
||||
--md-code-font: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] {
|
||||
--rb-surface: #1e1e2e;
|
||||
--rb-border: #313244;
|
||||
--rb-text-secondary: #a6adc8;
|
||||
--rb-accent: #ff9a8f;
|
||||
--rb-link: #aebcff;
|
||||
--rb-fg: #e3e4ee;
|
||||
--rb-surface: #252838;
|
||||
--rb-border: #3a3d52;
|
||||
--rb-border-strong: #5a5e7a;
|
||||
--rb-text-secondary: #a6adc8;
|
||||
--rb-ok-fg: #a5d6a7;
|
||||
--rb-ok-bg: #1b3a1f;
|
||||
--rb-warn-fg: #ffcc80;
|
||||
--rb-warn-bg: #7a2e00;
|
||||
--rb-err-fg: #ef9a9a;
|
||||
--rb-err-bg: #7f1414;
|
||||
--rb-info-fg: #90caf9;
|
||||
--rb-info-bg: #0d2a55;
|
||||
--rb-muted-fg: #cfd8dc;
|
||||
--rb-muted-bg: #37474f;
|
||||
--rb-level-start: #a5d6a7;
|
||||
--rb-level-setup: #90caf9;
|
||||
--rb-level-explore: #ce93d8;
|
||||
--rb-level-reference: #cfd8dc;
|
||||
--rb-level-contribute: #ffcc80;
|
||||
--rb-terminal-bg: #12131c;
|
||||
--rb-diagram-fill: #252838;
|
||||
--rb-diagram-stroke: #7c82a3;
|
||||
--rb-diagram-accent: #aebcff;
|
||||
}
|
||||
|
||||
/* Colour roles. The header keeps the brand indigo in both schemes: the
|
||||
lighter indigo it used in dark mode left the tab labels at 3.5:1. */
|
||||
[data-md-color-scheme="default"] {
|
||||
--md-primary-fg-color: var(--rb-primary);
|
||||
--md-primary-fg-color--light: var(--rb-primary-light);
|
||||
--md-primary-fg-color--light: #4a4e8a;
|
||||
--md-primary-fg-color--dark: var(--rb-primary-dark);
|
||||
--md-accent-fg-color: var(--rb-accent);
|
||||
--md-typeset-a-color: var(--rb-link);
|
||||
/* Comments and punctuation sat at 4.47:1 on the code background. */
|
||||
--md-code-hl-comment-color: #5c5c5c;
|
||||
--md-code-hl-generic-color: #5c5c5c;
|
||||
--md-code-hl-variable-color: #5c5c5c;
|
||||
--md-code-hl-operator-color: #5c5c5c;
|
||||
--md-code-hl-punctuation-color: #5c5c5c;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] {
|
||||
--md-primary-fg-color: var(--rb-primary-light);
|
||||
--md-primary-fg-color: var(--rb-primary-dark);
|
||||
--md-primary-fg-color--light: var(--rb-primary);
|
||||
--md-primary-fg-color--dark: #1f2147;
|
||||
--md-accent-fg-color: var(--rb-accent);
|
||||
--md-accent-bg-color: #1e2129;
|
||||
--md-typeset-a-color: var(--rb-link);
|
||||
--md-code-hl-constant-color: #b39ddb;
|
||||
}
|
||||
|
||||
/* Type scale: the page title is the strongest heading on the page. */
|
||||
.md-typeset h1 {
|
||||
color: var(--md-default-fg-color);
|
||||
font-size: 2em;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
line-height: 1.25;
|
||||
margin: 0 0 0.9em;
|
||||
}
|
||||
|
||||
.md-typeset h2 {
|
||||
font-size: 1.45em;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.005em;
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
.md-typeset h3 {
|
||||
font-size: 1.15em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.md-typeset h4 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.md-typeset .rb-lead {
|
||||
font-size: 1.05em;
|
||||
line-height: 1.55;
|
||||
max-width: 44em;
|
||||
}
|
||||
|
||||
/* Level label under a page title */
|
||||
.rb-level {
|
||||
display: inline-block;
|
||||
margin: 0 0 0.8rem;
|
||||
padding: 0.05rem 0.45rem;
|
||||
border: 1px solid currentColor;
|
||||
border-radius: 2px;
|
||||
font-size: 0.68rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.01em;
|
||||
line-height: 1.6;
|
||||
color: var(--rb-level-reference);
|
||||
}
|
||||
|
||||
.rb-level-start { color: var(--rb-level-start); }
|
||||
.rb-level-setup { color: var(--rb-level-setup); }
|
||||
.rb-level-explore { color: var(--rb-level-explore); }
|
||||
.rb-level-reference { color: var(--rb-level-reference); }
|
||||
.rb-level-contribute { color: var(--rb-level-contribute); }
|
||||
|
||||
/* Header block of platform, system and emulator pages */
|
||||
.rb-page-header {
|
||||
display: grid;
|
||||
grid-template-columns: 56px 1fr;
|
||||
gap: 0.4rem 1rem;
|
||||
align-items: center;
|
||||
margin: 0 0 1.2rem;
|
||||
}
|
||||
|
||||
.rb-page-header > :first-child img,
|
||||
.rb-page-header > img {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.md-typeset .rb-page-header h1 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rb-page-header p {
|
||||
margin: 0.2rem 0 0;
|
||||
}
|
||||
|
||||
/* A page that names its logo next to the title floats it right; the logo
|
||||
keeps its own box instead of shifting the counters below. */
|
||||
.md-typeset img[align="right"] {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
object-fit: contain;
|
||||
margin: 0 0 0.6rem 1rem;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* Logos are drawn for a light background: they keep one in dark mode. */
|
||||
.md-typeset img[src*="assets/logos/"] {
|
||||
padding: 2px;
|
||||
border-radius: 2px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* Headline figures, read as one line of numbers */
|
||||
.rb-stats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.4rem 2rem;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
|
||||
gap: 0.6rem 1.5rem;
|
||||
margin: 1rem 0 1.5rem;
|
||||
padding: 0.8rem 1rem;
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 4px;
|
||||
background: var(--rb-surface);
|
||||
}
|
||||
|
||||
.md-typeset .rb-stat p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.rb-stat .rb-stat-value {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
display: block;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.rb-stat .rb-stat-label {
|
||||
font-size: 0.8rem;
|
||||
font-size: 0.75rem;
|
||||
color: var(--rb-text-secondary);
|
||||
display: block;
|
||||
}
|
||||
@@ -61,22 +239,38 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.rb-badge-success { background: #e8f5e9; color: #1b5e20; }
|
||||
.rb-badge-warning { background: #fff3e0; color: #a33f00; }
|
||||
.rb-badge-danger { background: #ffebee; color: #b71c1c; }
|
||||
.rb-badge-info { background: #e3f2fd; color: #0d47a1; }
|
||||
.rb-badge-muted { background: #eceff1; color: #455a64; }
|
||||
.rb-badge-success { background: var(--rb-ok-bg); color: var(--rb-ok-fg); }
|
||||
.rb-badge-warning { background: var(--rb-warn-bg); color: var(--rb-warn-fg); }
|
||||
.rb-badge-danger { background: var(--rb-err-bg); color: var(--rb-err-fg); }
|
||||
.rb-badge-info { background: var(--rb-info-bg); color: var(--rb-info-fg); }
|
||||
.rb-badge-muted { background: var(--rb-muted-bg); color: var(--rb-muted-fg); }
|
||||
|
||||
[data-md-color-scheme="slate"] .rb-badge-success { background: #1b5e20; color: #a5d6a7; }
|
||||
[data-md-color-scheme="slate"] .rb-badge-warning { background: #e65100; color: #ffcc80; }
|
||||
[data-md-color-scheme="slate"] .rb-badge-danger { background: #b71c1c; color: #ef9a9a; }
|
||||
[data-md-color-scheme="slate"] .rb-badge-info { background: #0d47a1; color: #90caf9; }
|
||||
[data-md-color-scheme="slate"] .rb-badge-muted { background: #37474f; color: #b0bec5; }
|
||||
/* A link inside a badge keeps the badge's tested colour pair. */
|
||||
.md-typeset .rb-badge a:not(.md-button),
|
||||
.md-typeset a.rb-badge {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* Inline code inside a link reads as a link in both schemes. */
|
||||
.md-typeset a code {
|
||||
color: var(--rb-link);
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.md-typeset table:not([class]) {
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.md-typeset table:not([class]) th {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.md-typeset table:not([class]) th,
|
||||
.md-typeset table:not([class]) td {
|
||||
padding: 0.55em 0.9em;
|
||||
}
|
||||
|
||||
.md-typeset__scrollwrap {
|
||||
@@ -141,20 +335,27 @@
|
||||
|
||||
/* Hashes are printed whole so the search finds them, and wrap on phones */
|
||||
.rb-hash {
|
||||
font-family: monospace;
|
||||
font-family: var(--md-code-font);
|
||||
font-size: 0.78rem;
|
||||
color: var(--rb-text-secondary);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* Key and value cards: the header row is empty, so it is not drawn and
|
||||
not announced. */
|
||||
.rb-meta-card table {
|
||||
margin: 1rem 0 !important;
|
||||
}
|
||||
|
||||
.rb-meta-card th {
|
||||
.rb-meta-card thead,
|
||||
.md-typeset table thead:not(:has(th:not(:empty))) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.rb-meta-card td {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.rb-meta-card td:first-child {
|
||||
font-weight: 600;
|
||||
color: var(--rb-text-secondary);
|
||||
@@ -168,6 +369,24 @@
|
||||
padding: 0.55em 0.8em;
|
||||
}
|
||||
|
||||
/* Buttons. The dark scheme draws them in the link colour: the header indigo
|
||||
would sit at 3:1 on the page. */
|
||||
[data-md-color-scheme="slate"] .md-typeset .md-button {
|
||||
color: var(--rb-link);
|
||||
border-color: var(--rb-link);
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .md-button--primary {
|
||||
background-color: var(--rb-link);
|
||||
color: #1e2129;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset .md-button:is(:hover, :focus) {
|
||||
background-color: var(--rb-accent);
|
||||
border-color: var(--rb-accent);
|
||||
color: #1e2129;
|
||||
}
|
||||
|
||||
.md-typeset a:not(.md-button):not(.headerlink):not(.rb-badge) {
|
||||
color: var(--rb-link);
|
||||
text-decoration: underline;
|
||||
@@ -179,7 +398,7 @@
|
||||
text-decoration-thickness: 0.14em;
|
||||
}
|
||||
|
||||
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
|
||||
:where(a, button, input, select, textarea, label, [tabindex]):focus-visible {
|
||||
outline: 3px solid var(--rb-accent);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
@@ -240,6 +459,316 @@
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Admonitions: one meaning per colour.
|
||||
blue note, info, abstract, example, question, quote: background
|
||||
teal tip: a shortcut
|
||||
green success: what it looks like when it worked
|
||||
orange warning: a risk of losing data or using the wrong file
|
||||
red danger, failure, bug: something is broken or refused */
|
||||
.md-typeset :is(.admonition, details):is(.info, .abstract, .example, .question, .quote, .note) {
|
||||
border-color: #448aff;
|
||||
}
|
||||
|
||||
.md-typeset :is(.info, .abstract, .example, .question, .quote, .note) > :is(.admonition-title, summary) {
|
||||
background-color: rgba(68, 138, 255, 0.1);
|
||||
}
|
||||
|
||||
.md-typeset :is(.info, .abstract, .example, .question, .quote, .note) > :is(.admonition-title, summary)::before {
|
||||
background-color: #448aff;
|
||||
-webkit-mask-image: var(--md-admonition-icon--info);
|
||||
mask-image: var(--md-admonition-icon--info);
|
||||
}
|
||||
|
||||
.md-typeset :is(.admonition, details).tip {
|
||||
border-color: #00897b;
|
||||
}
|
||||
|
||||
.md-typeset .tip > :is(.admonition-title, summary) {
|
||||
background-color: rgba(0, 137, 123, 0.1);
|
||||
}
|
||||
|
||||
.md-typeset .tip > :is(.admonition-title, summary)::before {
|
||||
background-color: #00897b;
|
||||
-webkit-mask-image: var(--rb-icon-shortcut);
|
||||
mask-image: var(--rb-icon-shortcut);
|
||||
}
|
||||
|
||||
.md-typeset :is(.admonition, details):is(.danger, .failure, .bug, .error) {
|
||||
border-color: #d32f2f;
|
||||
}
|
||||
|
||||
.md-typeset :is(.danger, .failure, .bug, .error) > :is(.admonition-title, summary) {
|
||||
background-color: rgba(211, 47, 47, 0.1);
|
||||
}
|
||||
|
||||
.md-typeset :is(.danger, .failure, .bug, .error) > :is(.admonition-title, summary)::before {
|
||||
background-color: #d32f2f;
|
||||
-webkit-mask-image: var(--md-admonition-icon--danger);
|
||||
mask-image: var(--md-admonition-icon--danger);
|
||||
}
|
||||
|
||||
:root {
|
||||
--rb-icon-shortcut: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2a7 7 0 0 0-7 7c0 2.38 1.19 4.47 3 5.74V17a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1v-2.26c1.81-1.27 3-3.36 3-5.74a7 7 0 0 0-7-7M9 21a1 1 0 0 0 1 1h4a1 1 0 0 0 1-1v-1H9z"/></svg>');
|
||||
}
|
||||
|
||||
/* Code: shell commands wrap so the whole command shows on a phone, and the
|
||||
copy button keeps its own column instead of covering the end. */
|
||||
.md-typeset :is(.language-sh, .language-bash, .language-shell, .language-console,
|
||||
.language-powershell, .language-ps1, .language-pwsh, .language-cmd, .language-bat) pre > code,
|
||||
.md-typeset .rb-cmd pre > code {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
padding-right: 2.6rem;
|
||||
}
|
||||
|
||||
/* Terminal output: what the screen shows, not something to type */
|
||||
.md-typeset .rb-terminal pre,
|
||||
.md-typeset .rb-terminal pre > code {
|
||||
background: var(--rb-terminal-bg);
|
||||
color: var(--rb-terminal-fg);
|
||||
}
|
||||
|
||||
.md-typeset .rb-terminal pre {
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.md-typeset .rb-terminal pre::before {
|
||||
content: "Terminal output";
|
||||
display: block;
|
||||
padding: 0.5rem 1.2em 0;
|
||||
font: 600 0.65rem var(--md-text-font-family);
|
||||
color: var(--rb-terminal-label);
|
||||
}
|
||||
|
||||
.md-typeset .rb-terminal .md-code__button {
|
||||
color: var(--rb-terminal-label);
|
||||
}
|
||||
|
||||
/* Numbered steps */
|
||||
.md-typeset ol.rb-steps,
|
||||
.md-typeset .rb-steps > ol {
|
||||
counter-reset: rb-step;
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.md-typeset ol.rb-steps > li,
|
||||
.md-typeset .rb-steps > ol > li {
|
||||
counter-increment: rb-step;
|
||||
position: relative;
|
||||
margin: 0 0 1.2rem;
|
||||
padding-left: 2.6rem;
|
||||
min-height: 1.8rem;
|
||||
}
|
||||
|
||||
.md-typeset ol.rb-steps > li::before,
|
||||
.md-typeset .rb-steps > ol > li::before {
|
||||
content: counter(rb-step);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1.8rem;
|
||||
height: 1.8rem;
|
||||
border-radius: 4px;
|
||||
background: var(--md-primary-fg-color);
|
||||
color: #fff;
|
||||
font-weight: 700;
|
||||
line-height: 1.8rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
[data-md-color-scheme="slate"] .md-typeset ol.rb-steps > li::before,
|
||||
[data-md-color-scheme="slate"] .md-typeset .rb-steps > ol > li::before {
|
||||
background: var(--rb-link);
|
||||
color: #1e2129;
|
||||
}
|
||||
|
||||
/* Card grids. Material's grid cards keep their markup; the hover shadow
|
||||
gives way to a stronger border. */
|
||||
.md-typeset .grid.cards {
|
||||
--md-shadow-z2: 0 0 #0000;
|
||||
}
|
||||
|
||||
.md-typeset .grid.cards > :is(ul, ol) > li,
|
||||
.md-typeset .grid > .card {
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.md-typeset .grid.cards > :is(ul, ol) > li:is(:hover, :focus-within),
|
||||
.md-typeset .grid > .card:is(:hover, :focus-within) {
|
||||
border-color: var(--rb-border-strong);
|
||||
}
|
||||
|
||||
.rb-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
|
||||
gap: 0.8rem;
|
||||
margin: 1rem 0 1.5rem;
|
||||
}
|
||||
|
||||
.rb-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
padding: 0.8rem;
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 4px;
|
||||
background: var(--md-default-bg-color);
|
||||
}
|
||||
|
||||
.rb-card:is(:hover, :focus-within) {
|
||||
border-color: var(--rb-border-strong);
|
||||
}
|
||||
|
||||
.md-typeset .rb-card p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.md-typeset .rb-card .md-button {
|
||||
margin-top: auto;
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.md-typeset .rb-card-logo,
|
||||
.md-typeset .grid.cards img.rb-card-logo {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
object-fit: contain;
|
||||
padding: 4px;
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Path chip */
|
||||
.md-typeset code.rb-path {
|
||||
padding: 0.15rem 0.45rem;
|
||||
border: 1px solid var(--rb-border);
|
||||
border-radius: 2px;
|
||||
font-size: 0.8em;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
/* Content tabs (operating systems): the selected tab reads clearly. */
|
||||
.md-typeset .tabbed-labels > label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--rb-text-secondary);
|
||||
}
|
||||
|
||||
.md-typeset .tabbed-set > input:checked + label,
|
||||
.md-typeset .tabbed-labels > label:hover {
|
||||
color: var(--rb-link);
|
||||
}
|
||||
|
||||
.md-typeset .tabbed-labels::before {
|
||||
background: var(--rb-link);
|
||||
}
|
||||
|
||||
/* Inline coverage bar beside a number */
|
||||
.rb-bar {
|
||||
display: inline-block;
|
||||
width: 5rem;
|
||||
height: 0.4rem;
|
||||
margin-right: 0.4rem;
|
||||
border-radius: 2px;
|
||||
background: var(--rb-border);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.rb-bar > span {
|
||||
display: block;
|
||||
width: var(--v, 0%);
|
||||
height: 100%;
|
||||
border-radius: 2px;
|
||||
background: var(--rb-ok-fg);
|
||||
}
|
||||
|
||||
/* Diagrams written by scripts/sitediagrams.py. Text takes the page font and
|
||||
colour, boxes take the theme surface, so the drawing follows the palette
|
||||
toggle. Each diagram carries a wide and a narrow layout. */
|
||||
.md-typeset .rb-figure {
|
||||
margin: 1.2rem 0 1.6rem;
|
||||
}
|
||||
|
||||
.md-typeset .rb-figure svg {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
max-width: 52rem;
|
||||
color: var(--md-default-fg-color);
|
||||
}
|
||||
|
||||
.md-typeset .rb-figure figcaption {
|
||||
max-width: 44em;
|
||||
margin: 0.4rem 0 0;
|
||||
font-size: 0.75rem;
|
||||
font-style: normal;
|
||||
color: var(--rb-text-secondary);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.rb-diagram text {
|
||||
font-family: var(--md-text-font-family);
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-box {
|
||||
fill: var(--rb-diagram-fill);
|
||||
stroke: var(--rb-diagram-stroke);
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-accent {
|
||||
stroke: var(--rb-diagram-accent);
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-line {
|
||||
stroke: var(--rb-diagram-stroke);
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-head {
|
||||
fill: var(--rb-diagram-stroke);
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-num {
|
||||
fill: var(--rb-diagram-accent);
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-numtext {
|
||||
fill: var(--md-default-bg-color);
|
||||
}
|
||||
|
||||
.rb-diagram .rb-d-muted {
|
||||
fill: var(--rb-text-secondary);
|
||||
}
|
||||
|
||||
.rb-diagram-narrow {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (max-width: 37.5em) {
|
||||
.rb-diagram-wide {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.rb-diagram-narrow {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* The sidebar title stays legible over the list scrolling under it. */
|
||||
@media (min-width: 76.25em) {
|
||||
.md-nav--primary > .md-nav__title,
|
||||
.md-nav--secondary > .md-nav__title {
|
||||
background: var(--md-default-bg-color);
|
||||
border-bottom: 1px solid var(--rb-border);
|
||||
}
|
||||
}
|
||||
|
||||
/* Material's compact footer defaults sit just below WCAG AA on the dark bar. */
|
||||
.md-footer-meta .md-copyright {
|
||||
color: #b5b5b5;
|
||||
@@ -249,6 +778,116 @@
|
||||
color: #b8c6ff !important;
|
||||
}
|
||||
|
||||
/* 404 page */
|
||||
.rb-notfound-search {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 44px;
|
||||
padding: 0.55em 1.2em;
|
||||
border: 1px solid currentColor;
|
||||
border-radius: 2px;
|
||||
color: var(--rb-link);
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (max-width: 44.984375em) {
|
||||
/* Tables with an action column become one block per row, so the button
|
||||
is never behind a horizontal scroll (site.js marks them). */
|
||||
.md-typeset__table:has(table[data-rb-stack]) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] thead {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] tbody,
|
||||
.md-typeset table[data-rb-stack] tr {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] tr {
|
||||
padding: 0.5rem 0;
|
||||
border-top: 1px solid var(--rb-border);
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] td {
|
||||
display: block;
|
||||
position: relative;
|
||||
min-height: 1.6rem;
|
||||
padding: 0.25rem 0.6rem 0.25rem 8.4rem;
|
||||
border: 0;
|
||||
text-align: left !important;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] td::before {
|
||||
content: attr(data-label);
|
||||
position: absolute;
|
||||
top: 0.25rem;
|
||||
left: 0.6rem;
|
||||
width: 7.4rem;
|
||||
font-weight: 600;
|
||||
color: var(--rb-text-secondary);
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] td .md-button {
|
||||
margin: 0 0.3rem 0.3rem 0;
|
||||
}
|
||||
|
||||
.md-typeset table[data-rb-stack] td:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Other wide tables scroll with their first column held in place. */
|
||||
.md-typeset table:not([class]):not([data-rb-stack]) :is(td, th):first-child {
|
||||
position: sticky;
|
||||
left: 0;
|
||||
max-width: 40vw;
|
||||
background: var(--md-default-bg-color);
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.md-typeset table:not([class]):not([data-rb-stack]) th:first-child {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
/* On a phone every command wraps: the end of a one-liner (the "| sh"
|
||||
that makes it work) is never off-screen. Terminal output keeps its
|
||||
columns and scrolls. */
|
||||
.md-typeset pre > code {
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
padding-right: 2.6rem;
|
||||
}
|
||||
|
||||
.md-typeset :is(.rb-terminal, .language-text) pre > code {
|
||||
white-space: pre;
|
||||
overflow-wrap: normal;
|
||||
}
|
||||
|
||||
/* Text on reference pages stays at 12 px or more on a phone. */
|
||||
.rb-file-entry ul,
|
||||
.rb-sys-file ul,
|
||||
.rb-hash {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.rb-page-header {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.rb-table-filter {
|
||||
grid-template-columns: 1fr;
|
||||
@@ -257,6 +896,14 @@
|
||||
.rb-table-filter label {
|
||||
grid-column: auto;
|
||||
}
|
||||
|
||||
.rb-stats {
|
||||
grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr));
|
||||
}
|
||||
|
||||
.rb-stat .rb-stat-value {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
|
||||
+75
-12
@@ -2,16 +2,65 @@
|
||||
(() => {
|
||||
"use strict";
|
||||
|
||||
// A heading's words without its permalink sign.
|
||||
const headingText = (heading) => {
|
||||
const copy = heading.cloneNode(true);
|
||||
copy.querySelectorAll(".headerlink").forEach((link) => link.remove());
|
||||
return copy.textContent.trim();
|
||||
};
|
||||
|
||||
const textFromHeading = (element) => {
|
||||
let cursor = element;
|
||||
while (cursor) {
|
||||
cursor = cursor.previousElementSibling;
|
||||
if (!cursor) break;
|
||||
if (/^H[1-6]$/.test(cursor.tagName)) {
|
||||
return cursor.textContent.trim();
|
||||
return headingText(cursor);
|
||||
}
|
||||
}
|
||||
return document.querySelector("h1")?.textContent.trim() || "Data table";
|
||||
const title = document.querySelector("h1");
|
||||
return title ? headingText(title) : "Data table";
|
||||
};
|
||||
|
||||
// A scroller is a stop in the tab order only while it overflows: a table
|
||||
// in a closed block or a hidden tab gains its overflow later.
|
||||
const markScrollable = (container, heading) => {
|
||||
if (!container) return;
|
||||
container.dataset.rbHeading = heading;
|
||||
if (container.scrollWidth > container.clientWidth + 1) {
|
||||
container.tabIndex = 0;
|
||||
container.setAttribute("role", "region");
|
||||
container.setAttribute("aria-label", `${heading}, scrollable table`);
|
||||
} else if (container.getAttribute("role") === "region") {
|
||||
container.removeAttribute("tabindex");
|
||||
container.removeAttribute("role");
|
||||
container.removeAttribute("aria-label");
|
||||
}
|
||||
};
|
||||
|
||||
const recheckScrollable = () => {
|
||||
document.querySelectorAll(".md-typeset__scrollwrap[data-rb-heading]").forEach((container) => {
|
||||
markScrollable(container, container.dataset.rbHeading);
|
||||
});
|
||||
};
|
||||
|
||||
// A table whose rows end in an action (a download button) is laid out one
|
||||
// block per row on a phone, each cell under its column name, so the action
|
||||
// never sits behind a horizontal scroll.
|
||||
const stackActionTable = (table) => {
|
||||
if (!table.querySelector("tbody .md-button")) return;
|
||||
const labels = Array.from(table.querySelectorAll("thead th")).map((cell) =>
|
||||
cell.textContent.trim()
|
||||
);
|
||||
if (!labels.length) return;
|
||||
table.dataset.rbStack = "true";
|
||||
table.querySelectorAll("tbody tr").forEach((row) => {
|
||||
Array.from(row.children).forEach((cell, column) => {
|
||||
if (labels[column] && !cell.hasAttribute("data-label")) {
|
||||
cell.setAttribute("data-label", labels[column]);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const enhanceTables = () => {
|
||||
@@ -27,7 +76,9 @@
|
||||
if (first && !first.hasAttribute("scope")) first.setAttribute("scope", "row");
|
||||
});
|
||||
|
||||
const container = table.parentElement;
|
||||
// The scrolling element is Material's scrollwrap, one level above
|
||||
// the table's own wrapper.
|
||||
const container = table.closest(".md-typeset__scrollwrap") || table.parentElement;
|
||||
const heading = textFromHeading(container);
|
||||
if (!table.querySelector("caption")) {
|
||||
const caption = document.createElement("caption");
|
||||
@@ -35,11 +86,8 @@
|
||||
caption.textContent = heading;
|
||||
table.prepend(caption);
|
||||
}
|
||||
if (container && container.scrollWidth > container.clientWidth) {
|
||||
container.tabIndex = 0;
|
||||
container.setAttribute("role", "region");
|
||||
container.setAttribute("aria-label", `${heading}, scrollable table`);
|
||||
}
|
||||
stackActionTable(table);
|
||||
markScrollable(container, heading);
|
||||
|
||||
const rows = Array.from(table.querySelectorAll("tbody tr"));
|
||||
if (rows.length < 20 || !container || container.dataset.rbFilter === "true") {
|
||||
@@ -88,10 +136,15 @@
|
||||
const heading = dialog.querySelector("h1, h2, h3");
|
||||
dialog.setAttribute("aria-label", heading?.textContent.trim() || "Site search");
|
||||
});
|
||||
document.querySelectorAll('[role="progressbar"]').forEach((progress) => {
|
||||
if (!progress.hasAttribute("aria-label") && !progress.hasAttribute("aria-labelledby")) {
|
||||
progress.setAttribute("aria-label", "Loading page");
|
||||
}
|
||||
// The page-load bar is drawn for the eye only: the new page announces
|
||||
// itself when it arrives.
|
||||
document.querySelectorAll(".md-progress").forEach((progress) => {
|
||||
progress.setAttribute("aria-hidden", "true");
|
||||
});
|
||||
// Material wraps each copy button in a nav element: one unnamed
|
||||
// navigation landmark per code block. The button stays, the landmark goes.
|
||||
document.querySelectorAll("nav.md-code__nav").forEach((nav) => {
|
||||
nav.setAttribute("role", "none");
|
||||
});
|
||||
};
|
||||
|
||||
@@ -130,6 +183,16 @@
|
||||
resolveFileAddress();
|
||||
};
|
||||
|
||||
let resizeTimer = 0;
|
||||
window.addEventListener("resize", () => {
|
||||
window.clearTimeout(resizeTimer);
|
||||
resizeTimer = window.setTimeout(recheckScrollable, 150);
|
||||
});
|
||||
document.addEventListener("toggle", recheckScrollable, true);
|
||||
document.addEventListener("change", (event) => {
|
||||
if (event.target.matches?.(".tabbed-set > input")) recheckScrollable();
|
||||
});
|
||||
|
||||
if (window.document$?.subscribe) {
|
||||
window.document$.subscribe(enhance);
|
||||
} else if (document.readyState === "loading") {
|
||||
|
||||
Reference in new issue
Block a user