diff --git a/README.md b/README.md index 4750c6a..4e5c150 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ A diagram renderer, which draws flowcharts and diagrams from a plain-text descri ### Essentials / Advanced toggle -A two-option switch, provided by the [mkdocs-audience-toggle](#mkdocs-audience-toggle) plugin (configured under `plugins:` in `mkdocs.yml`), that lets a reader hide everything beyond a first-pass beginner curriculum. Content is opted into hiding by marking it `data-fcm-hide="essentials"`: +A two-option switch, provided by the [mkdocs-audience-toggle](#mkdocs-audience-toggle) plugin (configured under `plugins:` in `mkdocs.yml`), that lets a reader hide everything beyond a first-pass beginner curriculum. Content is opted into hiding by marking it `data-audience-hide="essentials"`: - On a `##`/`###` heading inside a content page (e.g. functions.md's `## Decorators`), it hides that heading plus every sibling up to the next heading of the same or higher level, and removes the matching entry from the `toc.integrate` sidebar — so there's no dead nav link to something that's hidden. - On a homepage card-grid row, it hides just that row. A whole homepage card hides too, once its first paragraph (the only one attr_list can attach the marker to) carries the marker — extra.css has a small `:has()` rule that extends that into hiding the entire `
  • `, since the plugin itself only hides the exact element marked. @@ -177,10 +177,10 @@ plugins: ``` ```markdown -## Decorators {: data-fcm-hide="essentials" } +## Decorators {: data-audience-hide="essentials" } ``` -Material has no built-in way to tailor a page to different readers. The plugin hides a marked heading together with its whole section and its table of contents entry. It switches to the nearest mode that shows the content when a link points to something hidden. It also collapses to icons or moves to its own row on narrow screens. It includes its own Playwright and axe-core tests. See the [plugin's README](https://github.com/luka-sherman/mkdocs-audience-toggle) for all options. This site's setup is under `audience_toggle` in `mkdocs.yml`, with color overrides in `extra.css`'s `#fcm-toggle` rule. +Material has no built-in way to tailor a page to different readers. The plugin hides a marked heading together with its whole section and its table of contents entry. It switches to the nearest mode that shows the content when a link points to something hidden. It also collapses to icons or moves to its own row on narrow screens. It includes its own Playwright and axe-core tests. See the [plugin's README](https://github.com/luka-sherman/mkdocs-audience-toggle) for all options. This site's setup is under `audience_toggle` in `mkdocs.yml`, with color overrides in `extra.css`'s `#audience-toggle` rule. ### [mkdocs-cheatsheet](https://pypi.org/project/mkdocs-cheatsheet/) @@ -205,6 +205,21 @@ plugins: A section with its own cheatsheet page, like Libraries here, shows up on the homepage as title-and-description cards only. The optional header button replaces the logo with a "Cheatsheet" link home. It includes its own Playwright and axe-core tests. See the [plugin's README](https://github.com/luka-sherman/mkdocs-cheatsheet) for all options. This site's setup is under `cheatsheet` in `mkdocs.yml`, with the flag rules in STRUCTURE.md's "Cheatsheet flags" section. +### [mkdocs-light-dark-toggle](https://pypi.org/project/mkdocs-light-dark-toggle/) + +An always-visible two-button light/dark switch, replacing Material's native single-knob palette toggle (whose knob is the only clickable spot, and whose current scheme is the only thing you can see). It started as this site's own light/dark JavaScript, and I rewrote it as a published plugin. + +```bash +pip install mkdocs-light-dark-toggle +``` + +```yaml +plugins: + - light_dark_toggle +``` + +Needs zero configuration to work: it ships with built-in sun/moon icons, unlike `mkdocs-audience-toggle` above where mode icons have no universal meaning and must always be supplied. The native palette radios stay in the DOM, hidden — their own JavaScript still applies and persists the scheme via `localStorage`, the plugin only drives them. It includes its own Playwright and axe-core tests. See the [plugin's README](https://github.com/luka-sherman/mkdocs-light-dark-toggle) for all options. This site's setup is under `light_dark_toggle` in `mkdocs.yml`, with color overrides in `extra.css`'s `#light-dark-toggle` rule. + ## Theme ### Custom CSS @@ -327,3 +342,23 @@ The domain is set up via the [docs/CNAME](docs/CNAME) file, which MkDocs copies ## License The content and code in this repo are not licensed for reuse — see [LICENSE](LICENSE). + +## AI usage + +I used [Claude Code](https://claude.com/claude-code) for: + +- Restructuring and rewriting existing content +- Scaffolding first drafts of library pages based off the site's existing [structure](STRUCTURE.md) +- Implementing new features (e.g. the [Essentials/Advanced toggle](#essentials--advanced-toggle)) +- Propagating a content or naming change everywhere it's referenced (headings, anchors, homepage keyword links) +- Diagnosing and fixing test failures (structure, accessibility) instead of just rerunning them +- Verifying a change with `mkdocs build` and `pytest` before calling it done + +How I managed it: + +- Scoped to low-judgment, high-volume work — architecture and correctness stayed manual +- Rewrote drafts in my own words rather than publishing them as-is, so I kept my own mental model of the content I'm teaching from +- Checked output against [STRUCTURE.md](STRUCTURE.md) +- Increased [test coverage](#testing) and [continuous integration](#continuous-integration) to protect its integrity +- Scoped prompts to one task at a time to keep context down +- After one prompt "fixed" content in bulk on its own, I switched to: report gaps, don't auto-fix content on your behalf diff --git a/STRUCTURE.md b/STRUCTURE.md index 1344f3b..6c6f84c 100644 --- a/STRUCTURE.md +++ b/STRUCTURE.md @@ -169,16 +169,16 @@ shows library pages as title-and-description cards only, and their links appear - **Card text.** Each page's front matter sets `cheatsheet_description` (falling back to `description`), plus `cheatsheet_title`, `cheatsheet_icon` or `cheatsheet_title_suffix` (the built-in/third-party badge on library cards) where the defaults don't fit. -- **Essentials mode.** A flagged heading that carries `data-fcm-hide="essentials"` passes it to +- **Essentials mode.** A flagged heading that carries `data-audience-hide="essentials"` passes it to its cheatsheet line or link, so the audience toggle hides both together. A whole card is - hidden with `cheatsheet_attrs: {data-fcm-hide: essentials}` in front matter. + hidden with `cheatsheet_attrs: {data-audience-hide: essentials}` in front matter. - **Verify with a real build.** A renamed heading moves its flag with it, so the cheatsheet can't go stale, but `mkdocs build` still prints a `WARNING` for any broken link elsewhere. - **Marking content "advanced" for the Essentials/Advanced toggle** — the header's segmented control is provided by the `mkdocs-audience-toggle` plugin (configured under `plugins:` in - `mkdocs.yml`) and hides content marked `data-fcm-hide="essentials"`. On a content page, append - `{ data-fcm-hide="essentials" }` to the heading line (e.g. `functions.md`'s - `## Decorators { data-fcm-hide="essentials" }`). This hides that heading, everything up to the + `mkdocs.yml`) and hides content marked `data-audience-hide="essentials"`. On a content page, append + `{ data-audience-hide="essentials" }` to the heading line (e.g. `functions.md`'s + `## Decorators { data-audience-hide="essentials" }`). This hides that heading, everything up to the next heading of the same or higher level, and its sidebar entry. The cheatsheet picks the marker up from the heading, so there's no second place to tag. Which spots to mark, and what counts as advanced/niche vs. core, is a per-editor judgment call @@ -211,7 +211,7 @@ Pick the existing type that matches the branch, don't invent new ones without a | `??? info` | Defining a term/concept adjacent to the page but not the topic itself. | | `??? failure` | The negative counterpart to a `success` branch — "this didn't work, here's what to do about it" (e.g. workspace.md's "download Python here" branch when `python --version` doesn't show 3.x.x). | | `??? ai` | Opinion/meta content specifically about learning with or around AI (e.g. index.md's FAQ tabs on whether/how to use AI while learning) — not used for teaching content about Python itself. | -| `??? efficiency` | A runtime/space aside naming the cost behind a choice already shown in prose (e.g. list vs. set membership, `sort()` vs. `sorted()`) — usually a Big O difference, occasionally a constant-factor one (`.get()` vs. two hash lookups, vectorized NumPy vs. a Python loop) where it's still worth flagging but doesn't change the O(...) class. Wrap it in `
    ` on a page that participates in the Essentials/Advanced toggle (skip it on a page that doesn't, like the library reference pages), and close with a link to [style.md's "Efficiency"](docs/practices/style.md#efficiency) section. Formalizes a tradeoff the surrounding prose already states in plain language; doesn't introduce the tradeoff for the first time. | +| `??? efficiency` | A runtime/space aside naming the cost behind a choice already shown in prose (e.g. list vs. set membership, `sort()` vs. `sorted()`) — usually a Big O difference, occasionally a constant-factor one (`.get()` vs. two hash lookups, vectorized NumPy vs. a Python loop) where it's still worth flagging but doesn't change the O(...) class. Wrap it in `
    ` on a page that participates in the Essentials/Advanced toggle (skip it on a page that doesn't, like the library reference pages), and close with a link to [style.md's "Efficiency"](docs/practices/style.md#efficiency) section. Formalizes a tradeoff the surrounding prose already states in plain language; doesn't introduce the tradeoff for the first time. | | `!!! example` | An always-open side-by-side comparison the reader is meant to see without a click, not a branch — e.g. "how to loop each type," showing every collection type's loop pattern in one visible table. | Default to collapsed (`???`), not always-open (`!!!`) — an always-open admonition competes with diff --git a/docs/javascripts/a11y_patches.js b/docs/javascripts/a11y_patches.js index 8f6862b..104fbe0 100644 --- a/docs/javascripts/a11y_patches.js +++ b/docs/javascripts/a11y_patches.js @@ -11,23 +11,8 @@ }); } - // pymdownx.tasklist (style.md's checklist) renders each `- [ ]` as a real - // wrapped in its own
  • , which the audience toggle hides.""" page.goto(f"{site_url}/?mode=essentials") card_display = page.evaluate( """() => { - const card = document.querySelector('.md-cheatsheet__card[data-fcm-hide~="essentials"]'); + const card = document.querySelector('.md-cheatsheet__card[data-audience-hide~="essentials"]'); return card ? getComputedStyle(card).display : null; }""" ) @@ -122,7 +122,7 @@ def test_whole_homepage_card_hides(page, site_url): def test_link_to_hidden_section_recovers_to_advanced(page, site_url): """collections.md's own cheat-sheet table (near the top) links to #tuples even - while the "Tuples" heading itself is hidden by data-fcm-hide="essentials" — clicking + while the "Tuples" heading itself is hidden by data-audience-hide="essentials" — clicking that visible link should flip the toggle back to Advanced and reveal the section, rather than landing on a hidden target and doing nothing.""" page.goto(f"{site_url}/types/collections/?mode=essentials") @@ -146,9 +146,9 @@ def test_link_to_hidden_section_recovers_to_advanced(page, site_url): after = page.evaluate( """() => ({ tuplesDisplay: getComputedStyle(document.getElementById('tuples')).display, - mode: document.documentElement.getAttribute('data-fcm-mode'), - toggleActive: document.getElementById('fcm-toggle')?.dataset.active, - stored: localStorage.getItem('fcm-mode'), + mode: document.documentElement.getAttribute('data-audience-mode'), + toggleActive: document.getElementById('audience-toggle')?.dataset.active, + stored: localStorage.getItem('audience-mode'), })""" ) assert after["tuplesDisplay"] != "none", "clicking the link should reveal the Tuples section" @@ -172,6 +172,6 @@ def test_link_recovery_ignores_toc_links_to_visible_sections(page, site_url): lists_link.first.click() still_essentials = page.evaluate( - "() => document.documentElement.getAttribute('data-fcm-mode')" + "() => document.documentElement.getAttribute('data-audience-mode')" ) assert still_essentials == "essentials", "a link to an already-visible section should not flip the mode"