diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 6400155e4..f2e52791d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -25,6 +25,10 @@ jobs: steps: - name: Check out project repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # The docs pages date themselves from when git last touched them, + # which a single-commit checkout cannot answer. + fetch-depth: 0 - name: Set up Node.js runtime uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: diff --git a/_assets/styles/_docs-page.scss b/_assets/styles/_docs-page.scss new file mode 100644 index 000000000..595fe0ccb --- /dev/null +++ b/_assets/styles/_docs-page.scss @@ -0,0 +1,498 @@ +@use 'sass:color'; + +// A documentation page: the head band and the foot read at the same 1200px +// width as the rest of the site; the prose between them sits at a reading +// measure instead, because these fourteen pages are for reading. Covers both +// docs.liquid's thirteen pages and deep-page.liquid's /about/vision/, which +// carries the same doc-page body class but renders no breadcrumb, no Key +// Point, and no foot. + +// Colours come from _sublime-theme.scss and reuse the exact tones +// _news-item.scss and _docs.scss give a reading page and a quiet section, so +// a handbook page agrees with the rest of the site on what a link, a muted +// caption, and an aside look like. + +$doc-wrap: 1200px; +$doc-gutter: clamp(1rem, 4vw, 3rem); +$doc-link: shade-color($primary, 25%); +$doc-muted: #4b433c; +$doc-hairline: rgb(167 151 139 / 55%); + +// Raw $tertiary is too pale to serve as a rule on parchment; shaded, it +// still reads as the same neutral and holds up as one. +$doc-rule: shade-color($tertiary, 20%); + +// The wash _docs.scss and _news.scss give a quiet section, reused here at +// prose scale: a callout's fill, an inline code chip, and the flash a +// heading gets when it is the page's `:target`. +$doc-quiet: color.mix($tertiary, $body-bg, 12%); + +// $quaternary as solid text on parchment fails AA; shaded, it clears it. The +// unshaded colour still suits the "not recommended" rule below, which only +// has to clear the lower non-text minimum. +$doc-bad-text: shade-color($quaternary, 25%); + +// Scoped to `main` to keep the resets off the navbar and footer, which are +// its siblings under the same body class. The padding replaces what +// `main > .container` gives the footer elsewhere. +.doc-page main { + padding-bottom: 104px; +} + +.doc-page main a { + color: $doc-link; +} + +.doc-page main :focus-visible { + outline: 2px solid $body-color; + outline-offset: 2px; +} + +.doc-page .wrap { + max-width: $doc-wrap; + padding-inline: $doc-gutter; + margin-inline: auto; +} + +/* --- Head: breadcrumb, title, Key Point --------------------------------- + A flat stack, not a grid: unlike the masthead, there is no second panel + beside it. +*/ + +// Ink, so it carries on from the navbar rather than leaving a pale band +// between the two. +.doc-page .doc-head { + padding-top: calc(#{$navbar-height} + clamp(2rem, 5vw, 3.5rem)); + padding-bottom: clamp(2.25rem, 5vw, 3.5rem); + color: $body-bg; + background-color: $body-color; +} + +// The band opens flush, with no borrowed margin above its first element. +.doc-page .doc-head .wrap > :first-child { + margin-top: 0; +} + +.doc-page .breadcrumb-list { + display: flex; + flex-wrap: wrap; + gap: 0.25rem 0; + padding: 0; + margin: 0; + font-family: $font-family-monospace; + font-size: 0.8125rem; + list-style: none; +} + +.doc-page .breadcrumb-step + .breadcrumb-step::before { + margin-inline: 0.4375em; + content: '›'; +} + +// Links on the ink. `.doc-page main a` is (0,1,2), so this needs `main` too. +.doc-page main .breadcrumb-step a { + color: rgb(231 231 214 / 82%); +} + +.doc-page main .breadcrumb-step a:hover { + color: $body-bg; +} + +// _custom.scss makes every h1 a flex row and draws a rule after it, which is +// right for a page heading and wrong at this scale. +.doc-page .doc-title { + display: block; + max-width: 40ch; + margin-top: 1rem; + font-size: clamp(1.875rem, 4.5vw, 2.75rem); + font-weight: 700; + line-height: 1.08; + letter-spacing: -0.02em; +} + +.doc-page .doc-title::after { + content: none; +} + +// The measure sits on the element that carries the font-size, so the `ch` it +// reads is the one the Key Point is actually set in. +.doc-page .doc-key { + max-width: 42ch; + margin-top: 1rem; + font-size: clamp(1rem, 1.6vw, 1.0625rem); + line-height: 1.6; + color: rgb(231 231 214 / 76%); +} + +/* --- Body: the prose ------------------------------------------------------ + The measure sits on `.doc-prose` itself, alongside its own font-size, for + the same reason. +*/ + +.doc-page .doc-body { + padding-block: clamp(2.5rem, 6vw, 4rem); +} + +// contributing.md autolinks a couple of bare GitHub label URLs; as visible +// link text they are one unbroken token long enough to push past 390px. +.doc-page .doc-prose { + max-width: 65ch; + margin-inline: auto; + font-size: 1.0625rem; + line-height: 1.75; + overflow-wrap: break-word; +} + +.doc-page .doc-prose > :first-child { + margin-top: 0; +} + +.doc-page .doc-prose > :last-child { + margin-bottom: 0; +} + +.doc-page .doc-prose p, +.doc-page .doc-prose ul, +.doc-page .doc-prose ol, +.doc-page .doc-prose table, +.doc-page .doc-prose pre { + margin-block: 1.375em; +} + +.doc-page .doc-prose h2, +.doc-page .doc-prose h3 { + font-weight: 700; + line-height: 1.3; +} + +.doc-page .doc-prose h2 { + margin-top: 2.5em; + margin-bottom: 0.75em; + font-size: 1.5rem; + letter-spacing: -0.01em; +} + +.doc-page .doc-prose h3 { + margin-top: 1.75em; + margin-bottom: 0.625em; + font-size: 1.1875rem; +} + +// Headings carry an id and no visible affordance; a cross-page anchor link +// (the handbook is full of them) needs something to confirm on arrival. +.doc-page .doc-prose :is(h2, h3):target { + padding-inline-start: 0.625em; + margin-inline-start: -0.625em; + background-color: $doc-quiet; +} + +.doc-page .doc-prose ul, +.doc-page .doc-prose ol { + padding-inline-start: 1.25em; +} + +.doc-page .doc-prose li + li { + margin-top: 0.5em; +} + +// contributing.md's Developer Certificate of Origin list is loose (each item +// is its own paragraph); the item, not the paragraph inside it, carries the +// rhythm. +.doc-page .doc-prose li > p { + margin-block: 0; +} + +.doc-page .doc-prose li > ul, +.doc-page .doc-prose li > ol { + margin-block: 0.5em 0; +} + +.doc-page .doc-prose strong { + font-weight: 700; +} + +.doc-page .doc-prose em { + font-style: italic; +} + +.doc-page .doc-prose a { + text-decoration: underline; +} + +.doc-page .doc-prose abbr[title] { + text-decoration: underline dotted; + cursor: help; +} + +// Reboot gives bare `code` Bootstrap's own pink (`--bs-code-color`); this is +// prose, not a diff, so it reads in the page's own ink instead. +.doc-page .doc-prose code { + padding: 0.15em 0.375em; + font-family: $font-family-monospace; + font-size: 0.875em; + color: $body-color; + background-color: $doc-quiet; +} + +.doc-page .doc-prose pre { + padding: 1rem; + overflow-x: auto; + background-color: $secondary; +} + +.doc-page .doc-prose pre code { + padding: 0; + font-size: 0.875em; + background-color: transparent; +} + +/* --- Examples: Google's recommended / not-recommended pairs -------------- + `.example` always wraps exactly one `.compare-better` or `.compare-worse` + span; `:has()` reads which, so the rule and the label agree without a + second class on the paragraph. +*/ + +.doc-page .doc-prose .example { + padding-inline-start: 1.25em; + margin-block: 1.375em; + border-inline-start: 3px solid $doc-rule; +} + +// A pair reads as one comparison, not two paragraphs in the ordinary rhythm. +.doc-page .doc-prose .example + .example { + margin-block-start: 0.625em; +} + +.doc-page .doc-prose .example:has(.compare-better) { + border-inline-start-color: $primary; +} + +.doc-page .doc-prose .example:has(.compare-worse) { + border-inline-start-color: $quaternary; +} + +.doc-page .doc-prose .compare-better, +.doc-page .doc-prose .compare-worse { + font-weight: 700; +} + +.doc-page .doc-prose .compare-better { + color: $doc-link; +} + +.doc-page .doc-prose .compare-worse { + color: $doc-bad-text; +} + +/* --- Callouts ------------------------------------------------------------- + markdown-it-github-alerts turns `> [!NOTE]` into a titled block. The rule + and the title carry the kind, so the wash stays the same for all of them + and the text keeps one contrast against one ground. +*/ + +.doc-page .doc-prose .markdown-alert { + padding: 0.875rem 1.125rem; + margin-block: 1.375em; + color: $doc-muted; + background-color: $doc-quiet; + border-inline-start: 3px solid $doc-rule; +} + +.doc-page .doc-prose .markdown-alert > :first-child { + margin-top: 0; +} + +.doc-page .doc-prose .markdown-alert > :last-child { + margin-bottom: 0; +} + +.doc-page .doc-prose .markdown-alert-title { + display: flex; + gap: 0.4375rem; + align-items: center; + margin-bottom: 0.375em; + font-family: $font-family-monospace; + font-size: 0.75rem; + font-weight: 700; + color: $body-color; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +// The octicons carry no fill of their own, so they take the title's colour +// and change with it. +.doc-page .doc-prose .markdown-alert-title svg { + flex: none; + width: 1rem; + height: 1rem; + fill: currentcolor; +} + +// Warning and caution are the two that mean stop and read. They take the +// same red the not-recommended examples use. +.doc-page .doc-prose .markdown-alert-warning, +.doc-page .doc-prose .markdown-alert-caution { + border-inline-start-color: $quaternary; +} + +.doc-page .doc-prose .markdown-alert-warning .markdown-alert-title, +.doc-page .doc-prose .markdown-alert-caution .markdown-alert-title { + color: $doc-bad-text; +} + +// A pure-parchment chip on the callout's wash reads as a cutout rather than +// a second, muddier wash stacked on the first. +.doc-page .doc-prose .markdown-alert code { + background-color: $body-bg; +} + +/* --- Tables --------------------------------------------------------------- + `display: block` hands the table its own scroll container without a + wrapper element markdown never gives it; the internal table layout is + unaffected, since `border-collapse` still reaches `th`/`td`. +*/ + +.doc-page .doc-prose table { + display: block; + width: max-content; + max-width: 100%; + margin-block: 1.375em; + overflow-x: auto; + font-size: 0.9375rem; + border-collapse: collapse; +} + +.doc-page .doc-prose th, +.doc-page .doc-prose td { + padding: 0.5rem 0.875rem; + text-align: left; + border-bottom: 1px solid $doc-hairline; +} + +.doc-page .doc-prose th { + font-weight: 700; + border-bottom: 2px solid $body-color; +} + +/* --- Footnotes -------------------------------------------------------- */ + +.doc-page .doc-prose .footnote-ref a { + text-decoration: none; +} + +.doc-page .doc-prose .footnotes-sep { + height: 0; + margin-block: 2.25em 1.25em; + border: 0; + border-top: 1px solid $doc-hairline; +} + +.doc-page .doc-prose .footnotes { + font-size: 0.9375rem; + color: $doc-muted; +} + +.doc-page .doc-prose .footnotes-list { + padding-inline-start: 1.25em; +} + +.doc-page .doc-prose .footnote-backref { + margin-inline-start: 0.375em; + text-decoration: none; +} + +/* --- Foot: licence, attribution, edit link -------------------------------- + Absent on /about/vision/: deep-page.liquid renders no foot at all. +*/ + +.doc-page .doc-foot { + padding-block: clamp(1.5rem, 3vw, 2rem); + border-top: 1px solid $doc-hairline; +} + +.doc-page .doc-foot-grid { + display: flex; + flex-wrap: wrap; + gap: 0.75rem 1.5rem; + align-items: baseline; + justify-content: space-between; +} + +// The buttons name the same terms the sentence under them states, so they +// sit at caption weight rather than as a badge. +.doc-page .doc-cc { + display: flex; + gap: 0.3125rem; + align-items: center; + margin-bottom: 0.5rem; + color: $doc-muted; +} + +.doc-page .doc-cc svg { + width: 1.375rem; + height: 1.375rem; +} + +.doc-page .doc-terms { + max-width: 58ch; + font-size: 0.8125rem; + line-height: 1.6; + color: $doc-muted; +} + +.doc-page .doc-foot-aside { + display: flex; + flex-wrap: wrap; + gap: 0.25rem 1.25rem; + align-items: baseline; +} + +.doc-page .doc-updated { + font-family: $font-family-monospace; + font-size: 0.75rem; + color: $doc-muted; +} + +// The one thing in the foot a reader can act on, so it takes a button's +// shape while the terms beside it stay at caption weight. +.doc-page .doc-edit a { + display: inline-flex; + gap: 0.4375rem; + align-items: center; + padding: 0.4375rem 0.875rem; + font-family: $font-family-monospace; + font-size: 0.8125rem; + font-weight: 700; + text-decoration: none; + border: 1px solid $doc-link; +} + +.doc-page .doc-edit a:hover { + color: $body-bg; + background-color: $doc-link; +} + +.doc-page .doc-edit svg { + flex: none; + width: 0.9375rem; + height: 0.9375rem; + fill: currentcolor; +} + +.doc-page .doc-edit { + flex: none; + font-family: $font-family-monospace; + font-size: 0.8125rem; +} + +/* --- Narrow --------------------------------------------------------------- + Below 480px the foot's two columns no longer both fit on one line even + wrapped; `space-between` would otherwise justify a single stacked item + away from the text it follows. +*/ + +@media (width < 480px) { + .doc-page .doc-foot-grid { + justify-content: flex-start; + } +} diff --git a/_assets/styles/main.scss b/_assets/styles/main.scss index 4f2ea309c..42c93e07d 100644 --- a/_assets/styles/main.scss +++ b/_assets/styles/main.scss @@ -18,6 +18,7 @@ @import '../../node_modules/bootstrap/scss/pagination'; @import 'about'; @import 'docs'; +@import 'docs-page'; @import 'error'; @import 'home'; @import 'nav'; diff --git a/_data/sections.json b/_data/sections.json new file mode 100644 index 000000000..8b19302eb --- /dev/null +++ b/_data/sections.json @@ -0,0 +1,6 @@ +{ + "handbook": { + "name": "Style handbook", + "url": "/docs/#handbook" + } +} diff --git a/_assets/img/cc/COPYING.md b/_includes/assets/img/cc/COPYING.md similarity index 100% rename from _assets/img/cc/COPYING.md rename to _includes/assets/img/cc/COPYING.md diff --git a/_assets/img/cc/cc-by.svg b/_includes/assets/img/cc/cc-by.svg similarity index 100% rename from _assets/img/cc/cc-by.svg rename to _includes/assets/img/cc/cc-by.svg diff --git a/_assets/img/cc/cc-heart-filled.svg b/_includes/assets/img/cc/cc-heart-filled.svg similarity index 100% rename from _assets/img/cc/cc-heart-filled.svg rename to _includes/assets/img/cc/cc-heart-filled.svg diff --git a/_assets/img/cc/cc-heart.svg b/_includes/assets/img/cc/cc-heart.svg similarity index 100% rename from _assets/img/cc/cc-heart.svg rename to _includes/assets/img/cc/cc-heart.svg diff --git a/_assets/img/cc/cc-logo.svg b/_includes/assets/img/cc/cc-logo.svg similarity index 100% rename from _assets/img/cc/cc-logo.svg rename to _includes/assets/img/cc/cc-logo.svg diff --git a/_assets/img/cc/cc-nc-eu.svg b/_includes/assets/img/cc/cc-nc-eu.svg similarity index 100% rename from _assets/img/cc/cc-nc-eu.svg rename to _includes/assets/img/cc/cc-nc-eu.svg diff --git a/_assets/img/cc/cc-nc-jp.svg b/_includes/assets/img/cc/cc-nc-jp.svg similarity index 100% rename from _assets/img/cc/cc-nc-jp.svg rename to _includes/assets/img/cc/cc-nc-jp.svg diff --git a/_assets/img/cc/cc-nc.svg b/_includes/assets/img/cc/cc-nc.svg similarity index 100% rename from _assets/img/cc/cc-nc.svg rename to _includes/assets/img/cc/cc-nc.svg diff --git a/_assets/img/cc/cc-nd.svg b/_includes/assets/img/cc/cc-nd.svg similarity index 100% rename from _assets/img/cc/cc-nd.svg rename to _includes/assets/img/cc/cc-nd.svg diff --git a/_assets/img/cc/cc-pd.svg b/_includes/assets/img/cc/cc-pd.svg similarity index 100% rename from _assets/img/cc/cc-pd.svg rename to _includes/assets/img/cc/cc-pd.svg diff --git a/_assets/img/cc/cc-pdm.svg b/_includes/assets/img/cc/cc-pdm.svg similarity index 100% rename from _assets/img/cc/cc-pdm.svg rename to _includes/assets/img/cc/cc-pdm.svg diff --git a/_assets/img/cc/cc-remix.svg b/_includes/assets/img/cc/cc-remix.svg similarity index 100% rename from _assets/img/cc/cc-remix.svg rename to _includes/assets/img/cc/cc-remix.svg diff --git a/_assets/img/cc/cc-sa.svg b/_includes/assets/img/cc/cc-sa.svg similarity index 100% rename from _assets/img/cc/cc-sa.svg rename to _includes/assets/img/cc/cc-sa.svg diff --git a/_assets/img/cc/cc-sampling-plus.svg b/_includes/assets/img/cc/cc-sampling-plus.svg similarity index 100% rename from _assets/img/cc/cc-sampling-plus.svg rename to _includes/assets/img/cc/cc-sampling-plus.svg diff --git a/_assets/img/cc/cc-sampling.svg b/_includes/assets/img/cc/cc-sampling.svg similarity index 100% rename from _assets/img/cc/cc-sampling.svg rename to _includes/assets/img/cc/cc-sampling.svg diff --git a/_assets/img/cc/cc-share.svg b/_includes/assets/img/cc/cc-share.svg similarity index 100% rename from _assets/img/cc/cc-share.svg rename to _includes/assets/img/cc/cc-share.svg diff --git a/_assets/img/cc/cc-zero.svg b/_includes/assets/img/cc/cc-zero.svg similarity index 100% rename from _assets/img/cc/cc-zero.svg rename to _includes/assets/img/cc/cc-zero.svg diff --git a/_includes/assets/img/octicons/COPYING.md b/_includes/assets/img/octicons/COPYING.md new file mode 100644 index 000000000..bc41ff0c7 --- /dev/null +++ b/_includes/assets/img/octicons/COPYING.md @@ -0,0 +1,44 @@ +# Copying + +The icons in this directory are [Octicons][], by GitHub, taken verbatim from +[`@primer/octicons`][] 19.33.0 and used under the MIT License reproduced below. + +They are vendored rather than installed because the site draws a handful of +them. [`markdown-it-github-alerts`][] carries its own copies of the alert icons +and does not read from here. + +
+ +```text +MIT License + +Copyright (c) 2026 GitHub Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` + + + + +[Octicons]: https://primer.style/octicons/ +[`@primer/octicons`]: https://www.npmjs.com/package/@primer/octicons +[`markdown-it-github-alerts`]: https://www.npmjs.com/package/markdown-it-github-alerts + + + diff --git a/_includes/assets/img/octicons/pencil.svg b/_includes/assets/img/octicons/pencil.svg new file mode 100644 index 000000000..1eb3d917a --- /dev/null +++ b/_includes/assets/img/octicons/pencil.svg @@ -0,0 +1,10 @@ + diff --git a/_includes/breadcrumb.liquid b/_includes/breadcrumb.liquid new file mode 100644 index 000000000..718cf172d --- /dev/null +++ b/_includes/breadcrumb.liquid @@ -0,0 +1,38 @@ +{%- assign trail = page.url | breadcrumb: collections.all, sections -%} +{%- if trail.size > 0 -%} + + {%- comment -%} + The page itself closes the list here, though not above: search results + want the whole trail, while on the page its title is the heading a line + below and would only be read twice. + {%- endcomment -%} + +{%- endif -%} diff --git a/_includes/key-point.liquid b/_includes/key-point.liquid deleted file mode 100644 index 63207961a..000000000 --- a/_includes/key-point.liquid +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/_layouts/deep-page.liquid b/_layouts/deep-page.liquid index df3126e4a..030cd3eba 100644 --- a/_layouts/deep-page.liquid +++ b/_layouts/deep-page.liquid @@ -1,12 +1,24 @@ --- layout: default -editable: true +body_classes: + - doc-page --- +{%- comment -%} + A page below the top level: it opens on the trail that leads to it. +{%- endcomment -%}
-
- {%- if page.permalink != '/' -%} -

