[READ-ONLY] Mirror of https://github.com/jmrplens/PyOctaveBand. [Python3] Octave-Band and Fractional Octave-Band filter. For signal in time domain. jmrplens.github.io/PyOctaveBand/
acoustics audio filter frequency frequency-analysis frequency-domain octave python3 signal time-domain
0

Configure Feed

Select the types of activity you want to include in your feed.

Take the standards information out of the sidebar and prototype chip pills

The sidebar keeps the tree and nothing else. The annotation experiment is
deleted rather than switched off: the data-toc-style dimension and its five
presentations, the annotation line, the hover card and its keyboard handling,
the page subtitle and the section landing tables all go, and with them the
attrs['data-chips'] classification in the sidebar config and in the API
generator, plus the shortened sidebar labels the chips had justified.

SidebarSublist.astro and Sidebar.astro are back to the smallest diff against
upstream Starlight that still gives me non-collapsible groups, the
overview-first convention where a group label links to its landing page, and
the fold toggle the API treatments need. Each file header now records what
differs from upstream and why, so a future Starlight upgrade is cheap to
reconcile.

Everything about what governs a page now lives in the page header run, which
takes its data from the frontmatter bibliography. That run gains two more
presentations to compare against the quiet text version: outlined pills, so
the chips look like the links they are, and the same pills with a faint
category tint. Both keep the eight chips of the densest page on one line and
clear 5.9:1 on their text in either theme.

José M. Requena Plens (Jul 26, 2026, 1:28 AM +0200) 04e159b9 baf7e819