{{ title }}

- {%- endif -%} - {{ content }} -
+
+
+
+ {% include 'breadcrumb.liquid' %} +

{{ title }}

+
+
+ +
+
+
{{ content }}
+
+
+
diff --git a/_layouts/docs.liquid b/_layouts/docs.liquid index 48b01246c..63373ea77 100644 --- a/_layouts/docs.liquid +++ b/_layouts/docs.liquid @@ -1,20 +1,126 @@ --- -layout: deep-page.liquid +layout: default body_classes: - docs + - doc-page +editable: true --- -
-
-
- {% if editable != false %} -
- Edit -
- {% endif %} - {{ content }} -
-
-
+{%- comment -%} + Which licence the page states: the handbook is share-alike, the rest of + the documentation is share-alike and non-commercial. +{%- endcomment -%} +{%- assign inHandbook = false -%} +{%- if page.url contains '/docs/handbook/' -%} + {%- assign inHandbook = true -%} +{%- endif -%} +{%- comment -%} + A page adapted from Google's style guide says so with `google: true`, which + reads the source page off its own filename. Where the two differ, name + Google's slug instead: `google: inclusive-documentation`. +{%- endcomment -%} +{%- if google -%} + {%- assign googleSlug = page.fileSlug -%} + {%- unless google == true -%} + {%- assign googleSlug = google -%} + {%- endunless -%} + {%- assign googleUrl = 'https://developers.google.com/style/' + | append: googleSlug + -%} +{%- endif -%} +
+
+
+
+ {% include 'breadcrumb.liquid' %} +