+744 -1716
+186 -366
TOC-REDESIGN-NOTES.md
··· 1 - # Standards info in the docs: variant prototypes 1 + # Standards in the docs: page header chips and the API sidebar 2 2 3 3 Experimental branch `feat/toc-sidebar-info`. It does not merge and has no PR: 4 - it exists so I can look at several ways of surfacing "what standard governs 5 - this page", plus three ways of dealing with the API reference tree, switch 6 - between them live, and then keep one. 4 + it exists so I can compare presentations live on the running site and then 5 + keep one. The target is the desktop reader; a design only has to survive a 6 + phone, it is not judged there. 7 7 8 - The predecessor of this branch, `exp/sidebar-standard-chips` 9 - (`SIDEBAR-CHIPS-NOTES.md` there), put a coloured badge on every sidebar item. 10 - The classification work was right; the presentation was too loud. 8 + ## The sidebar decision is final 11 9 12 - There are now two independent families: 10 + The sidebar carries no standards information. None. Not a chip, not an 11 + annotation line, not a hover card. 13 12 14 - - **Page chips** (`data-page-chips`), the newest and the one I would ship: a 15 - quiet run under the H1, derived from the page's own frontmatter 16 - bibliography, every item linking to its full entry at the bottom. 17 - - **Sidebar info** (`data-toc-style`), five ways of putting the same 18 - information into the navigation tree instead. 13 + Two rounds of prototypes went the other way and both failed for the same 14 + reason. `exp/sidebar-standard-chips` put a coloured badge on every item and 15 + was too loud. This branch then tried five quieter presentations (`focus`, 16 + `annotate`, `hover`, `clean`, `none`) and the best of them was still paying 17 + for information on every row of a very tall tree that a single row in the 18 + page header gives for free. The whole mechanism is now deleted rather than 19 + switched off: 19 20 20 - The two can be viewed together or separately, and the target is the desktop 21 - reader: this is a reference library that gets read next to an editor, so a 22 - design is judged on the desktop layout first and only has to survive a phone. 21 + - gone: the `data-toc-style` attribute and its five variants, the annotation 22 + line, the hover card and its keyboard handling, the page subtitle, the 23 + section landing tables; 24 + - gone: `SectionStandards.astro`, `src/styles/toc-info.css`, the 25 + `attrs['data-chips']` classification in `site/astro.config.mjs` and the 26 + `_API_CHIPS` table in `scripts/generate_api_docs.py`, together with the 27 + parsing that consumed them; 28 + - gone with them: the shortened sidebar labels the chips had justified, so 29 + entries like "Reverberation-time prediction (Sabine, Eyring, Arau)" read in 30 + full again. 23 31 24 - ## Mechanism 32 + `SidebarSublist.astro` and `Sidebar.astro` are back to the smallest diff 33 + against upstream Starlight 0.41.3 that still implements this repo's 34 + conventions. What differs from upstream, and why, is documented in each file 35 + header: groups are never collapsible, a group's marked landing entry is 36 + consumed so the group label itself becomes the link (the overview-first 37 + convention), and the API reference group carries a class plus a fold toggle 38 + for the API treatments below. That last one is the only piece of this 39 + experiment left in the sidebar, and it comes out if the API split is ever 40 + done with a plugin. 25 41 26 - ### Page chips: derived from the bibliography 42 + ## Page chips 27 43 28 - The page chips take nothing from a hand-maintained list. Each page already 29 - carries a Zod-typed `references` block in its frontmatter (schema in 30 - `src/content.config.ts`), rendered as the APA-7 References section at the 31 - bottom by `References.astro`. `src/lib/reference-chips.ts` turns that same 32 - list into the header run, so the two views cannot disagree: 44 + One run under the H1: the standards that govern the page, then the works its 45 + methods are attributed to. Nothing in the navigation. 46 + 47 + ### Derived from the bibliography, not from a second list 48 + 49 + Each page already carries a Zod-typed `references` block in its frontmatter 50 + (schema in `src/content.config.ts`), rendered as the APA-7 References section 51 + at the bottom by `References.astro`. `src/lib/reference-chips.ts` turns that 52 + same list into the header run, so the two are views of one source and cannot 53 + drift apart: 33 54 34 55 - `type: standard`, and `type: report` when it carries a document number, 35 - become the teal run. The designation collapses to its family, so 36 - `ISO 10140-2:2010`, `-3` and `-4` become one `ISO 10140` chip, and 56 + become the standards run. The designation collapses to its family, so 57 + `ISO 10140-2:2010`, `-3` and `-4` become one `ISO 10140`, and 37 58 `ANSI S3.5-1997 (R2017)` becomes `ANSI S3.5`. 38 - - `type: article` and `type: book` become the amber run, as author and year: 39 - `Schroeder 1965`, `Francois & Garrison 1982`, `Foret et al. 2011`. The 40 - Spanish build joins two authors with "y", like the bibliography does. 59 + - `type: article` and `type: book` become the references run, as author and 60 + year: `Schroeder 1965`, `Francois & Garrison 1982`, `Foret et al. 2011`. 61 + The Spanish build joins two authors with "y", like the bibliography does. 41 62 - `type: web` and numberless reports have neither a designation nor a citable 42 63 author-date pair, so they stay in the bibliography only. 43 64 - Five standards and three works fit on one line at a desktop reading width. 44 65 Anything past that folds into one `+N more` link to the References section. 45 - - Pages with no `references` render nothing at all, which is most of the API 46 - reference and the getting-started page. 66 + - Pages with no `references` render nothing at all. 47 67 48 - Every chip is a link to its entry, which now carries a stable id 49 - (`referenceAnchors` derives the ids from the frontmatter order, so the 50 - alphabetical sort of the bibliography does not move them). The target entry 51 - clears the sticky header and is highlighted on arrival, so a click on 52 - `ISO 10140` lands the reader on the right line of a fourteen-entry list. 68 + Every chip links to its entry, which carries a stable id (`referenceAnchors` 69 + derives the ids from frontmatter order, so the alphabetical sort of the 70 + bibliography does not move them). The target clears the sticky header and is 71 + highlighted on arrival, so a click on `ISO 10140` lands the reader on the 72 + right line of a fourteen-entry list. 53 73 54 - ### Sidebar info: the earlier classification 74 + ### Presentations 55 75 56 - The per-item sidebar classification travels as a JSON string in Starlight's 57 - sanctioned `attrs` passthrough, under `data-chips`: 58 - 59 - - `site/astro.config.mjs` builds it for the guides with the helpers `S(...)` 60 - (governing standard, teal), `T(...)` (named reference, amber) and 61 - `chips(...)`. 62 - - `scripts/generate_api_docs.py` emits the same shape for the API modules into 63 - `site/src/generated/api-sidebar.mjs`, from the module docstrings. 64 - - `site/src/components/SidebarSublist.astro` parses it, renders one `<Badge>` 65 - per chip inside a `.sidebar-chips` run in the link, and strips the raw 66 - attribute so it never reaches the DOM. 67 - - `site/src/styles/toc-info.css` decides what that run looks like, or whether 68 - it is shown at all. All of its selectors are unlayered, so they win over 69 - Starlight's layered styles without specificity tricks. 70 - 71 - Two more components exist for the `clean` variant: `PageTitle.astro` (the 72 - subtitle under the H1) and `SectionStandards.astro` (the "standards by page" 73 - table on section landings). Every one of these components always renders and 74 - is only displayed by CSS when its variant is active, so switching never needs 75 - a rebuild. 76 - 77 - The active variant is an attribute on `<html>`, applied before first paint by 78 - an inline script in `Head.astro` and persisted in `localStorage`. The same 79 - script stamps `data-area` (`guides` or `api`) from the URL, mounts the 80 - floating switcher, wires the API caret, and mirrors the section table heading 81 - into "On this page" when the clean variant is active. 82 - 83 - Chip text is language neutral (designations and author names), so EN and ES 84 - share one classification and there is nothing extra to translate. Only the 85 - table headings, the visually hidden prefix and the back link are localized. 86 - 87 - ## Variant matrix 88 - 89 - Page chips, attribute `data-page-chips` on `<html>`, localStorage key 90 - `pageChips`: 76 + `data-page-chips` on `<html>`, localStorage key `pageChips`: 91 77 92 78 | Value | What the reader sees | 93 79 | --- | --- | 94 - | `header` (default) | The run under the H1, standards then named works, each chip a link into the References section. | 95 - | `off` | Nothing; the page header is untouched. | 80 + | `header` | Tinted text, one small colour dot leading each category run. No boxes. | 81 + | `pills` (my recommendation) | The same content as outlined pills: 12 px text, 1 px category-coloured border at 38 % alpha, fully rounded, transparent inside. | 82 + | `filled` | The same pills with a faint category tint inside (18 % dark, 12 % light). | 83 + | `off` | Nothing. | 96 84 97 - Sidebar info, attribute `data-toc-style` on `<html>`, localStorage key 98 - `tocStyle`: 99 - 100 - | Value | What the reader sees | 101 - | --- | --- | 102 - | `focus` (default) | Annotation line under the label, only for the items of the section the reader is currently in. Rest of the tree untouched. | 103 - | `annotate` | The same line on every item of the whole tree. | 104 - | `hover` | Nothing at rest. A hairline dotted marker appears on annotated items while the pointer or the keyboard focus is inside the sidebar, and the info opens in a small floating card on hover or focus. On touch devices it falls back to the always-visible line. | 105 - | `clean` | Nothing in the sidebar. The info moves to a subtitle under the H1 and to a table on each section landing page. The subtitle yields whenever the page chips run is on, since both sit under the H1 and say the same thing. | 106 - | `none` | Nothing in the sidebar and no section tables. The pre-experiment tree. | 107 - 108 - API sidebar, attribute `data-api-style`, localStorage key `apiStyle`: 85 + `data-api-style`, localStorage key `apiStyle`: 109 86 110 87 | Value | What the reader sees | 111 88 | --- | --- | ··· 115 92 116 93 ### How to switch 117 94 118 - - The round "UX" button at the bottom right of every page opens the switcher, 119 - now with three groups: page chips, sidebar info, API sidebar. The choice is 120 - remembered across pages and reloads. 121 - - Without the widget, from the console: 122 - `document.documentElement.dataset.pageChips = 'off'`, 123 - `document.documentElement.dataset.tocStyle = 'annotate'`, 95 + - The round "UX" button at the bottom right opens the switcher, now with two 96 + groups: page chips and API sidebar. The choice is remembered across pages 97 + and reloads. 98 + - From the console: `document.documentElement.dataset.pageChips = 'pills'`, 124 99 `document.documentElement.dataset.apiStyle = 'collapsed'`. To make it stick, 125 - `localStorage.setItem('tocStyle', 'annotate')` and so on. 126 - - To go back to the shipped look, pick `off`, `none` and `inline`. 127 - - The interesting comparison is `header` + `none` (page chips carrying 128 - everything, sidebar untouched) against `off` + `focus` (sidebar carrying 129 - everything) and `header` + `focus` (both). 100 + `localStorage.setItem('pageChips', 'pills')`. 101 + - Defaults for a fresh browser are `header` and `split`. 130 102 131 103 ## Screenshots 132 104 133 - In `ux-variants2/`. Desktop is 1440 x 1000, mobile is 390 x 844 with the menu 134 - open. Sidebar-only crops for the sidebar variants, full viewport where the 135 - page itself carries the information. 105 + In `ux-variants2/`, all desktop at 1440 x 1000 unless the name says otherwise. 106 + The screenshots of the five rejected sidebar variants were removed along with 107 + the code; they are in the branch history if they are ever wanted again. 136 108 137 - Page chips: 138 - 139 - | File | What it shows | 140 - | --- | --- | 141 - | `pagechips-many-dark-desktop-en.png` | The dense case, dark: Laboratory Insulation Measurement, five ISO families and three books on one line. | 142 - | `pagechips-many-light-desktop-en.png` | The same in light. | 143 - | `pagechips-many-dark-desktop-es.png` | The same page in Spanish, under a two-line H1. | 144 - | `pagechips-overflow-light-desktop-en.png` | Underwater sound propagation, sixteen references: one standard, three works and `+12 more`. | 145 - | `pagechips-single-dark-desktop-en.png` | A page with one reference and no standard. | 146 - | `pagechips-none-light-desktop-en.png` | A page with no `references` block: nothing rendered. | 147 - | `pagechips-anchorjump-light-desktop-en.png` | After clicking the `ISO 10140` chip: the matching bibliography entry, highlighted and clear of the header. | 148 - | `pagechips-anchorjump-dark-desktop-es.png` | The same jump on the Spanish build. | 149 - 150 - Sidebar info: 109 + Page chips, on a page with eight chips (Laboratory Insulation Measurement), a 110 + page with a single chip, a page that overflows the caps and a page with no 111 + references at all: 151 112 152 113 | File | What it shows | 153 114 | --- | --- | 154 - | `focus-dark-desktop-en.png` | Focus, dark. Only the current section is annotated. | 155 - | `focus-light-desktop-en.png` | Focus, light. | 156 - | `focus-dark-desktop-es.png` | Focus on the Spanish tree: same chips, no translation needed. | 157 - | `focus-dark-mobile-en.png` | Focus inside the mobile menu. | 158 - | `annotate-dark-desktop-en.png` | Every item annotated, dark. | 159 - | `annotate-light-desktop-en.png` | Every item annotated, light. | 160 - | `annotate-dark-mobile-en.png` | Every item annotated, phone. | 161 - | `hover-resting-dark-desktop-en.png` | Hover variant at rest: no marks at all. It is byte for byte the same image as `none-dark-desktop-en.png`, which is the whole point of the variant. | 162 - | `hover-card-dark-desktop-en.png` | Hover variant engaged: markers visible, card open. | 163 - | `hover-card-light-desktop-en.png` | The same in light. | 164 - | `hover-card-dark-mobile-en.png` | The card at 390 px in a hover-capable browser. | 165 - | `hover-touchfallback-simulated-dark-mobile-en.png` | What a real phone gets instead: the annotation line. Simulated, see the caveat below. | 166 - | `clean-subtitle-dark-desktop-en.png` | Clean: subtitle under the H1, sidebar empty. | 167 - | `clean-subtitle-light-desktop-en.png` | The same in light. | 168 - | `clean-subtitle-light-desktop-es.png` | The same in Spanish. | 169 - | `clean-subtitle-dark-mobile-en.png` | Subtitle on a phone. | 170 - | `clean-sectiontable-light-desktop-en.png` | Section landing table, light. | 171 - | `clean-sectiontable-dark-desktop-en.png` | Section landing table, dark, with its entry in "On this page". | 172 - | `clean-sectiontable-light-desktop-es.png` | Section landing table in Spanish. | 173 - | `clean-sectiontable-dark-mobile-en.png` | The table stacked for a phone. | 174 - | `none-dark-desktop-en.png`, `none-dark-mobile-en.png` | Reference: today's sidebar. | 115 + | `chips-header-many-dark-desktop-en.png` | Text run, dark. | 116 + | `chips-header-many-light-desktop-en.png` | Text run, light. | 117 + | `chips-header-many-dark-desktop-es.png` | Text run in Spanish, under a two-line H1. | 118 + | `chips-header-single-dark-desktop-en.png` | Text run, one reference and no standard. | 119 + | `chips-header-overflow-light-desktop-en.png` | Text run with `+12 more`. | 120 + | `chips-pills-many-dark-desktop-en.png` | Outlined pills, dark. | 121 + | `chips-pills-many-light-desktop-en.png` | Outlined pills, light. | 122 + | `chips-pills-many-dark-desktop-es.png` | Outlined pills in Spanish. | 123 + | `chips-pills-single-light-desktop-en.png` | Outlined pills, single chip. | 124 + | `chips-pills-overflow-dark-desktop-en.png` | Outlined pills with the `+12 more` pill. | 125 + | `chips-filled-many-dark-desktop-en.png` | Filled pills, dark. | 126 + | `chips-filled-many-light-desktop-en.png` | Filled pills, light. | 127 + | `chips-filled-many-light-desktop-es.png` | Filled pills in Spanish. | 128 + | `chips-filled-single-dark-desktop-en.png` | Filled pills, single chip. | 129 + | `chips-none-light-desktop-en.png` | A page with no `references` block: nothing rendered. | 130 + | `chips-anchorjump-light-desktop-en.png` | After clicking `ISO 10140`: the matching entry, highlighted and clear of the header. | 131 + | `chips-anchorjump-dark-desktop-es.png` | The same jump on the Spanish build. | 132 + 133 + Sidebar and API: 134 + 135 + | File | What it shows | 136 + | --- | --- | 137 + | `sidebar-final-dark-desktop-en.png` | The tree as it stays: no chips, no annotations. | 175 138 | `api-inline-guidepage-dark-desktop-en.png` | API tree expanded in place on a guide page. | 176 139 | `api-collapsed-guidepage-dark-desktop-en.png` | API group folded behind a caret. | 177 140 | `api-split-guidepage-dark-desktop-en.png` | API group reduced to a label with an arrow. | 178 141 | `api-inline-apipage-dark-desktop-en.png` | Status quo on an API page, scrolled to the reference group. | 179 - | `api-collapsed-apipage-dark-desktop-en.png` | Collapsed mode on an API page: it opens the group by itself and adds the caret next to the label. | 180 - | `api-split-apipage-dark-desktop-en.png` | Split mode on an API page: back link plus reference only. | 181 - | `api-split-apipage-dark-mobile-en.png` | The same on a phone. | 182 - | `switcher-widget-dark-desktop-en.png` | The switcher panel with its three groups. | 142 + | `api-collapsed-apipage-dark-desktop-en.png` | Collapsed treatment on an API page: it opens the group by itself and adds the caret. | 143 + | `api-split-apipage-dark-desktop-en.png` | Split on an API page: back link plus reference only. | 144 + | `api-split-apipage-dark-mobile-en.png` | The same at 390 px. | 145 + | `switcher-widget-dark-desktop-en.png` | The switcher, now two groups. | 183 146 184 - ## Design critique 147 + ## Design critique of the three chip presentations 185 148 186 - **page chips.** The best of everything here, and the first version that does 187 - not have to fight for space. Under the H1 there is a full content column of 188 - horizontal room, so five standards and three named works sit on one line 189 - without wrapping and without displacing anything; the run reads as the 190 - dateline of a standard, which is exactly the register this library wants. Two 191 - coloured dots carry the whole legend, so the text can stay tinted rather than 192 - boxed and never approaches the pill look that was rejected before. 149 + **header (text run).** The quietest, and the one that reads most like the 150 + dateline of a standard: no boxes, two coloured dots carrying the entire 151 + legend, the run sitting under the H1 as if it were part of the title block. 152 + Its flaw is the one that prompted this round: the chips are links and they 153 + look exactly like plain text, so nothing tells the reader they can click 154 + through to the bibliography. The affordance appears only on hover, which is 155 + the definition of undiscoverable. 193 156 194 - Three things make it better than every sidebar variant rather than just 195 - prettier. It is derived, so it cannot rot: the header and the bibliography are 196 - the same list, and a new reference in the frontmatter shows up in the header 197 - with no second edit. It is linked, so the chip is not a label but a way in: 198 - clicking `ISO 10140` scrolls to the exact entry, highlighted, in a 199 - fourteen-entry list. And it costs the navigation nothing at all, which means 200 - it composes with any sidebar variant instead of competing with it. 157 + **pills (outlined).** My recommendation. It buys the affordance with the 158 + least possible ink: a 1 px border at 38 % alpha and a full radius, 12 px text 159 + instead of 14. The shape says "interactive", the border colour says which 160 + category, and nothing is filled, so the run stays a hairline drawing rather 161 + than a block of colour. The noise objection that killed the sidebar chips 162 + genuinely does not transfer: that was a decoration repeated down 150 rows of 163 + a tall tree, this is one row per page in a band that is otherwise empty. 164 + Eight pills still fit on one line at a desktop width, and the gap between the 165 + two category runs is wider than the gap inside a run, so the standards and 166 + the named works still read as two groups without needing the dots. 201 167 202 - Its honest weaknesses. It only helps once you are on the page, so it cannot 203 - answer "which of these neighbouring pages do I want", which is the one thing 204 - the sidebar annotation does. On literature-heavy pages the caps bite: 205 - Underwater sound propagation shows one standard, three works and `+12 more`, 206 - which is truthful but close to useless as a summary, and the choice of which 207 - three works survive is just frontmatter order. The family collapse is a 208 - judgement call: `ISO 10140` is what a reader recognises, but the chip then 209 - links to Part 2 specifically, and someone who wanted Part 4 has to look one 210 - line down. Finally it inherits whatever the frontmatter says, so a sloppy 211 - `references` block shows up in the header rather than staying quietly at the 212 - bottom, which is a feature for me and a risk for a careless page. 168 + **filled.** The same pills with a faint category tint. It groups each chip 169 + slightly better and makes the category legible without reading the border 170 + colour, but it adds a third visual channel (fill) that repeats what the 171 + border and the text colour already say, and at eight chips the row starts to 172 + read as a strip of status badges rather than as a citation line. The fill 173 + also has to stay very low (18 % dark, 12 % light) to avoid that, and at that 174 + alpha it is nearly invisible on the dark theme anyway, which makes it a lot 175 + of machinery for very little. 213 176 214 - **focus.** The strongest of the five sidebar variants. The tree stays exactly as quiet as it is 215 - today except for the five or six rows the reader is actually working in, and 216 - those rows answer the only question the annotation is there to answer: which 217 - of these neighbouring pages do I want. The annotation sits at 11 px, indented 218 - under the label, one step below the label colour, so the eye reads label 219 - first and metadata second without effort. Weaknesses: the annotated block is 220 - a visible island in an otherwise plain tree, which looks slightly arbitrary 221 - until you notice it tracks the current section; multi-standard rows such as 222 - "Laboratory Insulation Measurement" wrap to two annotation lines and the run 223 - dots then fall mid-line, which reads ragged; and if a reader wants to compare 224 - two distant sections it shows nothing useful. 177 + Ranking: `pills`, then `header`, then `filled`. If discoverability turns out 178 + not to be worth any ink at all, `header` is the fallback and nothing else 179 + changes; the three styles share all their markup. 225 180 226 - **annotate.** Honest and complete, and the least clever. It also roughly 227 - doubles the height of the tree, which on this site means a very long scroll, 228 - and it puts an almost equal density of text on every row, so the labels stop 229 - standing out as the thing you click. It is the right baseline to compare 230 - against and the wrong thing to ship. If it were shipped, the annotation 231 - should probably be limited to one designation per item. 232 - 233 - **hover.** The cleanest resting state by a wide margin and the only variant 234 - that costs zero vertical space. Its structural problem is that nearly every 235 - page in this library is governed by something, so the affordance would mark 236 - almost every row and therefore distinguish nothing. That is why the marker is 237 - now gone at rest and only fades in while the pointer or the keyboard focus is 238 - inside the sidebar; even then it reads as texture across the whole tree. The 239 - card itself is good: it is anchored to the trailing edge of the link so it can 240 - never push the sidebar into horizontal scroll, it has a 250 ms intent delay, 241 - it opens on keyboard focus, and Escape dismisses it without moving the focus. 242 - Its remaining cost is that it hides the row underneath while open, because the 243 - sidebar is a scroll container and a card placed outside it would be clipped. 244 - It is a desktop interaction, and on touch it falls back to the always-visible 245 - line; with the desktop weighting that is a footnote rather than a 246 - disqualification, and it makes `hover` the only sidebar variant that can be 247 - combined with the page chips without adding a single pixel to the resting 248 - layout. 249 - 250 - **clean.** Superseded. Its subtitle under the H1 was the right instinct, and 251 - the page chips are that instinct done properly: derived from the bibliography 252 - instead of from a parallel hand-written list, linked instead of inert, and 253 - capped instead of unbounded. The two now exclude each other by CSS, since 254 - both sit under the H1 and say the same thing, and the only reason the older 255 - subtitle is still in the branch is so the two can be compared side by side by 256 - toggling `pageChips` off. What is left of `clean` on its own merits is the 257 - section landing table, and that is the weakest part: it duplicates the bullet 258 - list already above it, where each bullet names its standards in prose, it 259 - introduces a heading the markdown pipeline never sees so its "On this page" 260 - entry has to be injected client side, and on a phone the three columns only 261 - work because they collapse into a stacked list. 262 - 263 - **none.** The control. Worth flipping to now and then to check how much any 264 - of the others actually cost. 265 - 266 - **API modes.** `inline` is what makes the sidebar unmanageable today: the API 267 - tree is far longer than the guide tree and it is always open. `collapsed` is 268 - the cheap fix and behaves well, though a caret is a single small target for a 269 - very large piece of navigation. `split` is the most comfortable to read on an 270 - API page, since the guide groups disappear entirely, but it is also the most 271 - custom, and it exposes a real flaw of the current information architecture: 272 - the API items still live three levels deep, under "Reference" and then "API 273 - reference", so module names like `loudness_moore_glasberg_time` wrap even when 274 - they are the only thing on screen. 275 - 276 - ## Recommendation 277 - 278 - Ship `header` page chips, `hover` for the sidebar, `split` for the API tree, 279 - done with the plugin rather than with my CSS. 280 - 281 - **Page chips carry the feature.** They are the only version of this idea that 282 - is derived rather than duplicated, that is a link rather than a label, and 283 - that costs the navigation nothing. If only one thing ships, it is this, and it 284 - should ship whatever happens to the sidebar. 285 - 286 - **The sidebar then only has to answer the one question the header cannot: 287 - which of these neighbouring pages do I want.** With the page chips in place, 288 - that is a much smaller job, and it changes which sidebar variant wins. 289 - 290 - My earlier recommendation was `focus`, chosen partly because `hover` was 291 - penalised for being unusable on touch. Weighting the desktop the way the 292 - library is actually read, that penalty mostly disappears and the ranking 293 - flips: 294 - 295 - - `hover` gives a resting tree that is pixel for pixel today's tree, with the 296 - standards a pointer-hover or a Tab away, and it adds nothing to the height 297 - of a sidebar that is already long. Next to a header run that is always 298 - visible, "quiet until asked" is the right register for the tree, and the two 299 - never repeat themselves on screen at the same time. 300 - - `focus` remains the best variant if the sidebar has to work on its own, and 301 - it is the safer choice if the page chips do not ship. It is redundant with 302 - them on the current page and useful on the neighbours, which is a defensible 303 - reason to keep it too. 304 - - `annotate` and `clean` are out. `annotate` doubles the height of the tree 305 - for information the header now gives for free, and `clean` is superseded by 306 - construction. 307 - 308 - So: `header` + `hover` as the shipping pair, with `header` + `focus` as the 309 - conservative alternative if the reveal-on-hover marker turns out to be too 310 - subtle in practice. `header` + `none` is also a perfectly respectable answer 311 - and the cheapest to maintain: everything in the page header, nothing in the 312 - sidebar at all. 313 - 314 - Two follow-ups before shipping the page chips: 315 - 316 - 1. Sort the amber run rather than taking frontmatter order, so the three works 317 - that survive the cap are the three the page actually leans on. Sorting by 318 - year, or an explicit `primary: true` flag in the frontmatter, would both 319 - work; the flag is more honest and costs one schema field. 320 - 2. Decide whether the family collapse should link to the first part or to the 321 - References heading. Landing on Part 2 when the chip says `ISO 10140` is 322 - slightly arbitrary, and jumping to the section start would be defensible. 323 - 324 - If `focus` or `hover` ships as well, trim the sidebar classification to two 325 - standards plus one reference per item so the wrapped three-designation rows 326 - stop happening; the full list is in the header now. 181 + One caveat before shipping pills: the border sits at 1.2:1 against the light 182 + background and 2.3:1 against the dark one. That is fine as decoration, since 183 + the link is identified by its text, which clears 5.9:1 to 8.1:1, but it would 184 + not pass as a UI component boundary under WCAG 1.4.11 if anyone argued that 185 + it is one. Raising the border alpha fixes it and costs some quiet; I left it 186 + quiet. 327 187 328 188 ## `split` versus `starlight-sidebar-topics` 329 189 330 - My `split` prototype and the `starlight-sidebar-topics` plugin solve the same 331 - problem, and the plugin solves it better in the ways that matter long term. 332 - 333 - What they share: one sidebar for the guides, another for the API reference, 334 - and a way back. What differs: 190 + My `split` prototype and the plugin solve the same problem, and the plugin 191 + solves it better in the ways that matter long term. 335 192 336 193 - The plugin makes each topic a root sidebar, so the API items lose the two 337 194 wrapper levels they currently sit under, and the topic switcher is a real 338 - navigation control at the top of the sidebar rather than a link that only 339 - appears on some pages. My prototype only hides things with CSS, so the 340 - nesting, and the wrapping module names that come with it, stay. 341 - - The plugin's topic labels and badges take per-locale objects, so EN and ES 342 - are handled by the config. Mine hardcodes the back link label in 343 - `Sidebar.astro`. 344 - - The plugin is maintained and documented. Mine is roughly 30 lines of CSS 345 - plus a hand-written back link, and every future Starlight release is my 346 - problem. 195 + navigation control rather than a link that only appears on some pages. My 196 + prototype only hides things with CSS, so the nesting, and the wrapping 197 + module names that come with it, stay. 198 + - The plugin's topic labels and badges take per-locale objects. Mine 199 + hardcodes the back link label in `Sidebar.astro`. 200 + - The plugin is maintained. Mine is about 30 lines of CSS plus a hand-written 201 + back link, and every future Starlight release is my problem. 347 202 348 - What I would want to check before adopting it: this repo already overrides 349 - `Sidebar.astro` and `SidebarSublist.astro`, and the whole "overview first" 350 - group-label-as-link convention lives in that override. If the plugin also 351 - overrides `Sidebar`, one of the two has to give, and reconciling them is the 352 - real cost of the migration. The plugin docs do not say. That is a 353 - one-afternoon experiment, not a blocker. 354 - 355 - So: keep `split` in this branch as the visual argument for splitting, and 356 - implement the split with the plugin rather than with this CSS. 203 + What to check before adopting it: this repo overrides `Sidebar.astro` and 204 + `SidebarSublist.astro`, and the overview-first convention lives in that 205 + override. If the plugin also overrides `Sidebar`, one of the two has to give. 206 + The plugin docs do not say. That is an afternoon, not a blocker. 357 207 358 208 ## Verification 359 209 360 - Checked in Chrome at 1440 x 1000 and at 390 x 844, in both themes, on EN and 361 - ES pages, on a guide page, a section landing and an API page: 210 + Checked in Chrome at 1440 x 1000, both themes, EN and ES, on a guide page and 211 + an API page: 362 212 363 - - All five `data-toc-style` values, both `data-page-chips` values and all 364 - three `data-api-style` values render as intended, including the API caret 365 - toggle and its session memory. 366 - - Page chips: every chip link resolves to an element on the page, on EN and 367 - on ES, on a page with eight chips and on a page with one. The caps produce 368 - `+12 more` on the heaviest page and it links to the References heading. 369 - Pages without a `references` block render no markup at all. With the chips 370 - on, the older `clean` subtitle is never displayed, in any combination. 371 - - The Spanish build localizes the visually hidden run prefixes, the "+N más" 372 - label and the two-author join ("Francois y Garrison 1982"), while 373 - designations and surnames stay language neutral. 374 - - No horizontal overflow of the sidebar in any variant at either width. The 375 - hover card used to cause it and no longer does. 376 - - Keyboard: the hover card opens on `:focus-visible`, Escape dismisses it 377 - without moving the focus, any other key brings it back, and leaving the link 378 - resets it. 379 - - The "Guides" back link used to point at a page that does not exist 380 - (`/guides/getting-started/`); it now points at `/getting-started/` and its 381 - Spanish counterpart, and both answer 200. 213 + - All four `data-page-chips` values and all three `data-api-style` values 214 + render as intended, including the API caret toggle and its session memory. 215 + - The sidebar renders no chips, no annotation line and no hover card in any 216 + state, and no `data-toc-style`, `.sidebar-chips`, `.page-standards` or 217 + `.section-standards` remains anywhere in `site/src` or `scripts/`. 218 + - Every chip link resolves to an element on the page, on EN and on ES, with 219 + eight chips and with one. The caps produce `+12 more` on the heaviest page. 220 + Pages without a `references` block render no markup at all. 221 + - All three chip presentations keep the run on one line at 1440 px on the 222 + densest page. 223 + - Text contrast measured against the composited chip background: 8.08:1 and 224 + 7.24:1 dark, 7.18:1 and 5.94:1 light, all above the 4.5:1 that 12 px text 225 + needs. 382 226 - `pnpm --dir site build` succeeds and the Starlight link validator reports 383 - all internal links valid. 384 - - `pnpm run html-validate` passes. It did not at first: the section table 385 - needed `scope="col"` on its headers, 36 errors across 12 pages. 386 - - `pnpm run pa11y` passes 46 of 46 URLs at WCAG2AA. 387 - - `node scripts/check-i18n-parity.mjs` passes. 227 + all internal links valid; `pnpm run html-validate` passes; `pnpm run pa11y` 228 + passes 46 of 46 URLs at WCAG2AA; `node scripts/check-i18n-parity.mjs` 229 + passes. 388 230 389 - What I could not verify locally: 231 + Known limits: 390 232 391 - - pa11y only exercises the default combination, since it starts with an empty 392 - `localStorage`. That does cover the page chips, which are on by default, but 393 - the other four sidebar variants and two API modes are not covered by the 394 - audit. Colour choices were checked by hand instead: the annotation ink is 395 - about 5.3:1 on the dark sidebar and 5.6:1 on the light one, both above the 396 - 4.5:1 that 11 px text needs. 233 + - pa11y only exercises the default combination, since it starts from an empty 234 + `localStorage`. That covers the `header` style; `pills` and `filled` were 235 + checked by hand with the contrast figures above. 397 236 - One content oddity the chips exposed: the ICAO Annex 16 entry on the 398 - aircraft-noise page carries `designation: "8th ed."`, which is an edition 399 - and not a document number, so no chip is derived for it. The helper skips 400 - designations of that shape rather than printing "8th ed." in the header. The 401 - real fix is in the frontmatter, on both language versions, and I left it 402 - alone here to keep this branch to presentation. 403 - - The touch fallback of the `hover` variant. The automation browser reports 404 - `hover: hover`, so `@media (hover: none)` never applies there and the 405 - screenshot of it is a simulation: the same declarations injected without the 406 - media query. It needs one look on the actual phone. 407 - - Whether the injected "On this page" entry for the clean variant participates 408 - in scroll spy. It does not, since Starlight collects its links at connect 409 - time. It is a prototype-only wart that disappears with the client-side 410 - injection if the variant is chosen. 237 + aircraft-noise page carries `designation: "8th ed."`, an edition rather 238 + than a document number, so no chip is derived for it. The helper skips 239 + designations of that shape rather than printing "8th ed." in the header. 240 + The real fix is in the frontmatter, on both language versions; I left it 241 + alone to keep this branch to presentation. 411 242 412 - ## When a variant is chosen 243 + ## What is prototype scaffolding 413 244 414 - Everything below is prototype scaffolding and comes out: 245 + When a presentation is chosen, these come out: 415 246 416 - - both inline scripts at the bottom of `Head.astro`, and the 417 - `.toc-switcher` rules in `toc-info.css`; 418 - - every branch of `toc-info.css` for the variants not chosen, and the 419 - `data-page-chips` gate around `.page-chips` if the run ships unconditionally; 420 - - `SectionStandards.astro` and its import in `MarkdownContent.astro`, unless 421 - the section table survives; 422 - - the hand-derived subtitle in `PageTitle.astro` (the `.page-standards` 423 - paragraph and its `findCurrent` helper), which the page chips replace; the 424 - override itself stays to host `<PageChips />`; 425 - - the `api-caret` button in `SidebarSublist.astro` if the split is done with 426 - the plugin instead. 247 + - both inline scripts at the bottom of `Head.astro` and the `.toc-switcher` 248 + rules in `src/styles/ux-variants.css`; 249 + - the `data-page-chips` gate and the two presentations not chosen; 250 + - the `api-caret` button in `SidebarSublist.astro` and the `topic-back` link 251 + in `Sidebar.astro`, if the API split is done with the plugin instead. 427 252 428 - What stays whatever the outcome: `src/lib/reference-chips.ts`, 429 - `PageChips.astro` and the bibliography anchors in `References.astro` if the 430 - page chips ship, and the sidebar classification (the `chips()` helpers in 431 - `astro.config.mjs`, the `_API_CHIPS` table in `scripts/generate_api_docs.py` 432 - and the parsing in `SidebarSublist.astro`) if any sidebar variant does. If 433 - only the page chips ship, the whole `data-chips` classification can go: it is 434 - a hand-maintained duplicate of what the frontmatter already says, which is the 435 - strongest argument for the page chips of all. 253 + What stays: `src/lib/reference-chips.ts`, `PageChips.astro`, the minimal 254 + `PageTitle.astro` override that mounts it, and the bibliography anchors and 255 + `:target` highlight in `References.astro`.
+4 -142
scripts/generate_api_docs.py
··· 1096 1096 return "\n".join(out).strip("\n") + "\n" 1097 1097 1098 1098 1099 - # Reference chips for the API sidebar. Each public module maps to either a 1100 - # published standard (teal "chip-standard") or, when no standard governs it, 1101 - # its single most notable reference (amber "chip-theory"). The attribution is 1102 - # taken from the module's own docstring: its cited standard designation, or 1103 - # the author it names. A handful of modules whose docstring names no source 1104 - # carry a minimal, correct canonical reference instead (marked "+" below). 1105 - # Value is (chip text, "s" for standard | "t" for theory). 1106 - _API_CHIPS: dict[str, tuple[tuple[str, str], ...]] = { 1107 - "phonometry.metrology.core": (("IEC 61260", "s"),), 1108 - "phonometry.metrology.parametric_filters": (("IEC 61672", "s"),), 1109 - "phonometry.metrology.equalizer": (("RBJ Cookbook", "t"),), 1110 - "phonometry.metrology.frequencies": (("ISO 266", "s"),), 1111 - "phonometry.metrology.compliance": (("IEC 61260", "s"), ("IEC 61672", "s")), 1112 - "phonometry.metrology.levels": (("IEC 61672", "s"),), 1113 - "phonometry.metrology.calibration": (("IEC 60942", "s"),), 1114 - "phonometry.psychoacoustics.loudness_zwicker": (("ISO 532-1", "s"), ("Zwicker", "t")), 1115 - "phonometry.psychoacoustics.loudness_moore_glasberg": (("ISO 532-2", "s"), ("Moore & Glasberg", "t")), 1116 - "phonometry.psychoacoustics.loudness_moore_glasberg_time": (("ISO 532-3", "s"), ("Moore & Glasberg", "t")), 1117 - "phonometry.psychoacoustics.loudness_ecma": (("ECMA-418-2", "s"),), 1118 - "phonometry.psychoacoustics.loudness_contours": (("ISO 226", "s"),), 1119 - "phonometry.psychoacoustics.sharpness": (("DIN 45692", "s"),), 1120 - "phonometry.psychoacoustics.roughness_ecma": (("ECMA-418-2", "s"),), 1121 - "phonometry.psychoacoustics.tonality": (("ECMA-418-1", "s"),), 1122 - "phonometry.psychoacoustics.tonality_ecma": (("ECMA-418-2", "s"),), 1123 - "phonometry.psychoacoustics.tone_audibility": (("ISO/PAS 20065", "s"),), 1124 - "phonometry.psychoacoustics.fluctuation_strength": (("Fastl & Zwicker", "t"),), 1125 - "phonometry.psychoacoustics.fluctuation_strength_ecma": (("ECMA-418-2", "s"),), 1126 - "phonometry.psychoacoustics.psychoacoustic_annoyance": (("Fastl & Zwicker", "t"),), 1127 - "phonometry.hearing.sti": (("IEC 60268-16", "s"), ("Houtgast & Steeneken", "t")), 1128 - "phonometry.hearing.sii": (("ANSI S3.5", "s"), ("French & Steinberg", "t")), 1129 - "phonometry.hearing.objective_intelligibility": (("Taal et al. 2011", "t"), ("Jensen et al. 2016", "t")), 1130 - "phonometry.hearing.threshold": (("ISO 7029", "s"), ("ISO 389-7", "s")), 1131 - "phonometry.hearing.noise_induced_hearing_loss": (("ISO 1999", "s"),), 1132 - "phonometry.hearing.occupational_exposure": (("ISO 9612", "s"),), 1133 - "phonometry.room.room_acoustics": (("ISO 3382", "s"), ("ISO 18233", "s"), ("Schroeder 1965", "t")), 1134 - "phonometry.room.room_ir": (("ISO 18233", "s"),), 1135 - "phonometry.room.room_noise": (("ANSI S12.2", "s"), ("Beranek 1957", "t"), ("Blazier 1997", "t")), 1136 - "phonometry.room.open_plan": (("ISO 3382-3", "s"),), 1137 - "phonometry.room.reverberation_prediction": (("Sabine", "t"), ("Eyring", "t"), ("Arau", "t")), 1138 - "phonometry.room.enclosed_space_absorption": (("EN 12354-6", "s"),), 1139 - "phonometry.room.image_source": (("Allen & Berkley", "t"),), 1140 - "phonometry.room.steady_field": (("Kuttruff", "t"),), 1141 - "phonometry.building.insulation": (("ISO 16283", "s"), ("ISO 717", "s")), 1142 - "phonometry.building.panel_transmission": (("EN 12354-1", "s"),), 1143 - "phonometry.building.aperture_transmission": (("Hopkins 2007", "t"),), 1144 - "phonometry.building.lab_insulation": (("ISO 10140", "s"),), 1145 - "phonometry.building.survey_insulation": (("ISO 10052", "s"),), 1146 - "phonometry.building.intensity_insulation": (("ISO 15186", "s"),), 1147 - "phonometry.building.flanking_transmission": (("ISO 10848", "s"),), 1148 - "phonometry.building.facade_prediction": (("EN 12354-3", "s"),), 1149 - "phonometry.building.building_prediction": (("EN 12354", "s"),), 1150 - "phonometry.building.building_uncertainty": (("ISO 12999-1", "s"),), 1151 - "phonometry.building.floor_covering_improvement": (("ISO 16251-1", "s"),), 1152 - "phonometry.building.structure_borne_power": (("EN 15657", "s"),), 1153 - "phonometry.building.installed_structure_borne": (("EN 12354-5", "s"),), 1154 - "phonometry.materials.sound_absorption": (("ISO 354", "s"),), 1155 - "phonometry.materials.absorption_rating": (("ISO 11654", "s"),), 1156 - "phonometry.materials.absorption_uncertainty": (("ISO 12999-2", "s"),), 1157 - "phonometry.materials.airflow_resistance": (("ISO 9053", "s"),), 1158 - "phonometry.materials.dynamic_stiffness": (("EN 29052-1", "s"),), 1159 - "phonometry.materials.impedance_tube": (("ISO 10534", "s"), ("ASTM E2611", "s")), 1160 - "phonometry.materials.porous_absorber": (("Delany & Bazley", "t"), ("Miki", "t"), ("Johnson et al.", "t")), 1161 - "phonometry.materials.slow_sound_absorber": (("Jiménez et al.", "t"),), 1162 - "phonometry.materials.diffuser_design": (("Cox & D'Antonio", "t"),), 1163 - "phonometry.materials.scattering_diffusion": (("ISO 17497", "s"), ("Cox & D'Antonio", "t")), 1164 - "phonometry.materials.road_absorption": (("ISO 13472", "s"),), 1165 - "phonometry.vibration.mechanical_mobility": (("ISO 7626", "s"),), 1166 - "phonometry.vibration.point_mobility": (("ISO 7626", "s"),), 1167 - "phonometry.vibration.radiation_efficiency": (("ISO/TS 7849", "s"), ("Cremer & Heckl", "t")), 1168 - "phonometry.vibration.junction_transmission": (("Cremer & Heckl", "t"),), 1169 - "phonometry.vibration.transfer_stiffness": (("ISO 10846", "s"),), 1170 - "phonometry.vibration.human_vibration": (("ISO 2631", "s"), ("ISO 5349", "s"), ("ISO 8041", "s")), 1171 - "phonometry.vibration.multiple_shock_vibration": (("ISO 2631-5", "s"),), 1172 - "phonometry.environmental.outdoor_propagation": (("ISO 9613", "s"), ("Maekawa 1968", "t")), 1173 - "phonometry.environmental.ground_barriers": (("ISO 9613-2", "s"), ("Kurze & Anderson", "t")), 1174 - "phonometry.environmental.atmospheric_refraction": (("Salomons", "t"),), 1175 - "phonometry.environmental.air_absorption": (("ISO 9613-1", "s"),), 1176 - "phonometry.environmental.impulse_prominence": (("NT ACOU 112", "s"),), 1177 - "phonometry.environmental.impulsive_sound": (("ISO/PAS 1996-3", "s"),), 1178 - "phonometry.environmental.rating": (("ISO 1996-1", "s"),), 1179 - "phonometry.environmental.measurement": (("ISO 1996-2", "s"),), 1180 - "phonometry.aircraft.aircraft_noise": (("ICAO Annex 16", "s"), ("IEC 61265", "s")), 1181 - "phonometry.aircraft.atmospheric_absorption": (("SAE ARP 5534", "s"),), 1182 - "phonometry.aircraft.airport_noise": (("ECAC Doc 29", "s"),), 1183 - "phonometry.aircraft.anp_fleet": (("ECAC Doc 29", "s"),), 1184 - "phonometry.aircraft.rotorcraft_noise": (("Olsen et al. 2024", "t"),), 1185 - "phonometry.environmental.wind_turbine_noise": (("IEC 61400-11", "s"), ("ISO 1996-2", "s")), 1186 - "phonometry.underwater.acoustics": (("ISO 18405", "s"),), 1187 - "phonometry.underwater.propagation": (("Francois & Garrison", "t"),), 1188 - "phonometry.underwater.sound_speed": (("Mackenzie 1981", "t"),), 1189 - "phonometry.underwater.sonar_equation": (("Urick", "t"),), 1190 - "phonometry.underwater.ocean_ambient_noise": (("Wenz 1962", "t"),), 1191 - "phonometry.underwater.seabed_reflection": (("Jensen et al.", "t"),), 1192 - "phonometry.underwater.ship_radiated_noise": (("ISO 17208", "s"),), 1193 - "phonometry.underwater.ship_traffic_noise": (("JOMOPANS-ECHO", "t"),), 1194 - "phonometry.underwater.pile_driving_noise": (("ISO 18406", "s"),), 1195 - "phonometry.underwater.numerical_propagation": (("Jensen et al.", "t"),), 1196 - "phonometry.emission.sound_power": (("ISO 3744", "s"), ("ISO 3741", "s")), 1197 - "phonometry.emission.sound_power_intensity": (("ISO 9614", "s"),), 1198 - "phonometry.emission.sound_power_reverberation": (("ISO 3741", "s"),), 1199 - "phonometry.emission.intensity": (("IEC 61043", "s"), ("ISO 9614", "s")), 1200 - "phonometry.emission.vibration_sound_power": (("ISO/TS 7849", "s"),), 1201 - "phonometry.emission.declaration": (("ISO 4871", "s"),), 1202 - "phonometry.electroacoustics.distortion": (("IEC 60268-3", "s"), ("AES17", "s")), 1203 - "phonometry.electroacoustics.frequency_response": (("Bendat & Piersol", "t"),), 1204 - "phonometry.electroacoustics.swept_sine": (("Farina 2000", "t"), ("Novak et al. 2015", "t")), 1205 - "phonometry.electroacoustics.piston": (("Beranek & Mellow", "t"),), 1206 - "phonometry.electroacoustics.loudspeaker": (("IEC 60268-5", "s"),), 1207 - "phonometry.electroacoustics.microphone": (("IEC 60268-4", "s"),), 1208 - "phonometry.noise_control.silencers": (("Munjal", "t"), ("Bies & Hansen", "t")), 1209 - "phonometry.noise_control.hvac": (("Bies & Hansen", "t"),), 1210 - "phonometry.noise_control.enclosures": (("Bies & Hansen", "t"),), 1211 - "phonometry.broadcast.program_loudness": (("ITU-R BS.1770", "s"), ("EBU R 128", "s")), 1212 - "phonometry.metrology.uncertainty": (("JCGM 100", "s"),), 1213 - "phonometry.metrology.random_data": (("Rice 1945", "t"), ("Bendat & Piersol", "t")), 1214 - "phonometry.metrology.spectra": (("Welch 1967", "t"), ("Thomson 1982", "t")), 1215 - "phonometry.metrology.miso": (("Bendat & Piersol", "t"),), 1216 - "phonometry.metrology.time_frequency": (("Bendat & Piersol", "t"),), 1217 - "phonometry.metrology.signals": (("Bendat & Piersol", "t"),), 1218 - "phonometry.metrology.phase": (("Farina 2000", "t"),), 1219 - "phonometry.metrology.cepstrum": (("Havelock et al.", "t"), ("Bendat & Piersol", "t")), 1220 - "phonometry.metrology.synchronous_average": (("McFadden 1987", "t"),), 1221 - "phonometry.metrology.inversion": (("Kirkeby & Nelson", "t"),), 1222 - "phonometry.simulation.fdtd": (("Botteldooren 1995", "t"),), 1223 - "phonometry.metrology.correlation": (("Knapp & Carter", "t"), ("Bendat & Piersol", "t")), 1224 - "phonometry.metrology.envelope": (("Bendat & Piersol", "t"),), 1225 - } 1226 - 1227 - 1228 1099 def render_sidebar(pages: list[ModuleDoc]) -> str: 1229 1100 """Render the Starlight sidebar fragment (ESM, imported by astro.config).""" 1230 1101 1231 1102 def js(text: str) -> str: 1232 1103 return "'" + text.replace("\\", "\\\\").replace("'", "\\'") + "'" 1233 - 1234 - def item(page: ModuleDoc) -> str: 1235 - slug = f"reference/api/{page.section.key}/{page.slug}" 1236 - chip_list = _API_CHIPS.get(page.module) 1237 - if not chip_list: 1238 - return f" {js(slug)}," 1239 - parsed = [ 1240 - {"text": text, "class": "chip-standard" if kind == "s" else "chip-theory"} 1241 - for text, kind in chip_list 1242 - ] 1243 - data = json.dumps(parsed, ensure_ascii=False) 1244 - return f" {{ slug: {js(slug)}, attrs: {{ 'data-chips': {js(data)} }} }}," 1245 1104 1246 1105 lines = [ 1247 1106 "// Auto-generated by scripts/generate_api_docs.py (make api-docs).", ··· 1264 1123 " items: [", 1265 1124 ] 1266 1125 ) 1267 - lines.extend(item(page) for page in by_section[section.key]) 1126 + lines.extend( 1127 + f" {js(f'reference/api/{section.key}/{page.slug}')}," 1128 + for page in by_section[section.key] 1129 + ) 1268 1130 lines.extend([" ],", " },"]) 1269 1131 lines.extend([" ],", "};", ""]) 1270 1132 return "\n".join(lines)
+69 -76
site/astro.config.mjs
··· 8 8 import rehypeKatex from 'rehype-katex'; 9 9 import { apiSidebar } from './src/generated/api-sidebar.mjs'; 10 10 11 - // Sidebar reference chips (see src/components/SidebarSublist.astro). 12 - // S = teal standard chip, T = amber theory/investigator chip; chips(...) 13 - // threads a list through the `attrs.data-chips` passthrough as JSON. 14 - const S = (text) => ({ text, class: 'chip-standard' }); 15 - const T = (text) => ({ text, class: 'chip-theory' }); 16 - const chips = (...items) => ({ attrs: { 'data-chips': JSON.stringify(items) } }); 17 - 18 11 // Converts deprecated HTML align attributes (emitted by markdown table 19 12 // alignment) to CSS text-align, for WCAG2AA compliance (pa11y), and makes 20 13 // wide tables keyboard-scrollable: Starlight renders markdown tables as ··· 260 253 // Default article body plus the unified APA-7 references section 261 254 // rendered from the typed frontmatter bibliography. 262 255 MarkdownContent: './src/components/MarkdownContent.astro', 263 - // Default H1 plus the optional standards/references subtitle line 264 - // (TOC-info variant "clean"; see TOC-REDESIGN-NOTES.md). 256 + // Default H1 plus the page header chips run derived from the page's 257 + // own `references` frontmatter (see TOC-REDESIGN-NOTES.md). 265 258 PageTitle: './src/components/PageTitle.astro', 266 259 }, 267 260 customCss: [ ··· 270 263 './src/styles/theme-tables.css', 271 264 './src/styles/splash-menu.css', 272 265 './src/styles/sidebar.css', 273 - './src/styles/toc-info.css', 266 + './src/styles/ux-variants.css', 274 267 ], 275 268 social: [ 276 269 { icon: 'github', label: 'GitHub', href: 'https://github.com/jmrplens/phonometry' }, ··· 342 335 translations: { es: 'Análisis de señal' }, 343 336 items: [ 344 337 { slug: 'guides/sections/core-signal-analysis', attrs: { 'data-group-link': true } }, 345 - { slug: 'guides/sound-level-meter', ...chips(S('IEC 61672'), S('IEC 61260'), S('IEC 60942')) }, 338 + 'guides/sound-level-meter', 346 339 { 347 340 label: 'Octave filtering', 348 341 translations: { es: 'Filtrado en octavas' }, 349 342 items: [ 350 343 { slug: 'guides/sections/octave-filtering', attrs: { 'data-group-link': true } }, 351 - { slug: 'guides/filter-banks', ...chips(S('IEC 61260'), S('ISO 266')) }, 352 - { slug: 'guides/block-processing', ...chips(S('IEC 61260'), S('IEC 61672')) }, 353 - { slug: 'guides/multichannel', ...chips(S('IEC 61260'), S('IEC 61672')) }, 344 + 'guides/filter-banks', 345 + 'guides/block-processing', 346 + 'guides/multichannel', 354 347 ], 355 348 }, 356 349 { ··· 358 351 translations: { es: 'Niveles y ponderación' }, 359 352 items: [ 360 353 { slug: 'guides/sections/levels-weighting', attrs: { 'data-group-link': true } }, 361 - { slug: 'guides/weighting', ...chips(S('IEC 61672'), S('ISO 7196'), S('ISO 226'), T('Fletcher & Munson')) }, 362 - { slug: 'guides/time-weighting', ...chips(S('IEC 61672')) }, 363 - { slug: 'guides/levels', ...chips(S('IEC 61672'), S('ISO 1996-1')) }, 354 + 'guides/weighting', 355 + 'guides/time-weighting', 356 + 'guides/levels', 364 357 ], 365 358 }, 366 359 { ··· 368 361 translations: { es: 'Señales y espectros' }, 369 362 items: [ 370 363 { slug: 'guides/sections/signals-spectra', attrs: { 'data-group-link': true } }, 371 - { slug: 'guides/spectral-analysis', ...chips(T('Welch 1967'), T('Harris 1978'), T('Thomson 1982')) }, 372 - { slug: 'guides/miso-coherence', ...chips(T('Bendat & Piersol')) }, 373 - { slug: 'guides/time-frequency', ...chips(T('Bendat & Piersol')) }, 374 - { slug: 'guides/cepstrum-echoes', ...chips(T('Havelock et al.'), T('Bendat & Piersol')) }, 375 - { slug: 'guides/synchronous-averaging', ...chips(T('McFadden 1987')) }, 376 - { slug: 'guides/correlation-delay', ...chips(T('Knapp & Carter')) }, 377 - { slug: 'guides/test-signals', ...chips(S('IEC 60268-1'), T('Bendat & Piersol')) }, 378 - { slug: 'guides/system-measurement', ...chips(T('Golay 1961'), T('Kirkeby & Nelson'), T('Müller & Massarani')) }, 364 + 'guides/spectral-analysis', 365 + 'guides/miso-coherence', 366 + 'guides/time-frequency', 367 + 'guides/cepstrum-echoes', 368 + 'guides/synchronous-averaging', 369 + 'guides/correlation-delay', 370 + 'guides/test-signals', 371 + 'guides/system-measurement', 379 372 ], 380 373 }, 381 374 { ··· 383 376 translations: { es: 'Calibración e incertidumbre' }, 384 377 items: [ 385 378 { slug: 'guides/sections/calibration-uncertainty', attrs: { 'data-group-link': true } }, 386 - { slug: 'guides/calibration', ...chips(S('IEC 60942'), S('IEC 61672-3')) }, 387 - { slug: 'guides/gum-uncertainty', ...chips(S('JCGM 100'), S('JCGM 101')) }, 388 - { slug: 'guides/data-qualification', ...chips(T('Rice 1945'), T('Wald & Wolfowitz'), T('Bendat & Piersol')) }, 379 + 'guides/calibration', 380 + 'guides/gum-uncertainty', 381 + 'guides/data-qualification', 389 382 ], 390 383 }, 391 384 ], ··· 400 393 translations: { es: 'Psicoacústica' }, 401 394 items: [ 402 395 { slug: 'guides/sections/psychoacoustics', attrs: { 'data-group-link': true } }, 403 - { slug: 'guides/loudness', ...chips(S('ISO 532'), S('ISO 226'), S('ECMA-418-2'), T('Fletcher & Munson')) }, 404 - { slug: 'guides/sound-quality', ...chips(S('DIN 45692'), S('ECMA-418-2'), T('Fastl & Zwicker')) }, 405 - { slug: 'guides/tone-prominence', label: 'Prominent Discrete Tones', translations: { es: 'Tonos discretos prominentes' }, ...chips(S('ECMA-418-1'), S('ECMA-74')) }, 406 - { slug: 'guides/tone-audibility', label: 'Objective audibility of tones in noise', translations: { es: 'Audibilidad objetiva de tonos en ruido' }, ...chips(S('ISO/PAS 20065'), S('ISO 1996-2'), S('DIN 45681')) }, 407 - { slug: 'guides/psychoacoustic-annoyance', ...chips(T('Fastl & Zwicker'), T('Osses et al. 2016')) }, 396 + 'guides/loudness', 397 + 'guides/sound-quality', 398 + 'guides/tone-prominence', 399 + 'guides/tone-audibility', 400 + 'guides/psychoacoustic-annoyance', 408 401 ], 409 402 }, 410 403 { ··· 412 405 translations: { es: 'Habla' }, 413 406 items: [ 414 407 { slug: 'guides/sections/speech', attrs: { 'data-group-link': true } }, 415 - { slug: 'guides/speech-transmission', ...chips(S('IEC 60268-16'), T('Houtgast & Steeneken')) }, 416 - { slug: 'guides/speech-intelligibility', ...chips(S('ANSI S3.5'), T('French & Steinberg')) }, 417 - { slug: 'guides/objective-intelligibility', ...chips(T('Taal et al. 2011'), T('Jensen et al. 2016')) }, 408 + 'guides/speech-transmission', 409 + 'guides/speech-intelligibility', 410 + 'guides/objective-intelligibility', 418 411 ], 419 412 }, 420 413 { ··· 422 415 translations: { es: 'Audición y exposición' }, 423 416 items: [ 424 417 { slug: 'guides/sections/hearing-exposure', attrs: { 'data-group-link': true } }, 425 - { slug: 'guides/hearing-threshold', ...chips(S('ISO 7029'), S('ISO 389-7')) }, 426 - { slug: 'guides/noise-induced-hearing-loss', label: 'Noise-induced hearing loss', translations: { es: 'Pérdida auditiva inducida por ruido' }, ...chips(S('ISO 1999'), T('Passchier-Vermeer')) }, 427 - { slug: 'guides/occupational-exposure', label: 'Occupational Noise Exposure', translations: { es: 'Exposición al ruido en el trabajo' }, ...chips(S('ISO 9612')) }, 418 + 'guides/hearing-threshold', 419 + 'guides/noise-induced-hearing-loss', 420 + 'guides/occupational-exposure', 428 421 ], 429 422 }, 430 423 ], ··· 439 432 translations: { es: 'Acústica de salas' }, 440 433 items: [ 441 434 { slug: 'guides/sections/room-acoustics', attrs: { 'data-group-link': true } }, 442 - { slug: 'guides/room-acoustics', ...chips(S('ISO 3382'), S('ISO 18233'), T('Schroeder 1965')) }, 443 - { slug: 'guides/room-image-sources', ...chips(T('Allen & Berkley'), T('Kuttruff')) }, 444 - { slug: 'guides/room-noise', ...chips(S('ANSI S12.2'), T('Beranek 1957'), T('Blazier 1997')) }, 445 - { slug: 'guides/reverberation-prediction', label: 'Reverberation-time prediction', translations: { es: 'Predicción del tiempo de reverberación' }, ...chips(S('EN 12354-6'), T('Sabine'), T('Eyring'), T('Arau')) }, 446 - { slug: 'guides/enclosed-space-absorption', label: 'Sound absorption in enclosed spaces', translations: { es: 'Absorción sonora en recintos' }, ...chips(S('EN 12354-6'), S('ISO 354')) }, 435 + 'guides/room-acoustics', 436 + 'guides/room-image-sources', 437 + 'guides/room-noise', 438 + 'guides/reverberation-prediction', 439 + 'guides/enclosed-space-absorption', 447 440 ], 448 441 }, 449 442 { ··· 451 444 translations: { es: 'Aislamiento acústico' }, 452 445 items: [ 453 446 { slug: 'guides/sections/sound-insulation', attrs: { 'data-group-link': true } }, 454 - { slug: 'guides/insulation-field', ...chips(S('ISO 16283'), S('ISO 717'), S('ISO 12999-1')) }, 455 - { slug: 'guides/insulation-lab', ...chips(S('ISO 10140'), S('ISO 15186'), S('ISO 10848'), S('ISO 717')) }, 456 - { slug: 'guides/insulation-prediction', label: 'Predicting Sound Insulation', translations: { es: 'Predicción del aislamiento acústico' }, ...chips(S('EN 12354'), T('Hopkins')) }, 457 - { slug: 'guides/panel-sound-insulation', ...chips(T('Bies & Hansen'), T('Cremer & Heckl')) }, 458 - { slug: 'guides/dynamic-stiffness', label: 'Dynamic stiffness of resilient materials', translations: { es: 'Rigidez dinámica de materiales resilientes' }, ...chips(S('EN 29052-1')) }, 447 + 'guides/insulation-field', 448 + 'guides/insulation-lab', 449 + 'guides/insulation-prediction', 450 + 'guides/panel-sound-insulation', 451 + 'guides/dynamic-stiffness', 459 452 ], 460 453 }, 461 454 ], ··· 465 458 translations: { es: 'Materiales y superficies' }, 466 459 items: [ 467 460 { slug: 'guides/sections/materials-surfaces', attrs: { 'data-group-link': true } }, 468 - { slug: 'guides/materials', ...chips(S('ISO 11654'), S('ISO 354'), S('ISO 10534'), S('ISO 9053')) }, 469 - { slug: 'guides/porous-absorbers', ...chips(T('Delany & Bazley'), T('Miki'), T('Johnson et al.'), T('Maa')) }, 470 - { slug: 'guides/surface-scattering', ...chips(S('ISO 17497'), S('ISO 13472'), T('Cox & D\'Antonio')) }, 461 + 'guides/materials', 462 + 'guides/porous-absorbers', 463 + 'guides/surface-scattering', 471 464 ], 472 465 }, 473 466 { ··· 480 473 translations: { es: 'Fuentes de ruido estructural' }, 481 474 items: [ 482 475 { slug: 'guides/sections/structure-borne', attrs: { 'data-group-link': true } }, 483 - { slug: 'guides/mechanical-mobility', label: 'Mechanical mobility and the FRF family', translations: { es: 'Movilidad mecánica y la familia de FRF' }, ...chips(S('ISO 7626'), T('Cremer & Heckl')) }, 484 - { slug: 'guides/junction-transmission', ...chips(T('Cremer & Heckl'), T('Craik')) }, 485 - { slug: 'guides/transfer-stiffness', label: 'Transfer stiffness of resilient elements', translations: { es: 'Rigidez dinámica de transferencia' }, ...chips(S('ISO 10846')) }, 486 - { slug: 'guides/vibration-sound-power', label: 'Sound power from surface vibration', translations: { es: 'Potencia acústica desde vibración' }, ...chips(S('ISO/TS 7849')) }, 487 - { slug: 'guides/structure-borne-power', label: 'Structure-borne sound power of equipment', translations: { es: 'Potencia sonora estructural de equipos' }, ...chips(S('EN 15657'), S('ISO 9611')) }, 488 - { slug: 'guides/installed-structure-borne', label: 'Installed structure-borne sound', translations: { es: 'Ruido estructural instalado' }, ...chips(S('EN 12354-5')) }, 476 + 'guides/mechanical-mobility', 477 + 'guides/junction-transmission', 478 + 'guides/transfer-stiffness', 479 + 'guides/vibration-sound-power', 480 + 'guides/structure-borne-power', 481 + 'guides/installed-structure-borne', 489 482 ], 490 483 }, 491 484 { ··· 493 486 translations: { es: 'Vibración en humanos' }, 494 487 items: [ 495 488 { slug: 'guides/sections/human-vibration', attrs: { 'data-group-link': true } }, 496 - { slug: 'guides/human-vibration', ...chips(S('ISO 8041'), S('ISO 2631'), S('ISO 5349')) }, 497 - { slug: 'guides/multiple-shock-vibration', label: 'Multiple-shock whole-body vibration', translations: { es: 'Vibración con choques múltiples' }, ...chips(S('ISO 2631-5')) }, 489 + 'guides/human-vibration', 490 + 'guides/multiple-shock-vibration', 498 491 ], 499 492 }, 500 493 ], ··· 509 502 translations: { es: 'Sonido en exteriores' }, 510 503 items: [ 511 504 { slug: 'guides/sections/outdoor-sound', attrs: { 'data-group-link': true } }, 512 - { slug: 'guides/outdoor-propagation', ...chips(S('ISO 9613'), T('Maekawa 1968')) }, 513 - { slug: 'guides/ground-barriers', ...chips(T('Kurze & Anderson'), T('Hadden & Pierce')) }, 514 - { slug: 'guides/atmospheric-refraction', ...chips(T('Salomons')) }, 515 - { slug: 'guides/impulse-prominence', label: 'Impulsive-sound prominence', translations: { es: 'Prominencia de sonidos impulsivos' }, ...chips(S('NT ACOU 112'), S('ISO 1996-1')) }, 505 + 'guides/outdoor-propagation', 506 + 'guides/ground-barriers', 507 + 'guides/atmospheric-refraction', 508 + 'guides/impulse-prominence', 516 509 ], 517 510 }, 518 511 { ··· 520 513 translations: { es: 'Aeronaves y energía eólica' }, 521 514 items: [ 522 515 { slug: 'guides/sections/aircraft-wind', attrs: { 'data-group-link': true } }, 523 - { slug: 'guides/aircraft-noise', ...chips(S('ICAO Annex 16'), S('IEC 61265'), S('SAE ARP 5534')) }, 524 - { slug: 'guides/rotorcraft-noise', ...chips(T('Olsen et al. 2024'), T('Chien & Soroka')) }, 525 - { slug: 'guides/wind-turbine-noise', ...chips(S('IEC 61400-11'), S('ISO 1996-2')) }, 516 + 'guides/aircraft-noise', 517 + 'guides/rotorcraft-noise', 518 + 'guides/wind-turbine-noise', 526 519 ], 527 520 }, 528 521 ], ··· 532 525 translations: { es: 'Acústica submarina' }, 533 526 items: [ 534 527 { slug: 'guides/sections/underwater', attrs: { 'data-group-link': true } }, 535 - { slug: 'guides/underwater-acoustics', ...chips(S('ISO 18405'), S('ISO 17208'), S('ISO 18406')) }, 536 - { slug: 'guides/underwater-propagation', ...chips(T('Francois & Garrison'), T('Wenz 1962'), T('Mackenzie 1981')) }, 528 + 'guides/underwater-acoustics', 529 + 'guides/underwater-propagation', 537 530 ], 538 531 }, 539 532 { ··· 541 534 translations: { es: 'Fuentes y dispositivos' }, 542 535 items: [ 543 536 { slug: 'guides/sections/sources-devices', attrs: { 'data-group-link': true } }, 544 - { slug: 'guides/intensity', ...chips(S('IEC 61043'), S('ISO 9614')) }, 545 - { slug: 'guides/sound-power', ...chips(S('ISO 3744'), S('ISO 3741'), S('ISO 9614'), S('ISO 4871')) }, 546 - { slug: 'guides/electroacoustics', ...chips(S('IEC 60268'), S('AES17')) }, 547 - { slug: 'guides/swept-sine-distortion', ...chips(T('Farina 2000'), T('Novak et al. 2015')) }, 548 - { slug: 'guides/noise-control', ...chips(T('Bies & Hansen'), T('Munjal')) }, 549 - { slug: 'guides/program-loudness', label: 'Programme loudness and true peak', translations: { es: 'Sonoridad de programa y pico verdadero' }, ...chips(S('ITU-R BS.1770'), S('EBU R 128')) }, 537 + 'guides/intensity', 538 + 'guides/sound-power', 539 + 'guides/electroacoustics', 540 + 'guides/swept-sine-distortion', 541 + 'guides/noise-control', 542 + 'guides/program-loudness', 550 543 ], 551 544 }, 552 545 { ··· 554 547 translations: { es: 'Simulación de ondas' }, 555 548 items: [ 556 549 { slug: 'guides/sections/simulation', attrs: { 'data-group-link': true } }, 557 - { slug: 'guides/fdtd-simulation', ...chips(T('Botteldooren 1995')) }, 550 + 'guides/fdtd-simulation', 558 551 ], 559 552 }, 560 553 {
ux-variants2/annotate-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/annotate-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/annotate-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-anchorjump-dark-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/chips-anchorjump-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-filled-many-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-filled-many-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-filled-many-light-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/chips-filled-single-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-header-many-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-header-many-dark-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/chips-header-many-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-header-overflow-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-header-single-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-none-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-pills-many-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-pills-many-dark-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/chips-pills-many-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-pills-overflow-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/chips-pills-single-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-sectiontable-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-sectiontable-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-sectiontable-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-sectiontable-light-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/clean-subtitle-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-subtitle-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-subtitle-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/clean-subtitle-light-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/focus-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/focus-dark-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/focus-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/focus-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/hover-card-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/hover-card-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/hover-card-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/hover-resting-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/hover-touchfallback-simulated-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/none-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/none-dark-mobile-en.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-anchorjump-dark-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-anchorjump-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-many-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-many-dark-desktop-es.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-many-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-none-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-overflow-light-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/pagechips-single-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/sidebar-final-dark-desktop-en.png