{{ title }}

+ {%- if key_point %} +

{{ key_point }}

+ {%- endif %} +
+
+ +
+
+
{{ content }}
+
+
+
+ + +
diff --git a/_layouts/handbook-content-g-devdocs-style.liquid b/_layouts/handbook-content-g-devdocs-style.liquid deleted file mode 100644 index 330a73da2..000000000 --- a/_layouts/handbook-content-g-devdocs-style.liquid +++ /dev/null @@ -1,120 +0,0 @@ -
-
-
- {%- if editable != false -%} -
- Edit -
- {%- endif -%} -

{{ title }}

-
- {% include key-point.html %} - {{ content }} -
-
- -
-
diff --git a/collections/_docs/README.md b/collections/_docs/README.md index a3e124cdc..a6bb29b0b 100644 --- a/collections/_docs/README.md +++ b/collections/_docs/README.md @@ -1,12 +1,14 @@ ## `open.inf.is` Documentation -> [!WARNING]\ +> [!WARNING] +> > This documentation is still in **draft** stage. All information may be > incomplete, inaccurate, outdated, or even **completely wrong**.
-> [!NOTE]\ +> [!NOTE] +> > If one is using VS Code, it is recommended to use the provided devcontainer > available via the official [Remote Development extension][]. > @@ -68,6 +70,35 @@ nps build

+### Handbook pages adapted from Google + +
+ +Much of the style handbook is adapted from the [Google developer documentation +style guide][], which is offered under [CC BY 4.0][]. That license asks for +credit, so a page carrying any of it says where it came from: + +```yaml +--- +title: Colons +key_point: A colon indicates that closely-related information follows. +google: true +--- +``` + +`google: true` reads the source page off the filename, so `colons.md` credits +`developers.google.com/style/colons`. Where the two do not line up, name +Google's own slug instead, and the credit follows it: + +```yaml +google: inclusive-documentation +``` + +Leave the key off a page that is ours, and no credit is shown. The footer builds +itself either way. + +

+ ### License
@@ -78,7 +109,9 @@ Commons Attribution-NonCommercial-ShareAlike 4.0 International License][]. +[CC BY 4.0]: https://creativecommons.org/licenses/by/4.0/ [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License]: https://creativecommons.org/licenses/by-nc-sa/4.0/ +[Google developer documentation style guide]: https://developers.google.com/style [Remote Development extension]: https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack diff --git a/collections/_docs/handbook/style/capitalization.md b/collections/_docs/handbook/style/capitalization.md index 0a5d60fff..e3296f53d 100644 --- a/collections/_docs/handbook/style/capitalization.md +++ b/collections/_docs/handbook/style/capitalization.md @@ -4,7 +4,8 @@ key_point: When to capitalize, and when to leave a word lowercase. stub: true --- -> [!NOTE]\ +> [!NOTE] +> > This page is a placeholder. It is linked from elsewhere in the handbook and is > yet to be written. diff --git a/collections/_docs/handbook/style/code-in-text.md b/collections/_docs/handbook/style/code-in-text.md index 3f9268546..74a57eb1e 100644 --- a/collections/_docs/handbook/style/code-in-text.md +++ b/collections/_docs/handbook/style/code-in-text.md @@ -4,7 +4,8 @@ key_point: What to set in code font, and how to explain placeholders. stub: true --- -> [!NOTE]\ +> [!NOTE] +> > This page is a placeholder. The sections below are linked from elsewhere in > the handbook and are yet to be written. diff --git a/collections/_docs/handbook/style/code-samples.md b/collections/_docs/handbook/style/code-samples.md index d4b0449dc..bb58d5b1b 100644 --- a/collections/_docs/handbook/style/code-samples.md +++ b/collections/_docs/handbook/style/code-samples.md @@ -4,7 +4,8 @@ key_point: How to introduce and present a code sample. stub: true --- -> [!NOTE]\ +> [!NOTE] +> > This page is a placeholder. The section below is linked from elsewhere in the > handbook and is yet to be written. diff --git a/collections/_docs/handbook/style/code-syntax.md b/collections/_docs/handbook/style/code-syntax.md index c47fdefc1..a260860bb 100644 --- a/collections/_docs/handbook/style/code-syntax.md +++ b/collections/_docs/handbook/style/code-syntax.md @@ -1,6 +1,7 @@ --- title: Documenting Command-Line Syntax key_point: Recommendations for documenting command-line tools. +google: true --- ## Placeholder variables diff --git a/collections/_docs/handbook/style/colons.md b/collections/_docs/handbook/style/colons.md index 042f85710..f5ebf2a45 100644 --- a/collections/_docs/handbook/style/colons.md +++ b/collections/_docs/handbook/style/colons.md @@ -1,8 +1,7 @@ --- title: Colons key_point: A colon indicates that closely-related information follows. -original_url: https://developers.google.com/style/colons -original_title: Colons | Google developer documentation style guide +google: true --- ## Introductory Phrase Preceding Colon diff --git a/collections/_docs/handbook/style/commit-messages.md b/collections/_docs/handbook/style/commit-messages.md index d6b416f37..8b4a0311f 100644 --- a/collections/_docs/handbook/style/commit-messages.md +++ b/collections/_docs/handbook/style/commit-messages.md @@ -144,7 +144,8 @@ Certificate of Origin][], and saying a tool helped is not a transfer of responsibility. You are answerable for every line in your pull request, whatever wrote it. -> [!WARNING]\ +> [!WARNING] +> > git only looks for trailers in the **last** paragraph of the message, and only > if every line in it is a trailer. Three consequences, each of which has > silently cost this project its metadata: diff --git a/collections/_docs/handbook/style/dashes.md b/collections/_docs/handbook/style/dashes.md index 3cb6664bf..1c0441755 100644 --- a/collections/_docs/handbook/style/dashes.md +++ b/collections/_docs/handbook/style/dashes.md @@ -4,7 +4,8 @@ key_point: Which dash to use, and how it differs from a colon. stub: true --- -> [!NOTE]\ +> [!NOTE] +> > This page is a placeholder. The section below is linked from elsewhere in the > handbook and is yet to be written. diff --git a/collections/_docs/handbook/style/lists.md b/collections/_docs/handbook/style/lists.md index 2817ff974..fa9ab7c9a 100644 --- a/collections/_docs/handbook/style/lists.md +++ b/collections/_docs/handbook/style/lists.md @@ -4,7 +4,8 @@ key_point: How to introduce and punctuate lists. stub: true --- -> [!NOTE]\ +> [!NOTE] +> > This page is a placeholder. The section below is linked from elsewhere in the > handbook and is yet to be written. diff --git a/collections/_docs/handbook/style/people-person-first-language.md b/collections/_docs/handbook/style/people-person-first-language.md index 536c80c82..239851a88 100644 --- a/collections/_docs/handbook/style/people-person-first-language.md +++ b/collections/_docs/handbook/style/people-person-first-language.md @@ -6,7 +6,8 @@ key_point: stub: true --- -> [!NOTE]\ +> [!NOTE] +> > This page is a placeholder. The rule below stands; the guidance that would > follow it is yet to be written. diff --git a/eleventy.config.mjs b/eleventy.config.mjs index 762a46180..1873c9d49 100644 --- a/eleventy.config.mjs +++ b/eleventy.config.mjs @@ -1,3 +1,4 @@ +import { execFileSync } from 'node:child_process'; import { parse as pathParse } from 'node:path'; import { EleventyI18nPlugin } from '@11ty/eleventy'; import { PATHS } from '@openinf/portal/build/constants'; @@ -5,6 +6,7 @@ import autoprefixer from 'autoprefixer'; import cssnano from 'cssnano'; import markdownItAnchor from 'markdown-it-anchor'; import markdownItFootnote from 'markdown-it-footnote'; +import markdownItGitHubAlerts from 'markdown-it-github-alerts'; import postcss from 'postcss'; import { compileString } from 'sass'; @@ -15,6 +17,81 @@ export default async function (eleventyConfig) { eleventyConfig.amendLibrary('md', (md) => { md.use(markdownItAnchor); md.use(markdownItFootnote); + // `> [!NOTE]` and the rest become a titled callout rather than a + // blockquote opening on the literal marker. The icons it ships with come + // through as well; _docs-page.scss draws them in the title's own colour. + md.use(markdownItGitHubAlerts); + }); + + // When a page last changed, read from git rather than the file's mtime, + // which a checkout sets to the moment it ran. A shallow clone holds one + // commit and would date every page to the build, so it reports nothing + // instead and the layouts leave the line off. + const gitIsShallow = (() => { + try { + return ( + execFileSync('git', ['rev-parse', '--is-shallow-repository'], { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'ignore'], + }).trim() === 'true' + ); + } catch { + return true; + } + })(); + + const lastChanged = new Map(); + eleventyConfig.addFilter('gitLastUpdated', (inputPath) => { + if (gitIsShallow || !inputPath) return null; + const file = String(inputPath).replace(/^\.\//, ''); + if (!lastChanged.has(file)) { + let iso = ''; + try { + iso = execFileSync('git', ['log', '-1', '--format=%cI', '--', file], { + encoding: 'utf8', + stdio: ['ignore', 'pipe', 'ignore'], + }).trim(); + } catch { + iso = ''; + } + lastChanged.set(file, iso ? new Date(iso) : null); + } + + return lastChanged.get(file); + }); + + // The trail to a page, built from somewhere a reader can actually go + // rather than from the slashes in its URL. `/docs/handbook/style/colons/` + // has no page at `/docs/handbook/` or `/docs/handbook/style/`, so a trail + // split off the URL would link twice into nothing, and a post's date + // directories would do it three times. A step appears here only if a page + // sits at that URL, or `_data/sections.json` names somewhere else it can + // point. The trail always terminates at the front page, and stops short of + // the page it is on, whose title is the heading directly below it. + eleventyConfig.addFilter('breadcrumb', (url, all, sections) => { + if (typeof url !== 'string' || url === '/') return []; + + const titles = new Map( + (all ?? []) + .filter((item) => item?.url && item.data?.title) + .map((item) => [item.url, item.data.title]) + ); + // The front page is titled for its own heading, not for this list. + const trail = [{ title: 'Home', url: '/' }]; + const parts = url.split('/').filter(Boolean); + + for (let index = 0; index < parts.length - 1; index += 1) { + const ancestor = `/${parts.slice(0, index + 1).join('/')}/`; + const named = sections?.[parts[index]]; + + if (titles.has(ancestor)) { + trail.push({ title: titles.get(ancestor), url: ancestor }); + } else if (named?.name && named?.url) { + trail.push({ title: named.name, url: named.url }); + } + } + + return trail; }); // Configure Eleventy. @@ -99,6 +176,11 @@ export default async function (eleventyConfig) { 'Aggregate, curate, disseminate, and apply information derived from diverse sources.' ); eleventyConfig.addGlobalData('siteUrl', 'https://open.inf.is'); + // The branch an "Improve this page" link opens against. Fixed rather than + // read from the checkout, which during a pull request build is the branch + // under review; GitHub's editor also wants a branch it can commit to, and + // takes no symbolic ref. + eleventyConfig.addGlobalData('repoBranch', 'live'); // What Jekyll called `site.time`: the moment the site was generated. The // footer still asks for it through a `date` filter, so this is the instant // rather than a formatted year, and anything else wanting a build date can diff --git a/package.json b/package.json index c0776113b..9626662ed 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "markdown-it-abbr": "2.0.0", "markdown-it-anchor": "9.2.1", "markdown-it-footnote": "4.0.0", + "markdown-it-github-alerts": "1.0.1", "markdown-it-sub": "2.0.0", "markdown-it-sup": "2.0.0", "markdown-it-task-lists": "2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7750d5121..fee17a966 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,6 +71,9 @@ importers: markdown-it-footnote: specifier: 4.0.0 version: 4.0.0 + markdown-it-github-alerts: + specifier: 1.0.1 + version: 1.0.1(markdown-it@14.3.0) markdown-it-sub: specifier: 2.0.0 version: 2.0.0 @@ -2163,6 +2166,11 @@ packages: markdown-it-footnote@4.0.0: resolution: {integrity: sha512-WYJ7urf+khJYl3DqofQpYfEYkZKbmXmwxQV8c8mO/hGIhgZ1wOe7R4HLFNwqx7TjILbnC98fuyeSsin19JdFcQ==} + markdown-it-github-alerts@1.0.1: + resolution: {integrity: sha512-NNATF4QdoGI07hyCitoB2YqJ1YcNVCKT89ut2VtfFY9rkeFCXe/V2lOonKQLpJiq5DjiZZepf97BJx5xOjFIAw==} + peerDependencies: + markdown-it: '>= 13.0.0' + markdown-it-sub@2.0.0: resolution: {integrity: sha512-iCBKgwCkfQBRg2vApy9vx1C1Tu6D8XYo8NvevI3OlwzBRmiMtsJ2sXupBgEA7PPxiDwNni3qIUkhZ6j5wofDUA==} @@ -5568,6 +5576,10 @@ snapshots: markdown-it-footnote@4.0.0: {} + markdown-it-github-alerts@1.0.1(markdown-it@14.3.0): + dependencies: + markdown-it: 14.3.0 + markdown-it-sub@2.0.0: {} markdown-it-sup@2.0.0: {}