This is a binary file and will not be displayed.

ux-variants2/switcher-widget-dark-desktop-en.png

This is a binary file and will not be displayed.

+7 -59
site/src/components/Head.astro
··· 97 97 <meta name="twitter:title" content={title} /> 98 98 {description && <meta name="twitter:description" content={description} />} 99 99 100 - {/* TOC-info experiment (TOC-REDESIGN-NOTES.md): apply the persisted variant 101 - attributes (`data-page-chips`, `data-toc-style`, `data-api-style`) before 102 - first paint, then mount the floating variant switcher. Prototype-only; 103 - remove both scripts when a variant is chosen. */} 100 + {/* Docs UX experiment (TOC-REDESIGN-NOTES.md): apply the persisted variant 101 + attributes (`data-page-chips`, `data-api-style`) before first paint, then 102 + mount the floating switcher. Prototype-only; both scripts come out when a 103 + variant is chosen. */} 104 104 <script is:inline> 105 105 (() => { 106 106 const d = document.documentElement; 107 - let toc = 'focus'; 108 107 let api = 'split'; 109 108 let page = 'header'; 110 109 try { 111 - toc = localStorage.getItem('tocStyle') || toc; 112 110 api = localStorage.getItem('apiStyle') || api; 113 111 page = localStorage.getItem('pageChips') || page; 114 112 } catch {} 115 - d.dataset.tocStyle = toc; 116 113 d.dataset.apiStyle = api; 117 114 d.dataset.pageChips = page; 118 115 d.dataset.area = /\/reference\/api(\/|$)/.test(location.pathname) ? 'api' : 'guides'; ··· 121 118 <script is:inline> 122 119 document.addEventListener('DOMContentLoaded', () => { 123 120 const d = document.documentElement; 124 - const TOC = ['focus', 'annotate', 'hover', 'clean', 'none']; 121 + const PAGE = ['header', 'pills', 'filled', 'off']; 125 122 const API = ['split', 'collapsed', 'inline']; 126 - const PAGE = ['header', 'off']; 127 123 128 124 const radios = (name, values, current) => 129 125 values ··· 138 134 const widget = document.createElement('details'); 139 135 widget.className = 'toc-switcher'; 140 136 widget.innerHTML = 141 - '<summary title="TOC experiment switcher">UX</summary>' + 137 + '<summary title="Docs UX switcher">UX</summary>' + 142 138 '<div class="toc-switcher-panel">' + 143 139 `<fieldset><legend>Page chips</legend>${radios('pageChips', PAGE, d.dataset.pageChips)}</fieldset>` + 144 - `<fieldset><legend>Sidebar info</legend>${radios('tocStyle', TOC, d.dataset.tocStyle)}</fieldset>` + 145 140 `<fieldset><legend>API sidebar</legend>${radios('apiStyle', API, d.dataset.apiStyle)}</fieldset>` + 146 141 '</div>'; 147 142 document.body.appendChild(widget); ··· 154 149 localStorage.setItem(input.name, input.value); 155 150 } catch {} 156 151 applyApiFold(); 157 - syncSectionToc(); 158 152 }); 159 153 160 - // 'clean' variant: the section standards table is injected after the 161 - // markdown pipeline, so its heading cannot reach the server-rendered 162 - // "On this page" list. Mirror the entry client-side while the variant is 163 - // active (an existing item is cloned to inherit Starlight's scoped 164 - // styles). Prototype-only: the cloned entry is not scroll-spied. 165 - const sectionHeading = document.querySelector('.section-standards h2'); 166 - const syncSectionToc = () => { 167 - for (const node of document.querySelectorAll('.toc-standards-entry')) node.remove(); 168 - if (!sectionHeading || d.dataset.tocStyle !== 'clean') return; 169 - for (const list of document.querySelectorAll('starlight-toc nav ul, mobile-starlight-toc nav ul')) { 170 - const last = list.lastElementChild; 171 - if (!last) continue; 172 - const item = last.cloneNode(true); 173 - item.classList.add('toc-standards-entry'); 174 - const link = item.querySelector('a'); 175 - if (!link) continue; 176 - link.setAttribute('href', `#${sectionHeading.id}`); 177 - link.removeAttribute('aria-current'); 178 - const label = link.querySelector('span') || link; 179 - label.textContent = sectionHeading.textContent; 180 - list.append(item); 181 - } 182 - }; 183 - syncSectionToc(); 184 - 185 - // Collapsed API mode: initial fold state and caret wiring. 154 + // Collapsed API treatment: initial fold state and caret wiring. 186 155 const apiGroup = document.querySelector('#starlight__sidebar .api-group'); 187 156 const caret = apiGroup?.querySelector('.api-caret'); 188 157 const apiList = apiGroup?.querySelector('ul'); ··· 208 177 const folded = stored != null ? stored === 'true' : d.dataset.area !== 'api'; 209 178 setFolded(folded); 210 179 }; 211 - // Hover variant: Escape dismisses the floating card without moving the 212 - // keyboard focus (WCAG 2.2 1.4.13); any other key, or leaving the link, 213 - // brings it back. 214 - let dismissed = null; 215 - const restore = () => { 216 - if (!dismissed) return; 217 - delete dismissed.dataset.cardDismissed; 218 - dismissed = null; 219 - }; 220 - document.addEventListener('keydown', (event) => { 221 - const active = document.activeElement; 222 - const link = active?.closest?.('#starlight__sidebar a'); 223 - if (event.key === 'Escape' && link?.querySelector('.sidebar-chips')) { 224 - link.dataset.cardDismissed = ''; 225 - dismissed = link; 226 - return; 227 - } 228 - restore(); 229 - }); 230 - document.addEventListener('focusout', restore); 231 - 232 180 caret?.addEventListener('click', () => { 233 181 const folded = !apiGroup.classList.contains('folded'); 234 182 setFolded(folded);
+1 -2
site/src/components/MarkdownContent.astro
··· 7 7 */ 8 8 import Default from '@astrojs/starlight/components/MarkdownContent.astro'; 9 9 import References from './References.astro'; 10 - import SectionStandards from './SectionStandards.astro'; 11 10 --- 12 11 13 - <Default><slot /><SectionStandards /><References /></Default> 12 + <Default><slot /><References /></Default>
+5 -5
site/src/components/PageChips.astro
··· 1 1 --- 2 2 /** 3 - * Page header chips: one quiet horizontal run under the H1 stating which 4 - * standards govern the page and which named works the methods are attributed 5 - * to (TOC-info experiment, `data-page-chips='header'`; see 3 + * Page header chips: one run under the H1 stating which standards govern the 4 + * page and which named works its methods are attributed to (see 6 5 * TOC-REDESIGN-NOTES.md). 7 6 * 8 7 * Everything comes from the page's own `references` frontmatter through ··· 10 9 * References section at the bottom, and every chip links to its full entry 11 10 * there. Pages without references render nothing. 12 11 * 13 - * Always in the DOM, displayed only while the variant is active 14 - * (src/styles/toc-info.css), so switching costs no rebuild. 12 + * The markup is the same for every presentation; `data-page-chips` on <html> 13 + * picks between the quiet text run, the outlined pills, the filled pills and 14 + * nothing at all (src/styles/ux-variants.css), so switching costs no rebuild. 15 15 */ 16 16 import { pageChips } from '../lib/reference-chips'; 17 17
+5 -75
site/src/components/PageTitle.astro
··· 1 1 --- 2 2 /** 3 - * Default Starlight page title plus an optional standards/references 4 - * subtitle line (TOC-info variant "clean"; see TOC-REDESIGN-NOTES.md). 3 + * Default Starlight page title plus the page header chips run. 5 4 * 6 - * The line reuses the sidebar classification: the current page's sidebar 7 - * entry carries its governing standards / named references as 8 - * `attrs['data-chips']` JSON, so the subtitle needs no per-page frontmatter 9 - * and is identical in EN and ES (designations and author names are 10 - * language-neutral; only the visually-hidden accessibility prefix is 11 - * localized). It is always rendered and only displayed when 12 - * `data-toc-style='clean'` is active and the page chips run is off 13 - * (toc-info.css), since both sit under the H1 and say the same thing. 14 - * 15 - * PageChips.astro is the successor of this line: the same idea, but derived 16 - * from the page's own `references` frontmatter and linked to the bibliography. 5 + * The override exists only to give PageChips.astro a mount point directly 6 + * under the H1, inside the page header band and above the content divider. 7 + * Everything the run shows comes from the page's own `references` frontmatter; 8 + * see PageChips.astro and src/lib/reference-chips.ts. 17 9 */ 18 10 import Default from '@astrojs/starlight/components/PageTitle.astro'; 19 - import type { StarlightRouteData } from '@astrojs/starlight/route-data'; 20 11 import PageChips from './PageChips.astro'; 21 - 22 - type SidebarEntry = StarlightRouteData['sidebar'][number]; 23 - type SidebarLink = Extract<SidebarEntry, { type: 'link' }>; 24 - 25 - interface Chip { 26 - text: string; 27 - class: string; 28 - } 29 - 30 - function findCurrent(entries: SidebarEntry[]): SidebarLink | undefined { 31 - for (const entry of entries) { 32 - if (entry.type === 'link') { 33 - if (entry.isCurrent) return entry; 34 - } else { 35 - const found = findCurrent(entry.entries); 36 - if (found) return found; 37 - } 38 - } 39 - return undefined; 40 - } 41 - 42 - function parseChips(attrs: Record<string, unknown> | undefined): Chip[] { 43 - const raw = attrs?.['data-chips']; 44 - if (typeof raw !== 'string') return []; 45 - try { 46 - const list = JSON.parse(raw); 47 - return Array.isArray(list) ? (list as Chip[]) : []; 48 - } catch { 49 - return []; 50 - } 51 - } 52 - 53 - const current = findCurrent(Astro.locals.starlightRoute.sidebar); 54 - const chips = parseChips(current?.attrs); 55 - const isEs = Astro.currentLocale === 'es'; 56 12 --- 57 13 58 14 <Default><slot /></Default> 59 15 <PageChips /> 60 - { 61 - chips.length > 0 && ( 62 - <p class="page-standards"> 63 - <span class="sr-only"> 64 - {isEs ? 'Normas y referencias: ' : 'Standards and references: '} 65 - </span> 66 - {chips.map((chip) => ( 67 - <span class:list={['page-chip', chip.class]}>{chip.text}</span> 68 - ))} 69 - </p> 70 - ) 71 - } 72 - 73 - <style> 74 - .sr-only { 75 - position: absolute; 76 - width: 1px; 77 - height: 1px; 78 - padding: 0; 79 - margin: -1px; 80 - overflow: hidden; 81 - clip: rect(0, 0, 0, 0); 82 - white-space: nowrap; 83 - border: 0; 84 - } 85 - </style>
-142
site/src/components/SectionStandards.astro
··· 1 - --- 2 - /** 3 - * Auto-generated "what governs each page" table for section landing pages 4 - * (TOC-info variant "clean"; see TOC-REDESIGN-NOTES.md). 5 - * 6 - * When the current page is a sidebar group landing (the Overview-first 7 - * `data-group-link` convention), this renders a table of the group's pages 8 - * with their governing standards (teal) and named references (amber), all 9 - * sourced from the same `attrs['data-chips']` classification the sidebar 10 - * variants use. Nested subgroups become separator rows. Rendered on every 11 - * page (empty unless the page is a landing with annotated children) and 12 - * displayed only when `data-toc-style='clean'` is active (toc-info.css). 13 - */ 14 - import type { StarlightRouteData } from '@astrojs/starlight/route-data'; 15 - 16 - type SidebarEntry = StarlightRouteData['sidebar'][number]; 17 - type SidebarLink = Extract<SidebarEntry, { type: 'link' }>; 18 - type SidebarGroup = Extract<SidebarEntry, { type: 'group' }>; 19 - 20 - interface Chip { 21 - text: string; 22 - class: string; 23 - } 24 - 25 - function parseChips(attrs: Record<string, unknown> | undefined): Chip[] { 26 - const raw = attrs?.['data-chips']; 27 - if (typeof raw !== 'string') return []; 28 - try { 29 - const list = JSON.parse(raw); 30 - return Array.isArray(list) ? (list as Chip[]) : []; 31 - } catch { 32 - return []; 33 - } 34 - } 35 - 36 - function isLanding(entry: SidebarEntry): entry is SidebarLink { 37 - return entry.type === 'link' && entry.attrs != null && 'data-group-link' in entry.attrs; 38 - } 39 - 40 - /** Find the group whose landing page is the current page. */ 41 - function findCurrentGroup(entries: SidebarEntry[]): SidebarGroup | undefined { 42 - for (const entry of entries) { 43 - if (entry.type !== 'group') continue; 44 - const [first] = entry.entries; 45 - if (first && isLanding(first) && first.isCurrent) return entry; 46 - const nested = findCurrentGroup(entry.entries); 47 - if (nested) return nested; 48 - } 49 - return undefined; 50 - } 51 - 52 - interface Row { 53 - kind: 'page' | 'subgroup'; 54 - label: string; 55 - href?: string; 56 - standards: Chip[]; 57 - references: Chip[]; 58 - } 59 - 60 - function rows(group: SidebarGroup): Row[] { 61 - const out: Row[] = []; 62 - const [first, ...rest] = group.entries; 63 - const children = first && isLanding(first) ? rest : group.entries; 64 - for (const entry of children) { 65 - if (entry.type === 'link') { 66 - const chips = parseChips(entry.attrs); 67 - out.push({ 68 - kind: 'page', 69 - label: entry.label, 70 - href: entry.href, 71 - standards: chips.filter((c) => c.class === 'chip-standard'), 72 - references: chips.filter((c) => c.class === 'chip-theory'), 73 - }); 74 - } else { 75 - out.push({ kind: 'subgroup', label: entry.label, standards: [], references: [] }); 76 - for (const row of rows(entry)) if (row.kind === 'page') out.push(row); 77 - } 78 - } 79 - return out; 80 - } 81 - 82 - const group = findCurrentGroup(Astro.locals.starlightRoute.sidebar); 83 - const tableRows = group ? rows(group) : []; 84 - const hasChips = tableRows.some((r) => r.standards.length > 0 || r.references.length > 0); 85 - const isEs = Astro.currentLocale === 'es'; 86 - const heading = isEs ? 'Normas y referencias por página' : 'Standards and references by page'; 87 - const colPage = isEs ? 'Página' : 'Page'; 88 - const colStandards = isEs ? 'Normas' : 'Standards'; 89 - const colReferences = isEs ? 'Referencias clave' : 'Key references'; 90 - --- 91 - 92 - { 93 - group && hasChips && ( 94 - <section class="section-standards"> 95 - <h2 id="standards-by-page">{heading}</h2> 96 - {/* Starlight renders tables as scrollable blocks and the page names 97 - push this one past a phone viewport, so the scroll container needs 98 - an explicit tabindex for WCAG 2.1.1, exactly like the markdown 99 - table transform in astro.config.mjs. */} 100 - <table tabindex="0"> 101 - <thead> 102 - <tr> 103 - <th scope="col">{colPage}</th> 104 - <th scope="col">{colStandards}</th> 105 - <th scope="col">{colReferences}</th> 106 - </tr> 107 - </thead> 108 - <tbody> 109 - {tableRows.map((row) => 110 - row.kind === 'subgroup' ? ( 111 - <tr class="subgroup-row"> 112 - <td colspan="3">{row.label}</td> 113 - </tr> 114 - ) : ( 115 - <tr> 116 - <td> 117 - <a href={row.href}>{row.label}</a> 118 - </td> 119 - <td> 120 - {row.standards.map((chip, i) => ( 121 - <span class={chip.class}> 122 - {i > 0 && ', '} 123 - {chip.text} 124 - </span> 125 - ))} 126 - </td> 127 - <td> 128 - {row.references.map((chip, i) => ( 129 - <span class={chip.class}> 130 - {i > 0 && ', '} 131 - {chip.text} 132 - </span> 133 - ))} 134 - </td> 135 - </tr> 136 - ) 137 - )} 138 - </tbody> 139 - </table> 140 - </section> 141 - ) 142 - }
+5 -4
site/src/components/Sidebar.astro
··· 10 10 instead of upstream's `virtual:starlight/*` modules, so a future component 11 11 override of `MobileMenuFooter` would not be picked up here. 12 12 13 - TOC-info experiment (see TOC-REDESIGN-NOTES.md): a "Guides" back link is 14 - always rendered and only displayed in the split API mode on API pages 15 - (`data-api-style='split'` + `data-area='api'`, toc-info.css), where the 16 - guide groups are hidden from the tree. 13 + API sidebar experiment (see TOC-REDESIGN-NOTES.md): a "Guides" back link is 14 + always rendered and only displayed in the split API treatment on API pages 15 + (`data-api-style='split'` plus `data-area='api'`, ux-variants.css), where 16 + the guide groups are hidden from the tree. It comes out if the split is 17 + ever done with `starlight-sidebar-topics`, which brings its own switcher. 17 18 */ 18 19 import MobileMenuFooter from '@astrojs/starlight/components/MobileMenuFooter.astro'; 19 20 import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
+12 -62
site/src/components/SidebarSublist.astro
··· 12 12 Groups without a marked landing page render as a static heading. 13 13 - `aria-current="page"` moves to the label link when the landing page is 14 14 the current page, so highlighting keeps working. 15 - 16 - TOC-info experiment (see TOC-REDESIGN-NOTES.md): 17 - 18 - - Per-item standard/reference info travels through `attrs['data-chips']` 19 - (JSON), is rendered as a `.sidebar-chips` run inside each link, and is 20 - styled per-variant by `src/styles/toc-info.css` (annotation line, hover 21 - card, or hidden entirely). 22 - - The API reference group (landing `reference/api`) gets an `api-group` 23 - class plus a caret toggle button so the collapsed / split prototypes can 24 - fold it away without re-rendering. The caret is hidden unless the 25 - "collapsed" API mode is active (see toc-info.css and the switcher in 26 - Head.astro). 15 + - The API reference group (the one whose landing page is `reference/api`) 16 + is marked with an `api-group` class and gets a caret toggle button, so 17 + the API sidebar treatments can fold it away without re-rendering. The 18 + caret is hidden unless the "collapsed" treatment is active; see 19 + `src/styles/ux-variants.css` and the switcher in `Head.astro`. This is 20 + the only part of the file that is not upstream behaviour plus the 21 + overview-first convention, and it comes out if the API split is ever done 22 + with `starlight-sidebar-topics` instead. 27 23 */ 28 24 import type { StarlightRouteData } from '@astrojs/starlight/route-data'; 29 25 import { Badge } from '@astrojs/starlight/components'; ··· 56 52 : { group: entry, landing: undefined, children: entry.entries }; 57 53 } 58 54 59 - /* 60 - Multiple reference chips per item. Starlight's native `badge` slot is a 61 - single badge, so a list of chips is threaded through the sanctioned `attrs` 62 - passthrough as a JSON string under `data-chips` (built by the `chips()` 63 - helper in astro.config.mjs and by the API generator). Each chip is 64 - `{ text, class }` where the class is `chip-standard` (teal) or `chip-theory` 65 - (amber). We parse that here and render one Badge per chip, then drop the 66 - raw attribute so it is not echoed onto the <a> element. 67 - */ 68 - interface Chip { 69 - text: string; 70 - class: string; 71 - } 72 - function parseChips(attrs: Record<string, unknown> | undefined): Chip[] { 73 - const raw = attrs?.['data-chips']; 74 - if (typeof raw !== 'string') return []; 75 - try { 76 - const list = JSON.parse(raw); 77 - return Array.isArray(list) ? (list as Chip[]) : []; 78 - } catch { 79 - return []; 80 - } 81 - } 82 - function withoutChips(attrs: Record<string, unknown> | undefined): Record<string, unknown> { 83 - const { 'data-chips': _drop, ...rest } = attrs ?? {}; 84 - return rest; 85 - } 86 - 87 55 /** True for the API reference group (landing page `reference/api`). */ 88 56 function isApiGroup(landing: SidebarLink | undefined): boolean { 89 - if (!landing) return false; 90 - return /\/reference\/api\/?$/.test(landing.href); 57 + return landing ? /\/reference\/api\/?$/.test(landing.href) : false; 91 58 } 92 59 --- 93 60 ··· 95 62 { 96 63 sublist.map((entry) => { 97 64 if (entry.type === 'link') { 98 - const linkChips = parseChips(entry.attrs); 99 - const linkAttrs = withoutChips(entry.attrs); 100 65 return ( 101 66 <li> 102 67 <a 103 68 href={entry.href} 104 69 aria-current={entry.isCurrent ? 'page' : undefined} 105 70 class:list={[{ large: !nested }, entry.attrs.class]} 106 - {...linkAttrs} 71 + {...entry.attrs} 107 72 > 108 - <span class="sidebar-item-label">{entry.label}</span> 109 - {linkChips.length > 0 && ( 110 - <span class="sidebar-chips"> 111 - {linkChips.map((chip) => ( 112 - <Badge class={chip.class} text={chip.text} /> 113 - ))} 114 - </span> 115 - )} 73 + <span>{entry.label}</span> 116 74 {entry.badge && ( 117 75 <Badge 118 76 variant={entry.badge.variant} ··· 130 88 // except the internal `data-group-link` marker itself. 131 89 const { 132 90 'data-group-link': _marker, 133 - 'data-chips': _landingChipsRaw, 134 91 class: landingClass, 135 92 ...landingAttrs 136 93 } = landing?.attrs ?? {}; 137 - const groupChips = parseChips(landing?.attrs); 138 94 const labelLink = landing ? ( 139 95 <a 140 96 class:list={['group-label', landingClass]} ··· 143 99 {...landingAttrs} 144 100 > 145 101 <span class="large">{group.label}</span> 146 - {groupChips.length > 0 && ( 147 - <span class="sidebar-chips"> 148 - {groupChips.map((chip) => ( 149 - <Badge class={chip.class} text={chip.text} /> 150 - ))} 151 - </span> 152 - )} 153 102 {group.badge && ( 154 103 <Badge 155 104 variant={group.badge.variant} ··· 242 191 line-height: 1.4; 243 192 } 244 193 194 + /* API reference group only: label plus its fold toggle. */ 245 195 .group-label-row { 246 196 display: flex; 247 197 align-items: center;
+118 -118
site/src/generated/api-sidebar.mjs
··· 10 10 translations: { es: 'Filtros y frecuencias' }, 11 11 items: [ 12 12 'reference/api/filters/phonometry', 13 - { slug: 'reference/api/filters/core', attrs: { 'data-chips': '[{"text": "IEC 61260", "class": "chip-standard"}]' } }, 14 - { slug: 'reference/api/filters/parametric-filters', attrs: { 'data-chips': '[{"text": "IEC 61672", "class": "chip-standard"}]' } }, 15 - { slug: 'reference/api/filters/equalizer', attrs: { 'data-chips': '[{"text": "RBJ Cookbook", "class": "chip-theory"}]' } }, 16 - { slug: 'reference/api/filters/frequencies', attrs: { 'data-chips': '[{"text": "ISO 266", "class": "chip-standard"}]' } }, 17 - { slug: 'reference/api/filters/compliance', attrs: { 'data-chips': '[{"text": "IEC 61260", "class": "chip-standard"}, {"text": "IEC 61672", "class": "chip-standard"}]' } }, 13 + 'reference/api/filters/core', 14 + 'reference/api/filters/parametric-filters', 15 + 'reference/api/filters/equalizer', 16 + 'reference/api/filters/frequencies', 17 + 'reference/api/filters/compliance', 18 18 ], 19 19 }, 20 20 { 21 21 label: 'Levels and calibration', 22 22 translations: { es: 'Niveles y calibración' }, 23 23 items: [ 24 - { slug: 'reference/api/levels/levels', attrs: { 'data-chips': '[{"text": "IEC 61672", "class": "chip-standard"}]' } }, 25 - { slug: 'reference/api/levels/calibration', attrs: { 'data-chips': '[{"text": "IEC 60942", "class": "chip-standard"}]' } }, 24 + 'reference/api/levels/levels', 25 + 'reference/api/levels/calibration', 26 26 ], 27 27 }, 28 28 { 29 29 label: 'Psychoacoustics', 30 30 translations: { es: 'Psicoacústica' }, 31 31 items: [ 32 - { slug: 'reference/api/psychoacoustics/loudness-zwicker', attrs: { 'data-chips': '[{"text": "ISO 532-1", "class": "chip-standard"}, {"text": "Zwicker", "class": "chip-theory"}]' } }, 33 - { slug: 'reference/api/psychoacoustics/loudness-moore-glasberg', attrs: { 'data-chips': '[{"text": "ISO 532-2", "class": "chip-standard"}, {"text": "Moore & Glasberg", "class": "chip-theory"}]' } }, 34 - { slug: 'reference/api/psychoacoustics/loudness-moore-glasberg-time', attrs: { 'data-chips': '[{"text": "ISO 532-3", "class": "chip-standard"}, {"text": "Moore & Glasberg", "class": "chip-theory"}]' } }, 35 - { slug: 'reference/api/psychoacoustics/loudness-ecma', attrs: { 'data-chips': '[{"text": "ECMA-418-2", "class": "chip-standard"}]' } }, 36 - { slug: 'reference/api/psychoacoustics/loudness-contours', attrs: { 'data-chips': '[{"text": "ISO 226", "class": "chip-standard"}]' } }, 37 - { slug: 'reference/api/psychoacoustics/sharpness', attrs: { 'data-chips': '[{"text": "DIN 45692", "class": "chip-standard"}]' } }, 38 - { slug: 'reference/api/psychoacoustics/roughness-ecma', attrs: { 'data-chips': '[{"text": "ECMA-418-2", "class": "chip-standard"}]' } }, 39 - { slug: 'reference/api/psychoacoustics/tonality', attrs: { 'data-chips': '[{"text": "ECMA-418-1", "class": "chip-standard"}]' } }, 40 - { slug: 'reference/api/psychoacoustics/tonality-ecma', attrs: { 'data-chips': '[{"text": "ECMA-418-2", "class": "chip-standard"}]' } }, 41 - { slug: 'reference/api/psychoacoustics/tone-audibility', attrs: { 'data-chips': '[{"text": "ISO/PAS 20065", "class": "chip-standard"}]' } }, 42 - { slug: 'reference/api/psychoacoustics/fluctuation-strength', attrs: { 'data-chips': '[{"text": "Fastl & Zwicker", "class": "chip-theory"}]' } }, 43 - { slug: 'reference/api/psychoacoustics/fluctuation-strength-ecma', attrs: { 'data-chips': '[{"text": "ECMA-418-2", "class": "chip-standard"}]' } }, 44 - { slug: 'reference/api/psychoacoustics/psychoacoustic-annoyance', attrs: { 'data-chips': '[{"text": "Fastl & Zwicker", "class": "chip-theory"}]' } }, 32 + 'reference/api/psychoacoustics/loudness-zwicker', 33 + 'reference/api/psychoacoustics/loudness-moore-glasberg', 34 + 'reference/api/psychoacoustics/loudness-moore-glasberg-time', 35 + 'reference/api/psychoacoustics/loudness-ecma', 36 + 'reference/api/psychoacoustics/loudness-contours', 37 + 'reference/api/psychoacoustics/sharpness', 38 + 'reference/api/psychoacoustics/roughness-ecma', 39 + 'reference/api/psychoacoustics/tonality', 40 + 'reference/api/psychoacoustics/tonality-ecma', 41 + 'reference/api/psychoacoustics/tone-audibility', 42 + 'reference/api/psychoacoustics/fluctuation-strength', 43 + 'reference/api/psychoacoustics/fluctuation-strength-ecma', 44 + 'reference/api/psychoacoustics/psychoacoustic-annoyance', 45 45 ], 46 46 }, 47 47 { 48 48 label: 'Speech', 49 49 translations: { es: 'Habla' }, 50 50 items: [ 51 - { slug: 'reference/api/speech/sti', attrs: { 'data-chips': '[{"text": "IEC 60268-16", "class": "chip-standard"}, {"text": "Houtgast & Steeneken", "class": "chip-theory"}]' } }, 52 - { slug: 'reference/api/speech/sii', attrs: { 'data-chips': '[{"text": "ANSI S3.5", "class": "chip-standard"}, {"text": "French & Steinberg", "class": "chip-theory"}]' } }, 53 - { slug: 'reference/api/speech/objective-intelligibility', attrs: { 'data-chips': '[{"text": "Taal et al. 2011", "class": "chip-theory"}, {"text": "Jensen et al. 2016", "class": "chip-theory"}]' } }, 51 + 'reference/api/speech/sti', 52 + 'reference/api/speech/sii', 53 + 'reference/api/speech/objective-intelligibility', 54 54 ], 55 55 }, 56 56 { 57 57 label: 'Hearing and exposure', 58 58 translations: { es: 'Audición y exposición' }, 59 59 items: [ 60 - { slug: 'reference/api/hearing/threshold', attrs: { 'data-chips': '[{"text": "ISO 7029", "class": "chip-standard"}, {"text": "ISO 389-7", "class": "chip-standard"}]' } }, 61 - { slug: 'reference/api/hearing/noise-induced-hearing-loss', attrs: { 'data-chips': '[{"text": "ISO 1999", "class": "chip-standard"}]' } }, 62 - { slug: 'reference/api/hearing/occupational-exposure', attrs: { 'data-chips': '[{"text": "ISO 9612", "class": "chip-standard"}]' } }, 60 + 'reference/api/hearing/threshold', 61 + 'reference/api/hearing/noise-induced-hearing-loss', 62 + 'reference/api/hearing/occupational-exposure', 63 63 ], 64 64 }, 65 65 { 66 66 label: 'Room acoustics', 67 67 translations: { es: 'Acústica de salas' }, 68 68 items: [ 69 - { slug: 'reference/api/rooms/room-acoustics', attrs: { 'data-chips': '[{"text": "ISO 3382", "class": "chip-standard"}, {"text": "ISO 18233", "class": "chip-standard"}, {"text": "Schroeder 1965", "class": "chip-theory"}]' } }, 70 - { slug: 'reference/api/rooms/room-ir', attrs: { 'data-chips': '[{"text": "ISO 18233", "class": "chip-standard"}]' } }, 71 - { slug: 'reference/api/rooms/room-noise', attrs: { 'data-chips': '[{"text": "ANSI S12.2", "class": "chip-standard"}, {"text": "Beranek 1957", "class": "chip-theory"}, {"text": "Blazier 1997", "class": "chip-theory"}]' } }, 72 - { slug: 'reference/api/rooms/open-plan', attrs: { 'data-chips': '[{"text": "ISO 3382-3", "class": "chip-standard"}]' } }, 73 - { slug: 'reference/api/rooms/reverberation-prediction', attrs: { 'data-chips': '[{"text": "Sabine", "class": "chip-theory"}, {"text": "Eyring", "class": "chip-theory"}, {"text": "Arau", "class": "chip-theory"}]' } }, 74 - { slug: 'reference/api/rooms/enclosed-space-absorption', attrs: { 'data-chips': '[{"text": "EN 12354-6", "class": "chip-standard"}]' } }, 75 - { slug: 'reference/api/rooms/image-source', attrs: { 'data-chips': '[{"text": "Allen & Berkley", "class": "chip-theory"}]' } }, 76 - { slug: 'reference/api/rooms/steady-field', attrs: { 'data-chips': '[{"text": "Kuttruff", "class": "chip-theory"}]' } }, 69 + 'reference/api/rooms/room-acoustics', 70 + 'reference/api/rooms/room-ir', 71 + 'reference/api/rooms/room-noise', 72 + 'reference/api/rooms/open-plan', 73 + 'reference/api/rooms/reverberation-prediction', 74 + 'reference/api/rooms/enclosed-space-absorption', 75 + 'reference/api/rooms/image-source', 76 + 'reference/api/rooms/steady-field', 77 77 ], 78 78 }, 79 79 { 80 80 label: 'Building acoustics', 81 81 translations: { es: 'Acústica de la edificación' }, 82 82 items: [ 83 - { slug: 'reference/api/building/insulation', attrs: { 'data-chips': '[{"text": "ISO 16283", "class": "chip-standard"}, {"text": "ISO 717", "class": "chip-standard"}]' } }, 84 - { slug: 'reference/api/building/panel-transmission', attrs: { 'data-chips': '[{"text": "EN 12354-1", "class": "chip-standard"}]' } }, 85 - { slug: 'reference/api/building/aperture-transmission', attrs: { 'data-chips': '[{"text": "Hopkins 2007", "class": "chip-theory"}]' } }, 86 - { slug: 'reference/api/building/lab-insulation', attrs: { 'data-chips': '[{"text": "ISO 10140", "class": "chip-standard"}]' } }, 87 - { slug: 'reference/api/building/survey-insulation', attrs: { 'data-chips': '[{"text": "ISO 10052", "class": "chip-standard"}]' } }, 88 - { slug: 'reference/api/building/intensity-insulation', attrs: { 'data-chips': '[{"text": "ISO 15186", "class": "chip-standard"}]' } }, 89 - { slug: 'reference/api/building/flanking-transmission', attrs: { 'data-chips': '[{"text": "ISO 10848", "class": "chip-standard"}]' } }, 90 - { slug: 'reference/api/building/facade-prediction', attrs: { 'data-chips': '[{"text": "EN 12354-3", "class": "chip-standard"}]' } }, 91 - { slug: 'reference/api/building/building-prediction', attrs: { 'data-chips': '[{"text": "EN 12354", "class": "chip-standard"}]' } }, 92 - { slug: 'reference/api/building/building-uncertainty', attrs: { 'data-chips': '[{"text": "ISO 12999-1", "class": "chip-standard"}]' } }, 93 - { slug: 'reference/api/building/floor-covering-improvement', attrs: { 'data-chips': '[{"text": "ISO 16251-1", "class": "chip-standard"}]' } }, 94 - { slug: 'reference/api/building/structure-borne-power', attrs: { 'data-chips': '[{"text": "EN 15657", "class": "chip-standard"}]' } }, 95 - { slug: 'reference/api/building/installed-structure-borne', attrs: { 'data-chips': '[{"text": "EN 12354-5", "class": "chip-standard"}]' } }, 83 + 'reference/api/building/insulation', 84 + 'reference/api/building/panel-transmission', 85 + 'reference/api/building/aperture-transmission', 86 + 'reference/api/building/lab-insulation', 87 + 'reference/api/building/survey-insulation', 88 + 'reference/api/building/intensity-insulation', 89 + 'reference/api/building/flanking-transmission', 90 + 'reference/api/building/facade-prediction', 91 + 'reference/api/building/building-prediction', 92 + 'reference/api/building/building-uncertainty', 93 + 'reference/api/building/floor-covering-improvement', 94 + 'reference/api/building/structure-borne-power', 95 + 'reference/api/building/installed-structure-borne', 96 96 ], 97 97 }, 98 98 { 99 99 label: 'Materials and surfaces', 100 100 translations: { es: 'Materiales y superficies' }, 101 101 items: [ 102 - { slug: 'reference/api/materials/sound-absorption', attrs: { 'data-chips': '[{"text": "ISO 354", "class": "chip-standard"}]' } }, 103 - { slug: 'reference/api/materials/absorption-rating', attrs: { 'data-chips': '[{"text": "ISO 11654", "class": "chip-standard"}]' } }, 104 - { slug: 'reference/api/materials/absorption-uncertainty', attrs: { 'data-chips': '[{"text": "ISO 12999-2", "class": "chip-standard"}]' } }, 105 - { slug: 'reference/api/materials/airflow-resistance', attrs: { 'data-chips': '[{"text": "ISO 9053", "class": "chip-standard"}]' } }, 106 - { slug: 'reference/api/materials/dynamic-stiffness', attrs: { 'data-chips': '[{"text": "EN 29052-1", "class": "chip-standard"}]' } }, 107 - { slug: 'reference/api/materials/impedance-tube', attrs: { 'data-chips': '[{"text": "ISO 10534", "class": "chip-standard"}, {"text": "ASTM E2611", "class": "chip-standard"}]' } }, 108 - { slug: 'reference/api/materials/porous-absorber', attrs: { 'data-chips': '[{"text": "Delany & Bazley", "class": "chip-theory"}, {"text": "Miki", "class": "chip-theory"}, {"text": "Johnson et al.", "class": "chip-theory"}]' } }, 109 - { slug: 'reference/api/materials/slow-sound-absorber', attrs: { 'data-chips': '[{"text": "Jiménez et al.", "class": "chip-theory"}]' } }, 110 - { slug: 'reference/api/materials/scattering-diffusion', attrs: { 'data-chips': '[{"text": "ISO 17497", "class": "chip-standard"}, {"text": "Cox & D\'Antonio", "class": "chip-theory"}]' } }, 111 - { slug: 'reference/api/materials/diffuser-design', attrs: { 'data-chips': '[{"text": "Cox & D\'Antonio", "class": "chip-theory"}]' } }, 112 - { slug: 'reference/api/materials/road-absorption', attrs: { 'data-chips': '[{"text": "ISO 13472", "class": "chip-standard"}]' } }, 102 + 'reference/api/materials/sound-absorption', 103 + 'reference/api/materials/absorption-rating', 104 + 'reference/api/materials/absorption-uncertainty', 105 + 'reference/api/materials/airflow-resistance', 106 + 'reference/api/materials/dynamic-stiffness', 107 + 'reference/api/materials/impedance-tube', 108 + 'reference/api/materials/porous-absorber', 109 + 'reference/api/materials/slow-sound-absorber', 110 + 'reference/api/materials/scattering-diffusion', 111 + 'reference/api/materials/diffuser-design', 112 + 'reference/api/materials/road-absorption', 113 113 ], 114 114 }, 115 115 { 116 116 label: 'Vibration and structure-borne', 117 117 translations: { es: 'Vibración y ruido estructural' }, 118 118 items: [ 119 - { slug: 'reference/api/vibration/mechanical-mobility', attrs: { 'data-chips': '[{"text": "ISO 7626", "class": "chip-standard"}]' } }, 120 - { slug: 'reference/api/vibration/point-mobility', attrs: { 'data-chips': '[{"text": "ISO 7626", "class": "chip-standard"}]' } }, 121 - { slug: 'reference/api/vibration/radiation-efficiency', attrs: { 'data-chips': '[{"text": "ISO/TS 7849", "class": "chip-standard"}, {"text": "Cremer & Heckl", "class": "chip-theory"}]' } }, 122 - { slug: 'reference/api/vibration/junction-transmission', attrs: { 'data-chips': '[{"text": "Cremer & Heckl", "class": "chip-theory"}]' } }, 123 - { slug: 'reference/api/vibration/transfer-stiffness', attrs: { 'data-chips': '[{"text": "ISO 10846", "class": "chip-standard"}]' } }, 124 - { slug: 'reference/api/vibration/human-vibration', attrs: { 'data-chips': '[{"text": "ISO 2631", "class": "chip-standard"}, {"text": "ISO 5349", "class": "chip-standard"}, {"text": "ISO 8041", "class": "chip-standard"}]' } }, 125 - { slug: 'reference/api/vibration/multiple-shock-vibration', attrs: { 'data-chips': '[{"text": "ISO 2631-5", "class": "chip-standard"}]' } }, 119 + 'reference/api/vibration/mechanical-mobility', 120 + 'reference/api/vibration/point-mobility', 121 + 'reference/api/vibration/radiation-efficiency', 122 + 'reference/api/vibration/junction-transmission', 123 + 'reference/api/vibration/transfer-stiffness', 124 + 'reference/api/vibration/human-vibration', 125 + 'reference/api/vibration/multiple-shock-vibration', 126 126 ], 127 127 }, 128 128 { 129 129 label: 'Environmental acoustics', 130 130 translations: { es: 'Acústica ambiental' }, 131 131 items: [ 132 - { slug: 'reference/api/environment/outdoor-propagation', attrs: { 'data-chips': '[{"text": "ISO 9613", "class": "chip-standard"}, {"text": "Maekawa 1968", "class": "chip-theory"}]' } }, 133 - { slug: 'reference/api/environment/ground-barriers', attrs: { 'data-chips': '[{"text": "ISO 9613-2", "class": "chip-standard"}, {"text": "Kurze & Anderson", "class": "chip-theory"}]' } }, 134 - { slug: 'reference/api/environment/atmospheric-refraction', attrs: { 'data-chips': '[{"text": "Salomons", "class": "chip-theory"}]' } }, 135 - { slug: 'reference/api/environment/air-absorption', attrs: { 'data-chips': '[{"text": "ISO 9613-1", "class": "chip-standard"}]' } }, 136 - { slug: 'reference/api/environment/impulse-prominence', attrs: { 'data-chips': '[{"text": "NT ACOU 112", "class": "chip-standard"}]' } }, 137 - { slug: 'reference/api/environment/impulsive-sound', attrs: { 'data-chips': '[{"text": "ISO/PAS 1996-3", "class": "chip-standard"}]' } }, 138 - { slug: 'reference/api/environment/rating', attrs: { 'data-chips': '[{"text": "ISO 1996-1", "class": "chip-standard"}]' } }, 139 - { slug: 'reference/api/environment/measurement', attrs: { 'data-chips': '[{"text": "ISO 1996-2", "class": "chip-standard"}]' } }, 132 + 'reference/api/environment/outdoor-propagation', 133 + 'reference/api/environment/ground-barriers', 134 + 'reference/api/environment/atmospheric-refraction', 135 + 'reference/api/environment/air-absorption', 136 + 'reference/api/environment/impulse-prominence', 137 + 'reference/api/environment/impulsive-sound', 138 + 'reference/api/environment/rating', 139 + 'reference/api/environment/measurement', 140 140 ], 141 141 }, 142 142 { 143 143 label: 'Aircraft and wind energy', 144 144 translations: { es: 'Aeronaves y energía eólica' }, 145 145 items: [ 146 - { slug: 'reference/api/aeroacoustics/aircraft-noise', attrs: { 'data-chips': '[{"text": "ICAO Annex 16", "class": "chip-standard"}, {"text": "IEC 61265", "class": "chip-standard"}]' } }, 147 - { slug: 'reference/api/aeroacoustics/atmospheric-absorption', attrs: { 'data-chips': '[{"text": "SAE ARP 5534", "class": "chip-standard"}]' } }, 148 - { slug: 'reference/api/aeroacoustics/airport-noise', attrs: { 'data-chips': '[{"text": "ECAC Doc 29", "class": "chip-standard"}]' } }, 149 - { slug: 'reference/api/aeroacoustics/anp-fleet', attrs: { 'data-chips': '[{"text": "ECAC Doc 29", "class": "chip-standard"}]' } }, 150 - { slug: 'reference/api/aeroacoustics/rotorcraft-noise', attrs: { 'data-chips': '[{"text": "Olsen et al. 2024", "class": "chip-theory"}]' } }, 151 - { slug: 'reference/api/aeroacoustics/wind-turbine-noise', attrs: { 'data-chips': '[{"text": "IEC 61400-11", "class": "chip-standard"}, {"text": "ISO 1996-2", "class": "chip-standard"}]' } }, 146 + 'reference/api/aeroacoustics/aircraft-noise', 147 + 'reference/api/aeroacoustics/atmospheric-absorption', 148 + 'reference/api/aeroacoustics/airport-noise', 149 + 'reference/api/aeroacoustics/anp-fleet', 150 + 'reference/api/aeroacoustics/rotorcraft-noise', 151 + 'reference/api/aeroacoustics/wind-turbine-noise', 152 152 ], 153 153 }, 154 154 { 155 155 label: 'Underwater acoustics', 156 156 translations: { es: 'Acústica submarina' }, 157 157 items: [ 158 - { slug: 'reference/api/underwater/acoustics', attrs: { 'data-chips': '[{"text": "ISO 18405", "class": "chip-standard"}]' } }, 159 - { slug: 'reference/api/underwater/propagation', attrs: { 'data-chips': '[{"text": "Francois & Garrison", "class": "chip-theory"}]' } }, 160 - { slug: 'reference/api/underwater/sound-speed', attrs: { 'data-chips': '[{"text": "Mackenzie 1981", "class": "chip-theory"}]' } }, 161 - { slug: 'reference/api/underwater/sonar-equation', attrs: { 'data-chips': '[{"text": "Urick", "class": "chip-theory"}]' } }, 162 - { slug: 'reference/api/underwater/ocean-ambient-noise', attrs: { 'data-chips': '[{"text": "Wenz 1962", "class": "chip-theory"}]' } }, 163 - { slug: 'reference/api/underwater/seabed-reflection', attrs: { 'data-chips': '[{"text": "Jensen et al.", "class": "chip-theory"}]' } }, 164 - { slug: 'reference/api/underwater/ship-radiated-noise', attrs: { 'data-chips': '[{"text": "ISO 17208", "class": "chip-standard"}]' } }, 165 - { slug: 'reference/api/underwater/ship-traffic-noise', attrs: { 'data-chips': '[{"text": "JOMOPANS-ECHO", "class": "chip-theory"}]' } }, 166 - { slug: 'reference/api/underwater/pile-driving-noise', attrs: { 'data-chips': '[{"text": "ISO 18406", "class": "chip-standard"}]' } }, 167 - { slug: 'reference/api/underwater/numerical-propagation', attrs: { 'data-chips': '[{"text": "Jensen et al.", "class": "chip-theory"}]' } }, 158 + 'reference/api/underwater/acoustics', 159 + 'reference/api/underwater/propagation', 160 + 'reference/api/underwater/sound-speed', 161 + 'reference/api/underwater/sonar-equation', 162 + 'reference/api/underwater/ocean-ambient-noise', 163 + 'reference/api/underwater/seabed-reflection', 164 + 'reference/api/underwater/ship-radiated-noise', 165 + 'reference/api/underwater/ship-traffic-noise', 166 + 'reference/api/underwater/pile-driving-noise', 167 + 'reference/api/underwater/numerical-propagation', 168 168 ], 169 169 }, 170 170 { 171 171 label: 'Sound power and intensity', 172 172 translations: { es: 'Potencia acústica e intensidad' }, 173 173 items: [ 174 - { slug: 'reference/api/power/sound-power', attrs: { 'data-chips': '[{"text": "ISO 3744", "class": "chip-standard"}, {"text": "ISO 3741", "class": "chip-standard"}]' } }, 175 - { slug: 'reference/api/power/sound-power-intensity', attrs: { 'data-chips': '[{"text": "ISO 9614", "class": "chip-standard"}]' } }, 176 - { slug: 'reference/api/power/sound-power-reverberation', attrs: { 'data-chips': '[{"text": "ISO 3741", "class": "chip-standard"}]' } }, 177 - { slug: 'reference/api/power/intensity', attrs: { 'data-chips': '[{"text": "IEC 61043", "class": "chip-standard"}, {"text": "ISO 9614", "class": "chip-standard"}]' } }, 178 - { slug: 'reference/api/power/vibration-sound-power', attrs: { 'data-chips': '[{"text": "ISO/TS 7849", "class": "chip-standard"}]' } }, 179 - { slug: 'reference/api/power/declaration', attrs: { 'data-chips': '[{"text": "ISO 4871", "class": "chip-standard"}]' } }, 174 + 'reference/api/power/sound-power', 175 + 'reference/api/power/sound-power-intensity', 176 + 'reference/api/power/sound-power-reverberation', 177 + 'reference/api/power/intensity', 178 + 'reference/api/power/vibration-sound-power', 179 + 'reference/api/power/declaration', 180 180 ], 181 181 }, 182 182 { 183 183 label: 'Electroacoustics', 184 184 translations: { es: 'Electroacústica' }, 185 185 items: [ 186 - { slug: 'reference/api/electroacoustics/distortion', attrs: { 'data-chips': '[{"text": "IEC 60268-3", "class": "chip-standard"}, {"text": "AES17", "class": "chip-standard"}]' } }, 187 - { slug: 'reference/api/electroacoustics/frequency-response', attrs: { 'data-chips': '[{"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 188 - { slug: 'reference/api/electroacoustics/swept-sine', attrs: { 'data-chips': '[{"text": "Farina 2000", "class": "chip-theory"}, {"text": "Novak et al. 2015", "class": "chip-theory"}]' } }, 189 - { slug: 'reference/api/electroacoustics/piston', attrs: { 'data-chips': '[{"text": "Beranek & Mellow", "class": "chip-theory"}]' } }, 190 - { slug: 'reference/api/electroacoustics/loudspeaker', attrs: { 'data-chips': '[{"text": "IEC 60268-5", "class": "chip-standard"}]' } }, 191 - { slug: 'reference/api/electroacoustics/microphone', attrs: { 'data-chips': '[{"text": "IEC 60268-4", "class": "chip-standard"}]' } }, 186 + 'reference/api/electroacoustics/distortion', 187 + 'reference/api/electroacoustics/frequency-response', 188 + 'reference/api/electroacoustics/swept-sine', 189 + 'reference/api/electroacoustics/piston', 190 + 'reference/api/electroacoustics/loudspeaker', 191 + 'reference/api/electroacoustics/microphone', 192 192 ], 193 193 }, 194 194 { 195 195 label: 'Industrial noise control', 196 196 translations: { es: 'Control de ruido industrial' }, 197 197 items: [ 198 - { slug: 'reference/api/noise_control/silencers', attrs: { 'data-chips': '[{"text": "Munjal", "class": "chip-theory"}, {"text": "Bies & Hansen", "class": "chip-theory"}]' } }, 199 - { slug: 'reference/api/noise_control/hvac', attrs: { 'data-chips': '[{"text": "Bies & Hansen", "class": "chip-theory"}]' } }, 200 - { slug: 'reference/api/noise_control/enclosures', attrs: { 'data-chips': '[{"text": "Bies & Hansen", "class": "chip-theory"}]' } }, 198 + 'reference/api/noise_control/silencers', 199 + 'reference/api/noise_control/hvac', 200 + 'reference/api/noise_control/enclosures', 201 201 ], 202 202 }, 203 203 { 204 204 label: 'Program loudness', 205 205 translations: { es: 'Sonoridad de programa' }, 206 206 items: [ 207 - { slug: 'reference/api/broadcast/program-loudness', attrs: { 'data-chips': '[{"text": "ITU-R BS.1770", "class": "chip-standard"}, {"text": "EBU R 128", "class": "chip-standard"}]' } }, 207 + 'reference/api/broadcast/program-loudness', 208 208 ], 209 209 }, 210 210 { 211 211 label: 'Uncertainty and data quality', 212 212 translations: { es: 'Incertidumbre y calidad de datos' }, 213 213 items: [ 214 - { slug: 'reference/api/metrology/uncertainty', attrs: { 'data-chips': '[{"text": "JCGM 100", "class": "chip-standard"}]' } }, 215 - { slug: 'reference/api/metrology/random-data', attrs: { 'data-chips': '[{"text": "Rice 1945", "class": "chip-theory"}, {"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 214 + 'reference/api/metrology/uncertainty', 215 + 'reference/api/metrology/random-data', 216 216 ], 217 217 }, 218 218 { 219 219 label: 'Spectral analysis', 220 220 translations: { es: 'Análisis espectral' }, 221 221 items: [ 222 - { slug: 'reference/api/spectra/spectra', attrs: { 'data-chips': '[{"text": "Welch 1967", "class": "chip-theory"}, {"text": "Thomson 1982", "class": "chip-theory"}]' } }, 223 - { slug: 'reference/api/spectra/miso', attrs: { 'data-chips': '[{"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 224 - { slug: 'reference/api/spectra/time-frequency', attrs: { 'data-chips': '[{"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 225 - { slug: 'reference/api/spectra/signals', attrs: { 'data-chips': '[{"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 226 - { slug: 'reference/api/spectra/phase', attrs: { 'data-chips': '[{"text": "Farina 2000", "class": "chip-theory"}]' } }, 227 - { slug: 'reference/api/spectra/cepstrum', attrs: { 'data-chips': '[{"text": "Havelock et al.", "class": "chip-theory"}, {"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 228 - { slug: 'reference/api/spectra/synchronous-average', attrs: { 'data-chips': '[{"text": "McFadden 1987", "class": "chip-theory"}]' } }, 229 - { slug: 'reference/api/spectra/inversion', attrs: { 'data-chips': '[{"text": "Kirkeby & Nelson", "class": "chip-theory"}]' } }, 222 + 'reference/api/spectra/spectra', 223 + 'reference/api/spectra/miso', 224 + 'reference/api/spectra/time-frequency', 225 + 'reference/api/spectra/signals', 226 + 'reference/api/spectra/phase', 227 + 'reference/api/spectra/cepstrum', 228 + 'reference/api/spectra/synchronous-average', 229 + 'reference/api/spectra/inversion', 230 230 ], 231 231 }, 232 232 { 233 233 label: 'Wave simulation', 234 234 translations: { es: 'Simulación de ondas' }, 235 235 items: [ 236 - { slug: 'reference/api/simulation/fdtd', attrs: { 'data-chips': '[{"text": "Botteldooren 1995", "class": "chip-theory"}]' } }, 236 + 'reference/api/simulation/fdtd', 237 237 ], 238 238 }, 239 239 { 240 240 label: 'Correlation & envelope', 241 241 translations: { es: 'Correlación y envolvente' }, 242 242 items: [ 243 - { slug: 'reference/api/correlation/correlation', attrs: { 'data-chips': '[{"text": "Knapp & Carter", "class": "chip-theory"}, {"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 244 - { slug: 'reference/api/correlation/envelope', attrs: { 'data-chips': '[{"text": "Bendat & Piersol", "class": "chip-theory"}]' } }, 243 + 'reference/api/correlation/correlation', 244 + 'reference/api/correlation/envelope', 245 245 ], 246 246 }, 247 247 ],
-665
site/src/styles/toc-info.css
··· 1 - /* TOC standard/reference info: switchable presentation variants. 2 - 3 - Every sidebar item can carry the standard(s) it implements (teal category) 4 - and/or the notable reference(s) the method is attributed to (amber 5 - category). The data travels as `attrs['data-chips']` JSON (see 6 - astro.config.mjs and scripts/generate_api_docs.py) and is rendered by 7 - SidebarSublist.astro as a `.sidebar-chips` run inside each link. THIS file 8 - decides what that run looks like, or whether it shows at all. 9 - 10 - The active variant is a `data-toc-style` attribute on <html>, set before 11 - first paint by the switcher script in Head.astro (persisted in 12 - localStorage). Variants: 13 - 14 - data-toc-style='focus' (recommended default) the muted annotation 15 - line shows ONLY for the items of the section 16 - the reader is currently in; the rest of the 17 - tree stays perfectly clean. 18 - data-toc-style='annotate' the same annotation line, always visible on 19 - every item (whole-tree comparison baseline). 20 - data-toc-style='hover' no annotation lines; items with info carry a 21 - subtle dotted underline and the info appears 22 - in a small floating card on hover / keyboard 23 - focus. 24 - data-toc-style='clean' nothing in the sidebar at all; the info lives 25 - in the page subtitle under the H1 and in the 26 - section landing tables (see PageTitle.astro 27 - and SectionStandards.astro). 28 - data-toc-style='none' nothing anywhere (the pre-experiment look). 29 - 30 - The API sidebar treatment is independent, under `data-api-style`: 31 - 32 - data-api-style='inline' the API reference group renders fully 33 - expanded in place (status quo). 34 - data-api-style='collapsed' the API group gets a caret and folds; it 35 - starts folded on guide pages and unfolded on 36 - API pages. 37 - data-api-style='split' topic-style split: on guide pages the API 38 - group collapses to its single label link; on 39 - API pages only the Reference group is shown 40 - plus a "Guides" back link. 41 - 42 - `data-area` ('guides' | 'api') is stamped on <html> from the URL by the 43 - same early script. All selectors are unlayered so they win over 44 - Starlight's layered styles without specificity games. Both themes are 45 - covered (dark values on :root, light overrides on [data-theme='light']). */ 46 - 47 - :root { 48 - /* Category colours, dark theme. `*-accent` is the small leading dot, 49 - `*-ink` the tinted text used in the hover card / page subtitle. */ 50 - --chip-standard-accent: #6fdcc8; 51 - --chip-standard-ink: #7ee8d5; 52 - --chip-theory-accent: #e6b84e; 53 - --chip-theory-ink: #f4c04e; 54 - /* Neutral ink for the annotation line. Starlight's `--sl-color-gray-2` is 55 - the sidebar LINK colour, so reusing it gave the metadata exactly the 56 - tonal weight of the navigation labels. This is one step quieter in both 57 - themes and still clears WCAG AA for small text (5.3:1 dark, 5.6:1 58 - light). */ 59 - --chip-ink-muted: hsl(224, 8%, 62%); 60 - /* Dotted marker of the 'hover' variant. Starlight's hairline value is far 61 - too dark to be seen on the dark sidebar, so each theme gets a value at a 62 - comparable distance from its own background. */ 63 - --chip-marker: hsl(224, 7%, 38%); 64 - } 65 - 66 - :root[data-theme='light'] { 67 - --chip-standard-accent: #128273; 68 - --chip-standard-ink: #0c5c52; 69 - --chip-theory-accent: #a8760a; 70 - --chip-theory-ink: #855107; 71 - --chip-ink-muted: hsl(224, 7%, 42%); 72 - --chip-marker: hsl(224, 6%, 74%); 73 - } 74 - 75 - /* --------------------------------------------------------------------------- 76 - BASE: hidden unless a variant opts in; quiet sans metadata when shown. 77 - --------------------------------------------------------------------------- */ 78 - 79 - .sidebar-chips { 80 - display: none; 81 - } 82 - 83 - .sidebar-chips .sl-badge { 84 - /* Strip Starlight's badge fill / border / padding / mono font down to 85 - plain muted sans text. Absolute font size so every chip is identical 86 - regardless of the item's own size. */ 87 - display: inline; 88 - padding: 0; 89 - border: 0; 90 - background: transparent; 91 - font-family: inherit; 92 - color: var(--chip-ink-muted); 93 - font-size: 0.6875rem; 94 - font-weight: 500; 95 - letter-spacing: 0.01em; 96 - line-height: 1.3; 97 - white-space: nowrap; 98 - } 99 - 100 - /* --------------------------------------------------------------------------- 101 - ANNOTATION LINE (shared by 'annotate' and 'focus'). 102 - 103 - One quiet line below the label: chips in the site sans at ~11px, gray-2, 104 - separated by whitespace; ONE small colour dot leads each category run 105 - (teal for the standards run, amber for the references run), so a line has 106 - at most two marks, and EN/ES need no extra text. 107 - --------------------------------------------------------------------------- */ 108 - 109 - :root[data-toc-style='annotate'] .sidebar-chips, 110 - :root[data-toc-style='focus'] .sidebar-chips { 111 - flex-wrap: wrap; 112 - align-items: baseline; 113 - gap: 0.1rem 0.55rem; 114 - margin-block-start: 0.15rem; 115 - margin-inline-start: 0.9rem; 116 - line-height: 1.3; 117 - max-width: 100%; 118 - /* display stays `none`; the visibility rules below flip it to flex. */ 119 - } 120 - 121 - /* 'annotate': every item shows its line. */ 122 - :root[data-toc-style='annotate'] .sidebar-chips { 123 - display: flex; 124 - } 125 - 126 - /* 'focus': only the current section's items show their line, i.e. the 127 - siblings of the current page in its immediate list... */ 128 - :root[data-toc-style='focus'] 129 - #starlight__sidebar 130 - ul:has(> li > a[aria-current='page']) 131 - > li 132 - > a 133 - > .sidebar-chips { 134 - display: flex; 135 - } 136 - 137 - /* ...and, when the current page is a section landing, the direct children 138 - of that section (both the plain group markup and the API label row). */ 139 - :root[data-toc-style='focus'] 140 - #starlight__sidebar 141 - li:has(> a.group-label[aria-current='page']) 142 - > ul 143 - > li 144 - > a 145 - > .sidebar-chips, 146 - :root[data-toc-style='focus'] 147 - #starlight__sidebar 148 - li:has(> .group-label-row > a.group-label[aria-current='page']) 149 - > ul 150 - > li 151 - > a 152 - > .sidebar-chips { 153 - display: flex; 154 - } 155 - 156 - /* Leading colour dot at the start of each category run (a run starts at the 157 - first chip or wherever the category changes; standards precede references 158 - in the data, but both boundary directions are handled). */ 159 - :root[data-toc-style='annotate'] .sidebar-chips .chip-standard:first-child::before, 160 - :root[data-toc-style='annotate'] .sidebar-chips .chip-theory + .chip-standard::before, 161 - :root[data-toc-style='annotate'] .sidebar-chips .chip-theory:first-child::before, 162 - :root[data-toc-style='annotate'] .sidebar-chips .chip-standard + .chip-theory::before, 163 - :root[data-toc-style='focus'] .sidebar-chips .chip-standard:first-child::before, 164 - :root[data-toc-style='focus'] .sidebar-chips .chip-theory + .chip-standard::before, 165 - :root[data-toc-style='focus'] .sidebar-chips .chip-theory:first-child::before, 166 - :root[data-toc-style='focus'] .sidebar-chips .chip-standard + .chip-theory::before { 167 - content: ''; 168 - display: inline-block; 169 - vertical-align: 0.08em; 170 - inline-size: 0.3rem; 171 - block-size: 0.3rem; 172 - margin-inline-end: 0.3rem; 173 - border-radius: 50%; 174 - background: var(--run-dot); 175 - } 176 - 177 - :root[data-toc-style='annotate'] .sidebar-chips .chip-standard, 178 - :root[data-toc-style='focus'] .sidebar-chips .chip-standard { 179 - --run-dot: var(--chip-standard-accent); 180 - } 181 - :root[data-toc-style='annotate'] .sidebar-chips .chip-theory, 182 - :root[data-toc-style='focus'] .sidebar-chips .chip-theory { 183 - --run-dot: var(--chip-theory-accent); 184 - } 185 - 186 - /* Extra breathing space where one category run hands over to the next. */ 187 - :root[data-toc-style='annotate'] .sidebar-chips .chip-standard + .chip-theory, 188 - :root[data-toc-style='annotate'] .sidebar-chips .chip-theory + .chip-standard, 189 - :root[data-toc-style='focus'] .sidebar-chips .chip-standard + .chip-theory, 190 - :root[data-toc-style='focus'] .sidebar-chips .chip-theory + .chip-standard { 191 - margin-inline-start: 0.35rem; 192 - } 193 - 194 - /* On the active accent pill both the chip text and the run dots invert: the 195 - teal dot is all but invisible against the accent fill, and the category 196 - split is not worth reading on the page you are already on. */ 197 - :root[data-toc-style='annotate'] [aria-current='page'] .sidebar-chips .sl-badge, 198 - :root[data-toc-style='focus'] [aria-current='page'] .sidebar-chips .sl-badge { 199 - color: var(--sl-color-text-invert); 200 - opacity: 0.85; 201 - } 202 - :root[data-toc-style='annotate'] [aria-current='page'] .sidebar-chips .sl-badge::before, 203 - :root[data-toc-style='focus'] [aria-current='page'] .sidebar-chips .sl-badge::before { 204 - background: currentColor; 205 - } 206 - 207 - /* --------------------------------------------------------------------------- 208 - VARIANT 'hover': resting tree is clean; items with info carry a subtle 209 - dotted underline; the info appears in a small floating card on hover or 210 - keyboard focus (250 ms intent delay so casual mouse travel stays calm). 211 - --------------------------------------------------------------------------- */ 212 - 213 - :root[data-toc-style='hover'] #starlight__sidebar a:has(> .sidebar-chips) { 214 - position: relative; 215 - } 216 - 217 - /* The resting tree carries NO marker. Nearly every page in this library is 218 - governed by something, so an always-on underline would mark almost every 219 - row: that is texture, not information, and it fights the labels. The 220 - hairline dotted marker fades in only once the pointer (or the keyboard 221 - focus) is inside the sidebar, which is exactly when the reader is looking 222 - for a way in. */ 223 - :root[data-toc-style='hover'] 224 - #starlight__sidebar 225 - a:has(> .sidebar-chips) 226 - > .sidebar-item-label { 227 - text-decoration: underline dotted 1px transparent; 228 - text-underline-offset: 0.3em; 229 - transition: text-decoration-color 0.15s ease; 230 - } 231 - 232 - :root[data-toc-style='hover'] 233 - #starlight__sidebar:hover 234 - a:has(> .sidebar-chips) 235 - > .sidebar-item-label, 236 - :root[data-toc-style='hover'] 237 - #starlight__sidebar:focus-within 238 - a:has(> .sidebar-chips) 239 - > .sidebar-item-label { 240 - text-decoration-color: var(--chip-marker); 241 - } 242 - 243 - /* No marker on the active accent pill (inverted colours). */ 244 - :root[data-toc-style='hover'] 245 - #starlight__sidebar 246 - a[aria-current='page'] 247 - > .sidebar-item-label { 248 - text-decoration: none; 249 - } 250 - 251 - :root[data-toc-style='hover'] #starlight__sidebar .sidebar-chips { 252 - display: flex; 253 - flex-wrap: wrap; 254 - align-items: baseline; 255 - gap: 0.15rem 0.55rem; 256 - position: absolute; 257 - z-index: 6; 258 - /* Anchored to the link's trailing edge, so the card grows leftwards over 259 - the tree and can never push the sidebar into horizontal scroll, whatever 260 - the nesting depth of the item. */ 261 - inset-inline-end: 0; 262 - inset-block-start: calc(100% - 0.1rem); 263 - max-inline-size: min(15rem, 100%, calc(100vw - 3rem)); 264 - inline-size: max-content; 265 - padding: 0.35rem 0.6rem; 266 - /* gray-5 rather than the hairline: in light theme the card surface is the 267 - same white as the sidebar, so a hairline border left it floating without 268 - an edge. */ 269 - border: 1px solid var(--sl-color-gray-5); 270 - border-radius: 0.375rem; 271 - background: var(--sl-color-bg-nav); 272 - box-shadow: var(--sl-shadow-md); 273 - visibility: hidden; 274 - opacity: 0; 275 - transition: 276 - opacity 0.12s ease, 277 - visibility 0s linear 0.12s; 278 - } 279 - 280 - :root[data-toc-style='hover'] #starlight__sidebar a:hover > .sidebar-chips, 281 - :root[data-toc-style='hover'] #starlight__sidebar a:focus-visible > .sidebar-chips { 282 - visibility: visible; 283 - opacity: 1; 284 - transition-delay: 0.25s; 285 - } 286 - 287 - /* Card text: tinted per category, one leading dot per category run. */ 288 - :root[data-toc-style='hover'] .sidebar-chips .chip-standard { 289 - color: var(--chip-standard-ink); 290 - } 291 - :root[data-toc-style='hover'] .sidebar-chips .chip-theory { 292 - color: var(--chip-theory-ink); 293 - } 294 - :root[data-toc-style='hover'] .sidebar-chips .chip-standard:first-child::before, 295 - :root[data-toc-style='hover'] .sidebar-chips .chip-theory + .chip-standard::before, 296 - :root[data-toc-style='hover'] .sidebar-chips .chip-theory:first-child::before, 297 - :root[data-toc-style='hover'] .sidebar-chips .chip-standard + .chip-theory::before { 298 - content: ''; 299 - display: inline-block; 300 - vertical-align: 0.08em; 301 - inline-size: 0.3rem; 302 - block-size: 0.3rem; 303 - margin-inline-end: 0.3rem; 304 - border-radius: 50%; 305 - } 306 - :root[data-toc-style='hover'] .sidebar-chips .chip-standard:first-child::before, 307 - :root[data-toc-style='hover'] .sidebar-chips .chip-theory + .chip-standard::before { 308 - background: var(--chip-standard-accent); 309 - } 310 - :root[data-toc-style='hover'] .sidebar-chips .chip-theory:first-child::before, 311 - :root[data-toc-style='hover'] .sidebar-chips .chip-standard + .chip-theory::before { 312 - background: var(--chip-theory-accent); 313 - } 314 - 315 - /* WCAG 2.2 1.4.13 (content on hover or focus) wants the card dismissible 316 - without moving the pointer or the focus. Escape stamps `data-card-dismissed` 317 - on the focused link (see Head.astro) and this rule wins over the reveal 318 - rules above by source order. */ 319 - :root[data-toc-style='hover'] #starlight__sidebar a[data-card-dismissed] > .sidebar-chips { 320 - visibility: hidden; 321 - opacity: 0; 322 - transition-delay: 0s; 323 - } 324 - 325 - /* Touch devices have no hover, so on a phone the card would be unreachable: 326 - the same data degrades to the always-on annotation line of the 'annotate' 327 - variant. Keeps the variant usable on the device the docs are most read on. */ 328 - @media (hover: none) { 329 - :root[data-toc-style='hover'] #starlight__sidebar .sidebar-chips { 330 - position: static; 331 - inline-size: auto; 332 - max-inline-size: 100%; 333 - margin-block-start: 0.15rem; 334 - margin-inline-start: 0.9rem; 335 - padding: 0; 336 - border: 0; 337 - border-radius: 0; 338 - background: none; 339 - box-shadow: none; 340 - visibility: visible; 341 - opacity: 1; 342 - } 343 - :root[data-toc-style='hover'] .sidebar-chips .chip-standard, 344 - :root[data-toc-style='hover'] .sidebar-chips .chip-theory { 345 - color: var(--chip-ink-muted); 346 - } 347 - :root[data-toc-style='hover'] [aria-current='page'] .sidebar-chips .sl-badge { 348 - color: var(--sl-color-text-invert); 349 - opacity: 0.85; 350 - } 351 - :root[data-toc-style='hover'] 352 - #starlight__sidebar 353 - a:has(> .sidebar-chips) 354 - > .sidebar-item-label { 355 - text-decoration: none; 356 - } 357 - } 358 - 359 - /* --------------------------------------------------------------------------- 360 - VARIANT 'clean': page-level presentation. The subtitle under the H1 and 361 - the section landing tables are always in the DOM (PageTitle.astro / 362 - SectionStandards.astro) and only display in this variant. 363 - --------------------------------------------------------------------------- */ 364 - 365 - .page-standards, 366 - .section-standards { 367 - display: none; 368 - } 369 - 370 - :root[data-toc-style='clean']:not([data-page-chips='header']) .page-standards { 371 - display: flex; 372 - flex-wrap: wrap; 373 - align-items: baseline; 374 - gap: 0.2rem 0.75rem; 375 - margin-block-start: 0.5rem; 376 - font-size: var(--sl-text-sm); 377 - color: var(--sl-color-gray-2); 378 - } 379 - 380 - :root[data-toc-style='clean'] .section-standards { 381 - display: block; 382 - } 383 - 384 - .page-standards .page-chip { 385 - white-space: nowrap; 386 - font-weight: 500; 387 - } 388 - .page-standards .chip-standard { 389 - color: var(--chip-standard-ink); 390 - } 391 - .page-standards .chip-theory { 392 - color: var(--chip-theory-ink); 393 - } 394 - /* The first visible chip follows the visually-hidden accessibility prefix, 395 - so the run-start selectors pair `:first-child` with `.sr-only + *`. */ 396 - .page-standards .chip-standard:first-child::before, 397 - .page-standards .sr-only + .chip-standard::before, 398 - .page-standards .chip-theory + .chip-standard::before, 399 - .page-standards .chip-theory:first-child::before, 400 - .page-standards .sr-only + .chip-theory::before, 401 - .page-standards .chip-standard + .chip-theory::before { 402 - content: ''; 403 - display: inline-block; 404 - vertical-align: 0.1em; 405 - inline-size: 0.35rem; 406 - block-size: 0.35rem; 407 - margin-inline-end: 0.35rem; 408 - border-radius: 50%; 409 - } 410 - .page-standards .chip-standard:first-child::before, 411 - .page-standards .sr-only + .chip-standard::before, 412 - .page-standards .chip-theory + .chip-standard::before { 413 - background: var(--chip-standard-accent); 414 - } 415 - .page-standards .chip-theory:first-child::before, 416 - .page-standards .sr-only + .chip-theory::before, 417 - .page-standards .chip-standard + .chip-theory::before { 418 - background: var(--chip-theory-accent); 419 - } 420 - 421 - /* Section landing table: quiet, small, standards teal / references amber. */ 422 - .section-standards table { 423 - font-size: var(--sl-text-sm); 424 - } 425 - .section-standards td .chip-standard { 426 - color: var(--chip-standard-ink); 427 - white-space: nowrap; 428 - } 429 - .section-standards td .chip-theory { 430 - color: var(--chip-theory-ink); 431 - white-space: nowrap; 432 - } 433 - .section-standards .subgroup-row td { 434 - font-weight: 600; 435 - color: var(--sl-color-white); 436 - } 437 - 438 - /* Three columns do not survive a phone: the page names wrap to four lines 439 - each and the references column falls off the right edge. Below 30rem the 440 - table becomes a stacked list, one page per block with its standards and 441 - references underneath, which is what the sidebar annotation line does 442 - anyway. */ 443 - @media (max-width: 30rem) { 444 - :root[data-toc-style='clean'] .section-standards table, 445 - :root[data-toc-style='clean'] .section-standards tbody, 446 - :root[data-toc-style='clean'] .section-standards tr, 447 - :root[data-toc-style='clean'] .section-standards td { 448 - display: block; 449 - inline-size: auto; 450 - } 451 - :root[data-toc-style='clean'] .section-standards thead { 452 - position: absolute; 453 - inline-size: 1px; 454 - block-size: 1px; 455 - overflow: hidden; 456 - clip-path: inset(50%); 457 - white-space: nowrap; 458 - } 459 - :root[data-toc-style='clean'] .section-standards tr { 460 - padding-block: 0.4rem; 461 - border-block-end: 1px solid var(--sl-color-hairline-light); 462 - } 463 - :root[data-toc-style='clean'] .section-standards td { 464 - padding: 0.1rem 0; 465 - border: 0; 466 - } 467 - :root[data-toc-style='clean'] .section-standards td:empty { 468 - display: none; 469 - } 470 - } 471 - 472 - /* --------------------------------------------------------------------------- 473 - PAGE CHIPS (`data-page-chips='header'`), independent of the sidebar 474 - variants: one quiet run under the H1 naming the standards that govern the 475 - page and the works its methods are attributed to, every item a link into 476 - the References section at the bottom. Rendered by PageChips.astro from the 477 - page's own frontmatter bibliography. 478 - 479 - Deliberately not pills: at page level a run of tinted text with one leading 480 - dot per category reads as a dateline, while filled badges read as tags and 481 - compete with the H1. 482 - --------------------------------------------------------------------------- */ 483 - 484 - .page-chips { 485 - display: none; 486 - } 487 - 488 - :root[data-page-chips='header'] .page-chips { 489 - display: flex; 490 - flex-wrap: wrap; 491 - align-items: baseline; 492 - gap: 0.15rem 1.15rem; 493 - margin-block-start: 0.55rem; 494 - font-size: var(--sl-text-sm); 495 - line-height: 1.5; 496 - } 497 - 498 - .page-chips .chip-run { 499 - display: inline-flex; 500 - flex-wrap: wrap; 501 - align-items: baseline; 502 - gap: 0.15rem 0.7rem; 503 - } 504 - 505 - /* One leading dot per category run: teal for the governing standards, amber 506 - for the named references. Two marks per page, no legend needed, and the 507 - labels stay language neutral. */ 508 - .page-chips .chip-run::before { 509 - content: ''; 510 - flex: 0 0 auto; 511 - align-self: center; 512 - inline-size: 0.4rem; 513 - block-size: 0.4rem; 514 - margin-inline-end: 0.1rem; 515 - border-radius: 50%; 516 - } 517 - .page-chips .chip-run-standard::before { 518 - background: var(--chip-standard-accent); 519 - } 520 - .page-chips .chip-run-reference::before { 521 - background: var(--chip-theory-accent); 522 - } 523 - 524 - .page-chips .page-chip { 525 - font-weight: 500; 526 - white-space: nowrap; 527 - text-decoration: none; 528 - } 529 - .page-chips .page-chip:hover, 530 - .page-chips .page-chip:focus-visible { 531 - text-decoration: underline; 532 - text-underline-offset: 0.25em; 533 - } 534 - .page-chips .chip-standard { 535 - color: var(--chip-standard-ink); 536 - } 537 - .page-chips .chip-theory { 538 - color: var(--chip-theory-ink); 539 - } 540 - .page-chips .chip-more { 541 - color: var(--chip-ink-muted); 542 - } 543 - 544 - /* --------------------------------------------------------------------------- 545 - API SIDEBAR MODES. 546 - --------------------------------------------------------------------------- */ 547 - 548 - /* 'collapsed': the caret shows and the group's children fold. The switcher 549 - script stamps `.folded` (initial state: folded on guide pages, open on API 550 - pages) and keeps `aria-expanded` in sync. */ 551 - :root[data-api-style='collapsed'] .api-group .api-caret { 552 - display: inline-flex; 553 - } 554 - :root[data-api-style='collapsed'] .api-group.folded > ul { 555 - display: none; 556 - } 557 - 558 - /* 'split': topic-style separation. On guide pages the API group reduces to 559 - its single label link with a forward arrow... */ 560 - :root[data-api-style='split'][data-area='guides'] .api-group > ul { 561 - display: none; 562 - } 563 - :root[data-api-style='split'][data-area='guides'] .api-group .group-label .large::after { 564 - content: ' \2192'; 565 - color: var(--sl-color-gray-3); 566 - } 567 - 568 - /* ...and on API pages only the top-level group that contains the API 569 - reference (the Reference group) remains, plus the back link. */ 570 - :root[data-api-style='split'][data-area='api'] 571 - #starlight__sidebar 572 - .top-level 573 - > li:not(:has(.api-group)) { 574 - display: none; 575 - } 576 - 577 - .topic-back { 578 - display: none; 579 - } 580 - :root[data-api-style='split'][data-area='api'] .topic-back { 581 - display: flex; 582 - align-items: center; 583 - gap: 0.4rem; 584 - margin-block-end: 0.75rem; 585 - padding: 0.3em 0.5rem; 586 - border-radius: 0.25rem; 587 - font-size: var(--sl-text-sm); 588 - font-weight: 600; 589 - color: var(--sl-color-gray-2); 590 - text-decoration: none; 591 - } 592 - :root[data-api-style='split'][data-area='api'] .topic-back:hover, 593 - :root[data-api-style='split'][data-area='api'] .topic-back:focus-visible { 594 - color: var(--sl-color-white); 595 - background: var(--sl-color-gray-6); 596 - } 597 - 598 - /* --------------------------------------------------------------------------- 599 - VARIANT SWITCHER WIDGET (prototype-only UI, injected by Head.astro). 600 - --------------------------------------------------------------------------- */ 601 - 602 - .toc-switcher { 603 - position: fixed; 604 - inset-block-end: 1rem; 605 - inset-inline-end: 1rem; 606 - z-index: 100; 607 - font-family: var(--sl-font-system, sans-serif); 608 - font-size: 0.75rem; 609 - color: var(--sl-color-gray-2); 610 - } 611 - 612 - .toc-switcher summary { 613 - list-style: none; 614 - cursor: pointer; 615 - inline-size: 2.25rem; 616 - block-size: 2.25rem; 617 - display: flex; 618 - align-items: center; 619 - justify-content: center; 620 - margin-inline-start: auto; 621 - border: 1px solid var(--sl-color-hairline-light); 622 - border-radius: 50%; 623 - background: var(--sl-color-bg-nav); 624 - box-shadow: var(--sl-shadow-md); 625 - font-weight: 700; 626 - color: var(--sl-color-gray-1); 627 - } 628 - .toc-switcher summary::-webkit-details-marker { 629 - display: none; 630 - } 631 - 632 - .toc-switcher .toc-switcher-panel { 633 - margin-block-start: 0.5rem; 634 - padding: 0.75rem; 635 - border: 1px solid var(--sl-color-hairline-light); 636 - border-radius: 0.5rem; 637 - background: var(--sl-color-bg-nav); 638 - box-shadow: var(--sl-shadow-lg); 639 - min-inline-size: 13rem; 640 - } 641 - 642 - .toc-switcher fieldset { 643 - border: 0; 644 - margin: 0; 645 - padding: 0; 646 - } 647 - .toc-switcher fieldset + fieldset { 648 - margin-block-start: 0.6rem; 649 - } 650 - .toc-switcher legend { 651 - font-weight: 700; 652 - text-transform: uppercase; 653 - letter-spacing: 0.06em; 654 - font-size: 0.65rem; 655 - color: var(--sl-color-gray-3); 656 - padding: 0; 657 - margin-block-end: 0.25rem; 658 - } 659 - .toc-switcher label { 660 - display: flex; 661 - align-items: center; 662 - gap: 0.4rem; 663 - padding: 0.1rem 0; 664 - cursor: pointer; 665 - }
+332
site/src/styles/ux-variants.css
··· 1 + /* Page header chips and API sidebar treatments: switchable prototypes. 2 + 3 + The sidebar carries no standards information at all. That decision is 4 + final: the tree stays exactly as it is and everything about "what governs 5 + this page" lives in the page header, one row per page, derived from the 6 + page's own `references` frontmatter (PageChips.astro plus 7 + src/lib/reference-chips.ts). 8 + 9 + Two independent attributes on <html>, applied before first paint by the 10 + switcher script in Head.astro and persisted in localStorage: 11 + 12 + data-page-chips='header' the quiet run: tinted text, one small colour 13 + dot leading each category. 14 + data-page-chips='pills' the same content as outlined pills, so the 15 + chips read as the links they are. 16 + data-page-chips='filled' outlined pills with a faint category tint. 17 + data-page-chips='off' no run at all. 18 + 19 + data-api-style='inline' the API reference group renders fully 20 + expanded in place (status quo). 21 + data-api-style='collapsed' the API group gets a caret and folds; it 22 + starts folded on guide pages and unfolded on 23 + API pages. 24 + data-api-style='split' topic-style split: on guide pages the API 25 + group collapses to its single label link; on 26 + API pages only the Reference group is shown 27 + plus a "Guides" back link. 28 + 29 + `data-area` ('guides' | 'api') is stamped on <html> from the URL by the 30 + same script. All selectors are unlayered so they win over Starlight's 31 + layered styles without specificity games. Both themes are covered (dark 32 + values on :root, light overrides on [data-theme='light']). */ 33 + 34 + :root { 35 + /* Category colours, dark theme. `*-accent` is the leading dot and the pill 36 + border, `*-ink` the text, `*-tint` the filled pill background. */ 37 + --chip-standard-accent: #6fdcc8; 38 + --chip-standard-ink: #7ee8d5; 39 + --chip-standard-tint: rgb(111 220 200 / 18%); 40 + --chip-standard-tint-strong: rgb(111 220 200 / 32%); 41 + --chip-standard-line: rgb(111 220 200 / 38%); 42 + --chip-theory-accent: #e6b84e; 43 + --chip-theory-ink: #f4c04e; 44 + --chip-theory-tint: rgb(230 184 78 / 18%); 45 + --chip-theory-tint-strong: rgb(230 184 78 / 32%); 46 + --chip-theory-line: rgb(230 184 78 / 38%); 47 + --chip-ink-muted: hsl(224, 8%, 62%); 48 + } 49 + 50 + :root[data-theme='light'] { 51 + --chip-standard-accent: #128273; 52 + --chip-standard-ink: #0c5c52; 53 + --chip-standard-tint: rgb(18 130 115 / 12%); 54 + --chip-standard-tint-strong: rgb(18 130 115 / 22%); 55 + --chip-standard-line: rgb(18 130 115 / 35%); 56 + --chip-theory-accent: #a8760a; 57 + --chip-theory-ink: #855107; 58 + --chip-theory-tint: rgb(168 118 10 / 13%); 59 + --chip-theory-tint-strong: rgb(168 118 10 / 24%); 60 + --chip-theory-line: rgb(168 118 10 / 35%); 61 + --chip-ink-muted: hsl(224, 7%, 42%); 62 + } 63 + 64 + /* --------------------------------------------------------------------------- 65 + PAGE CHIPS, shared structure. One run per category under the H1: the 66 + standards that govern the page, then the works its methods are attributed 67 + to. Every chip links to its full entry in the page bibliography. 68 + --------------------------------------------------------------------------- */ 69 + 70 + .page-chips { 71 + display: none; 72 + } 73 + 74 + :root[data-page-chips='header'] .page-chips, 75 + :root[data-page-chips='pills'] .page-chips, 76 + :root[data-page-chips='filled'] .page-chips { 77 + display: flex; 78 + flex-wrap: wrap; 79 + align-items: baseline; 80 + margin-block-start: 0.55rem; 81 + font-size: var(--sl-text-sm); 82 + line-height: 1.5; 83 + } 84 + 85 + .page-chips .chip-run { 86 + display: inline-flex; 87 + flex-wrap: wrap; 88 + align-items: baseline; 89 + } 90 + 91 + .page-chips .page-chip { 92 + font-weight: 500; 93 + white-space: nowrap; 94 + text-decoration: none; 95 + } 96 + 97 + .page-chips .chip-standard { 98 + color: var(--chip-standard-ink); 99 + } 100 + .page-chips .chip-theory { 101 + color: var(--chip-theory-ink); 102 + } 103 + .page-chips .chip-more { 104 + color: var(--chip-ink-muted); 105 + } 106 + 107 + /* --------------------------------------------------------------------------- 108 + STYLE 'header': a run of tinted text. One leading dot per category run 109 + carries the whole legend, so nothing needs a box and the line reads as the 110 + dateline of a standard rather than as a row of tags. 111 + --------------------------------------------------------------------------- */ 112 + 113 + :root[data-page-chips='header'] .page-chips { 114 + gap: 0.15rem 1.15rem; 115 + } 116 + :root[data-page-chips='header'] .chip-run { 117 + gap: 0.15rem 0.7rem; 118 + } 119 + 120 + :root[data-page-chips='header'] .chip-run::before { 121 + content: ''; 122 + flex: 0 0 auto; 123 + align-self: center; 124 + inline-size: 0.4rem; 125 + block-size: 0.4rem; 126 + margin-inline-end: 0.1rem; 127 + border-radius: 50%; 128 + } 129 + :root[data-page-chips='header'] .chip-run-standard::before { 130 + background: var(--chip-standard-accent); 131 + } 132 + :root[data-page-chips='header'] .chip-run-reference::before { 133 + background: var(--chip-theory-accent); 134 + } 135 + 136 + :root[data-page-chips='header'] .page-chip:hover, 137 + :root[data-page-chips='header'] .page-chip:focus-visible { 138 + text-decoration: underline; 139 + text-underline-offset: 0.25em; 140 + } 141 + 142 + /* --------------------------------------------------------------------------- 143 + STYLES 'pills' and 'filled': the same content inside a bordered chip, so 144 + the clickability is visible without hovering. The border colour carries 145 + the category, which lets the pill stay small, low contrast and unfilled 146 + (or barely filled) instead of turning into the badge that was rejected in 147 + the sidebar experiment. 148 + --------------------------------------------------------------------------- */ 149 + 150 + :root[data-page-chips='pills'] .page-chips, 151 + :root[data-page-chips='filled'] .page-chips { 152 + align-items: center; 153 + /* The gap between the two category runs is wider than the gap inside one, 154 + so the standards and the named works still read as two groups without a 155 + dot to mark the boundary. */ 156 + gap: 0.3rem 1.1rem; 157 + } 158 + :root[data-page-chips='pills'] .chip-run, 159 + :root[data-page-chips='filled'] .chip-run { 160 + align-items: center; 161 + gap: 0.3rem 0.35rem; 162 + } 163 + 164 + :root[data-page-chips='pills'] .page-chip, 165 + :root[data-page-chips='filled'] .page-chip { 166 + padding: 0.1rem 0.5rem; 167 + border: 1px solid var(--chip-line, var(--sl-color-gray-5)); 168 + border-radius: 999px; 169 + font-size: 0.75rem; 170 + line-height: 1.5; 171 + transition: 172 + background-color 0.12s ease, 173 + border-color 0.12s ease; 174 + } 175 + 176 + :root[data-page-chips='pills'] .chip-standard, 177 + :root[data-page-chips='filled'] .chip-standard { 178 + --chip-line: var(--chip-standard-line); 179 + --chip-fill: var(--chip-standard-tint); 180 + --chip-fill-strong: var(--chip-standard-tint-strong); 181 + } 182 + :root[data-page-chips='pills'] .chip-theory, 183 + :root[data-page-chips='filled'] .chip-theory { 184 + --chip-line: var(--chip-theory-line); 185 + --chip-fill: var(--chip-theory-tint); 186 + --chip-fill-strong: var(--chip-theory-tint-strong); 187 + } 188 + 189 + :root[data-page-chips='filled'] .page-chip { 190 + background: var(--chip-fill, transparent); 191 + } 192 + 193 + /* Hover and focus: the tint appears (outlined) or deepens (filled) and the 194 + border firms up, so the state is legible in both themes without moving 195 + anything. */ 196 + :root[data-page-chips='pills'] .page-chip:hover, 197 + :root[data-page-chips='pills'] .page-chip:focus-visible, 198 + :root[data-page-chips='filled'] .page-chip:hover, 199 + :root[data-page-chips='filled'] .page-chip:focus-visible { 200 + background: var(--chip-fill-strong, var(--sl-color-gray-6)); 201 + border-color: currentColor; 202 + } 203 + 204 + :root[data-page-chips='pills'] .chip-more, 205 + :root[data-page-chips='filled'] .chip-more { 206 + --chip-line: var(--sl-color-gray-5); 207 + --chip-fill: transparent; 208 + --chip-fill-strong: var(--sl-color-gray-6); 209 + } 210 + 211 + /* --------------------------------------------------------------------------- 212 + API SIDEBAR TREATMENTS. 213 + --------------------------------------------------------------------------- */ 214 + 215 + /* 'collapsed': the caret shows and the group's children fold. The switcher 216 + script stamps `.folded` (initial state: folded on guide pages, open on API 217 + pages) and keeps `aria-expanded` in sync. */ 218 + :root[data-api-style='collapsed'] .api-group .api-caret { 219 + display: inline-flex; 220 + } 221 + :root[data-api-style='collapsed'] .api-group.folded > ul { 222 + display: none; 223 + } 224 + 225 + /* 'split': topic-style separation. On guide pages the API group reduces to 226 + its single label link with a forward arrow... */ 227 + :root[data-api-style='split'][data-area='guides'] .api-group > ul { 228 + display: none; 229 + } 230 + :root[data-api-style='split'][data-area='guides'] .api-group .group-label .large::after { 231 + content: ' \2192'; 232 + color: var(--sl-color-gray-3); 233 + } 234 + 235 + /* ...and on API pages only the top-level group that contains the API 236 + reference (the Reference group) remains, plus the back link. */ 237 + :root[data-api-style='split'][data-area='api'] 238 + #starlight__sidebar 239 + .top-level 240 + > li:not(:has(.api-group)) { 241 + display: none; 242 + } 243 + 244 + .topic-back { 245 + display: none; 246 + } 247 + :root[data-api-style='split'][data-area='api'] .topic-back { 248 + display: flex; 249 + align-items: center; 250 + gap: 0.4rem; 251 + margin-block-end: 0.75rem; 252 + padding: 0.3em 0.5rem; 253 + border-radius: 0.25rem; 254 + font-size: var(--sl-text-sm); 255 + font-weight: 600; 256 + color: var(--sl-color-gray-2); 257 + text-decoration: none; 258 + } 259 + :root[data-api-style='split'][data-area='api'] .topic-back:hover, 260 + :root[data-api-style='split'][data-area='api'] .topic-back:focus-visible { 261 + color: var(--sl-color-white); 262 + background: var(--sl-color-gray-6); 263 + } 264 + 265 + /* --------------------------------------------------------------------------- 266 + VARIANT SWITCHER WIDGET (prototype-only UI, injected by Head.astro). 267 + --------------------------------------------------------------------------- */ 268 + 269 + .toc-switcher { 270 + position: fixed; 271 + inset-block-end: 1rem; 272 + inset-inline-end: 1rem; 273 + z-index: 100; 274 + font-family: var(--sl-font-system, sans-serif); 275 + font-size: 0.75rem; 276 + color: var(--sl-color-gray-2); 277 + } 278 + 279 + .toc-switcher summary { 280 + list-style: none; 281 + cursor: pointer; 282 + inline-size: 2.25rem; 283 + block-size: 2.25rem; 284 + display: flex; 285 + align-items: center; 286 + justify-content: center; 287 + margin-inline-start: auto; 288 + border: 1px solid var(--sl-color-hairline-light); 289 + border-radius: 50%; 290 + background: var(--sl-color-bg-nav); 291 + box-shadow: var(--sl-shadow-md); 292 + font-weight: 700; 293 + color: var(--sl-color-gray-1); 294 + } 295 + .toc-switcher summary::-webkit-details-marker { 296 + display: none; 297 + } 298 + 299 + .toc-switcher .toc-switcher-panel { 300 + margin-block-start: 0.5rem; 301 + padding: 0.75rem; 302 + border: 1px solid var(--sl-color-hairline-light); 303 + border-radius: 0.5rem; 304 + background: var(--sl-color-bg-nav); 305 + box-shadow: var(--sl-shadow-lg); 306 + min-inline-size: 13rem; 307 + } 308 + 309 + .toc-switcher fieldset { 310 + border: 0; 311 + margin: 0; 312 + padding: 0; 313 + } 314 + .toc-switcher fieldset + fieldset { 315 + margin-block-start: 0.6rem; 316 + } 317 + .toc-switcher legend { 318 + font-weight: 700; 319 + text-transform: uppercase; 320 + letter-spacing: 0.06em; 321 + font-size: 0.65rem; 322 + color: var(--sl-color-gray-3); 323 + padding: 0; 324 + margin-block-end: 0.25rem; 325 + } 326 + .toc-switcher label { 327 + display: flex; 328 + align-items: center; 329 + gap: 0.4rem; 330 + padding: 0.1rem 0; 331 + cursor: pointer; 332 + }