srcdev-nuxt-components 9.2.5 → 9.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.json +35 -1
- package/.claude/skills/components/content-docs.md +165 -0
- package/.claude/skills/components/expanding-panel.md +55 -0
- package/.claude/skills/index.md +4 -2
- package/.claude/skills/qa-panel.md +5 -6
- package/.claude/skills/theming-typography-tokens.md +109 -0
- package/.vscode/srcdev-component-content-docs.code-snippets +129 -0
- package/.vscode/srcdev-component-expanding-panel.code-snippets +123 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue +410 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts +53 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts-snapshots/default-chromium-darwin.png +0 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts-snapshots/state-desktop-chromium-darwin.png +0 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts-snapshots/state-mobile-chromium-darwin.png +0 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts-snapshots/state-tablet-chromium-darwin.png +0 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/stories/ContentDocs.stories.ts +172 -0
- package/app/components/01.atoms/content-wrappers/docs-pages/tests/ContentDocs.spec.ts +218 -0
- package/app/components/01.atoms/page-row/PageRow.vue +2 -0
- package/app/components/02.molecules/expandable/expanding-panel/CONSUMER-STYLING.md +103 -0
- package/app/components/02.molecules/expandable/expanding-panel/ExpandingPanel.vue +97 -56
- package/app/components/02.molecules/expandable/expanding-panel/stories/ExpandingPanel.stories.ts +50 -2
- package/app/components/02.molecules/expandable/expanding-panel/tests/ExpandingPanel.spec.ts +79 -2
- package/app/components/02.molecules/expandable/expanding-panel/tests/__snapshots__/ExpandingPanel.spec.ts.snap +25 -4
- package/app/components/02.molecules/pricing-card/tests/PricingCard.spec.ts +2 -1
- package/app/components/05.forms/input-button/InputButtonCore.vue +12 -1
- package/app/components/05.forms/input-button/tests/InputButtonCore.spec.ts +28 -0
- package/app/components/layout-grids/LayoutGridA.vue +59 -59
- package/app/composables/tests/useContainerBreakpoints.spec.ts +91 -0
- package/app/composables/useContainerBreakpoints.ts +71 -0
- package/app/layouts/default.vue +1 -0
- package/app/pages/ui/expanding-panel.vue +266 -129
- package/app/pages/ui/layout-content-docs.vue +72 -0
- package/app/pages/ui/layout-grid-a.vue +5 -58
- package/app/types/components/content-docs.d.ts +5 -0
- package/app/types/components/index.ts +1 -0
- package/package.json +1 -1
package/.claude/settings.json
CHANGED
|
@@ -59,7 +59,41 @@
|
|
|
59
59
|
"Bash(node -e \"JSON.parse\\(require\\('fs'\\).readFileSync\\('/Users/simoncornforth/websites/nuxt-components/.vscode/srcdev-component-services-section.code-snippets','utf8'\\)\\); console.log\\('valid json'\\)\")",
|
|
60
60
|
"WebFetch(domain:luxury-locs-by-natasha-nuxt3.vercel.app)",
|
|
61
61
|
"Bash(cd /Users/simoncornforth/websites/nuxt-components *)",
|
|
62
|
-
"Bash(node -e \"JSON.parse\\(require\\('fs'\\).readFileSync\\('/Users/simoncornforth/websites/nuxt-components/.vscode/srcdev-component-banner-video.code-snippets','utf8'\\)\\); console.log\\('valid json'\\)\")"
|
|
62
|
+
"Bash(node -e \"JSON.parse\\(require\\('fs'\\).readFileSync\\('/Users/simoncornforth/websites/nuxt-components/.vscode/srcdev-component-banner-video.code-snippets','utf8'\\)\\); console.log\\('valid json'\\)\")",
|
|
63
|
+
"Bash(python3 -c \"import json; json.load\\(open\\('/Users/simoncornforth/websites/nuxt-components/.vscode/srcdev-component-expanding-panel.code-snippets'\\)\\)\")",
|
|
64
|
+
"Bash(node -e \"JSON.parse\\(require\\('fs'\\).readFileSync\\('/Users/simoncornforth/websites/nuxt-components/.vscode/srcdev-component-expanding-panel.code-snippets','utf8'\\)\\); console.log\\('OK'\\)\")",
|
|
65
|
+
"Bash(npx eslint *)",
|
|
66
|
+
"Bash(git stash *)",
|
|
67
|
+
"Bash(rm /Users/simoncornforth/websites/nuxt-components/app/components/02.molecules/expandable/expanding-panel/tests/repro.spec.ts)",
|
|
68
|
+
"Bash(npx playwright *)",
|
|
69
|
+
"Bash(break)",
|
|
70
|
+
"Bash(cp /tmp/pw-test.mjs /Users/simoncornforth/websites/nuxt-components/pw-test.mjs)",
|
|
71
|
+
"Bash(node pw-test.mjs)",
|
|
72
|
+
"Bash(ls ~/Library/Caches/ms-playwright 2>/dev/null)",
|
|
73
|
+
"Read(//Users/simoncornforth/Library/Caches/ms-playwright/**)",
|
|
74
|
+
"Bash(lsof -nP -iTCP:3000 -sTCP:LISTEN)",
|
|
75
|
+
"Bash(ps -p 3241 -o pid,etime,command)",
|
|
76
|
+
"Bash(pkill -f \"nuxt dev\" -u simoncornforth)",
|
|
77
|
+
"Bash(lsof -nP -iTCP:3000,3001 -sTCP:LISTEN)",
|
|
78
|
+
"Bash(curl -s http://localhost:3000/ui/layout-grid-a -o /tmp/a.html -w \"%{http_code}\\\\n\")",
|
|
79
|
+
"Bash(curl -s http://localhost:3000/ui/layout-grid-b -o /tmp/b.html -w \"%{http_code}\\\\n\")",
|
|
80
|
+
"Bash(grep -o \"desktopCanvas[^,{]*{[^}]*}\" /tmp/a.html)",
|
|
81
|
+
"Bash(grep -o \"desktopCanvas[^,{]*{[^}]*}\" /tmp/b.html)",
|
|
82
|
+
"Bash(curl -s \"http://localhost:3000/_nuxt/components/canvas-switcher/CanvasSwitcher.vue?vue&type=style&index=0&lang.css\")",
|
|
83
|
+
"Bash(ps -p 9159 -o pid,command)",
|
|
84
|
+
"Bash(curl -s -o /dev/null -w \"%{http_code}\\\\n\" http://localhost:3000/ui/layout-content-docs)",
|
|
85
|
+
"Bash(node /private/tmp/claude-501/-Users-simoncornforth-websites-nuxt-components/3e6d42b1-c0ff-4b71-a082-656f9e15e24c/scratchpad/debug-breakpoints.mjs)",
|
|
86
|
+
"Bash(sed -i '' 's/from \"playwright\"/from \"@playwright\\\\/test\"/' /Users/simoncornforth/websites/nuxt-components/debug-breakpoints.mjs)",
|
|
87
|
+
"Bash(node debug-breakpoints.mjs)",
|
|
88
|
+
"Bash(grep -v \"ERR_PACKAGE_PATH_NOT_EXPORTED\\\\|Resolve plugin\\\\|at exportsNot\\\\|at packageExports\\\\|at resolveExports\\\\|at Module\\\\|at wrapResolve\\\\|at resolveForCJS\\\\|at resolve \\\\|at CompilerOptions\\\\|at Object.createParsed\\\\|code: 'ERR'\\\\|^}$\")",
|
|
89
|
+
"Bash(lsof -i :6006 -sTCP:LISTEN -t)",
|
|
90
|
+
"Bash(curl -s \"http://127.0.0.1:6006/index.json\")",
|
|
91
|
+
"Bash(curl -s \"http://127.0.0.1:6006/iframe.html?id=atoms-content-wrappers-contentdocs--default&viewMode=story\" -o /dev/null -w \"%{http_code}\\\\n\")",
|
|
92
|
+
"Bash(SRCDEV_STANDALONE=true npx playwright test app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts --project=chromium --update-snapshots)",
|
|
93
|
+
"Bash(SRCDEV_STANDALONE=true npx playwright test app/components/01.atoms/content-wrappers/docs-pages/playwright/content-docs.playwright.ts --project=chromium)",
|
|
94
|
+
"Bash(git rm *)",
|
|
95
|
+
"Bash(awk '{print $1}')",
|
|
96
|
+
"Bash(git reset *)"
|
|
63
97
|
],
|
|
64
98
|
"additionalDirectories": [
|
|
65
99
|
"/Users/simoncornforth/websites/instepreflexology",
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# ContentDocs Component
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`ContentDocs` is a docs-page layout shell: a primary nav column, a main content column, and an "on this page" nav column, arranged via CSS `@container` queries (not viewport breakpoints) so the layout adapts to the space actually available — correct even when a consumer page has its own decoration (e.g. a site-wide left nav) eating into the viewport.
|
|
6
|
+
|
|
7
|
+
`docsNav` and `docsPageNav` are **not** slots — they're rendered internally as `ExpandingPanel` accordions driven by `docsNavItems`/`docsPageNavItems` props. Only `docsContent` remains a slot, since it's arbitrary page content. The two side panels auto force-open/collapse based on the component's own measured width via `useContainerBreakpoints`, and share a native `<details name>` accordion group only on mobile (see "Breakpoint behaviour" below).
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Props reference
|
|
12
|
+
|
|
13
|
+
| Prop | Type | Default | Notes |
|
|
14
|
+
|------|------|---------|-------|
|
|
15
|
+
| `tag` | `"div" \| "section" \| "article" \| "main"` | `"div"` | Root element tag. |
|
|
16
|
+
| `docsNavItems` | `DocsNavItem[]` | `[]` | Items rendered in the `docsNav` panel. Panel (and its `.docs-nav` wrapper) is omitted entirely when empty. |
|
|
17
|
+
| `docsPageNavItems` | `DocsNavItem[]` | `[]` | Items rendered in the `docsPageNav` panel. Panel omitted entirely when empty. |
|
|
18
|
+
| `docsNavLabel` | `string` | `"Navigation"` | Heading text for the `docsNav` panel's `#summary`. |
|
|
19
|
+
| `docsPageNavLabel` | `string` | `"On this page"` | Heading text for the `docsPageNav` panel's `#summary`. |
|
|
20
|
+
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root `.content-docs` element. |
|
|
21
|
+
|
|
22
|
+
`DocsNavItem` (from `~/types/components`):
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
interface DocsNavItem {
|
|
26
|
+
label: string;
|
|
27
|
+
to: string;
|
|
28
|
+
icon?: string; // Icon name, e.g. "lucide:rocket"
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Model
|
|
33
|
+
|
|
34
|
+
| Model | Type | Default | Notes |
|
|
35
|
+
|-------|------|---------|-------|
|
|
36
|
+
| `v-model:activeNavItem` | `string \| undefined` | `undefined` | The `to` of the currently-active `docsNav` item. Updates automatically on click; bind externally (e.g. to route matching) to control it. |
|
|
37
|
+
| `v-model:activePageNavItem` | `string \| undefined` | `undefined` | Same, for `docsPageNav`. |
|
|
38
|
+
|
|
39
|
+
Open/expanded state of the two panels is **not** exposed as a model — it's driven entirely by the container-width breakpoint logic (see below), not user-controllable.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Slots
|
|
44
|
+
|
|
45
|
+
| Slot | Purpose |
|
|
46
|
+
|------|---------|
|
|
47
|
+
| `#docsContent` | Main page content. Only slot this component exposes. |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Usage example
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<script setup lang="ts">
|
|
55
|
+
import type { DocsNavItem } from "~/types/components";
|
|
56
|
+
|
|
57
|
+
const docsNavItems: DocsNavItem[] = [
|
|
58
|
+
{ label: "Getting started", to: "/docs", icon: "lucide:rocket" },
|
|
59
|
+
{ label: "Installation", to: "/docs/install" },
|
|
60
|
+
];
|
|
61
|
+
const docsPageNavItems: DocsNavItem[] = [
|
|
62
|
+
{ label: "Overview", to: "/docs#overview" },
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
const activeNavItem = ref<string | undefined>(docsNavItems[0]?.to);
|
|
66
|
+
const activePageNavItem = ref<string | undefined>(undefined);
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<template>
|
|
70
|
+
<ContentDocs
|
|
71
|
+
v-model:active-nav-item="activeNavItem"
|
|
72
|
+
v-model:active-page-nav-item="activePageNavItem"
|
|
73
|
+
:docs-nav-items="docsNavItems"
|
|
74
|
+
:docs-page-nav-items="docsPageNavItems"
|
|
75
|
+
>
|
|
76
|
+
<template #docsContent>
|
|
77
|
+
<h1>Page title</h1>
|
|
78
|
+
<p>Page content.</p>
|
|
79
|
+
</template>
|
|
80
|
+
</ContentDocs>
|
|
81
|
+
</template>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Breakpoint behaviour
|
|
87
|
+
|
|
88
|
+
Widths are measured on the component's own root element (`useContainerBreakpoints`, container-name `contentDocs`), **not** the viewport — this is deliberate, so nested page decoration (nav rails, sidebars) that shrinks the actual available space is correctly accounted for. Thresholds: `tablet: 768px`, `desktop: 1024px`, matching the `@container contentDocs` queries in this component's own `<style>` block. If you change one, change the other.
|
|
89
|
+
|
|
90
|
+
| Width | `docsNav` | `docsPageNav` |
|
|
91
|
+
|-------|-----------|----------------|
|
|
92
|
+
| < 768px (mobile) | collapsible, closed by default | collapsible, closed by default |
|
|
93
|
+
| 768–1023px (tablet) | collapsible, closed by default | **forced open**, no toggle icon |
|
|
94
|
+
| ≥ 1024px (desktop) | **forced open**, no toggle icon | **forced open**, no toggle icon |
|
|
95
|
+
|
|
96
|
+
### Why the two panels share a `name` only on mobile
|
|
97
|
+
|
|
98
|
+
Both panels are `ExpandingPanel`s using the native `<details name="...">` grouping feature, which makes same-named panels mutually exclusive (browser force-closes one when the other opens). That's the wanted behaviour on mobile (accordion — only one open at a time), but at tablet/desktop both panels must be open **simultaneously** — a shared name there would make the browser silently force-close one of them the moment both try to be open. So the component computes distinct names (`"docsNav"` / `"docsPageNav"`) once past mobile, and a shared name (`"docsPanelGroup"`) only while mobile.
|
|
99
|
+
|
|
100
|
+
### Related fix in ExpandingPanel.vue
|
|
101
|
+
|
|
102
|
+
Building this component's forced-open/forced-closed cycling surfaced a real bug in `ExpandingPanel.vue`: `forceOpened` driving the native `open` attribute fires the element's own `toggle` event, which — before the fix — leaked into `isPanelOpen` (the user-click model), leaving the panel permanently "remembered open" even after `forceOpened` reverted to `false`. Fixed by ignoring toggle events while `forceOpened` is `true`. See `expanding-panel.md` and the `ExpandingPanel.spec.ts` regression test ("does not leak forceOpened into isPanelOpen...").
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Icons
|
|
107
|
+
|
|
108
|
+
`DocsNavItem.icon` is optional (any icon name resolvable by `<Icon>`, e.g. Lucide set: `"lucide:rocket"`). Items without an icon still align correctly with icon-bearing items — the link is `display: grid` with a fixed-width icon column (`--docs-nav-link-icon-size`), not `flex`, so an absent icon doesn't collapse the label leftward.
|
|
109
|
+
|
|
110
|
+
To move the icon to the end of the link instead of the start, set `--docs-nav-link-icon-order` (or `--docs-page-nav-link-icon-order`) to `rtl` (default `ltr`). This uses a `direction` flip to mirror which physical side the fixed-width column renders on, rather than swapping `grid-column` values directly — swapping columns would put the label into the icon-sized track and squeeze it. The icon and label content reset `direction: ltr` internally so text/glyphs don't visually mirror.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## CSS Token Customization
|
|
115
|
+
|
|
116
|
+
All `--content-docs-*` tokens can be overridden at global, page, or instance scope. Each has a **shared** version (applies to both `docsNav` and `docsPageNav`) and a **per-side** override (`content-docs-nav-*` / `content-docs-page-nav-*`) that falls back to the shared token if unset.
|
|
117
|
+
|
|
118
|
+
**Heading tokens** (shared: `--content-docs-heading-*`, per-side: `--content-docs-{nav,page-nav}-heading-*`):
|
|
119
|
+
- `-font-size`, `-font-weight`, `-color`, `-bg`, `-margin`, `-padding-block`, `-padding-inline`
|
|
120
|
+
|
|
121
|
+
**Panel tokens** (shared: `--content-docs-panel-*`, per-side: `--content-docs-{nav,page-nav}-panel-bg`):
|
|
122
|
+
- `-bg` (default: `light-dark(var(--slate-00), var(--slate-10))`, the project's standard card-surface token), `-padding-block`, `-padding-inline`, `-border-radius`
|
|
123
|
+
|
|
124
|
+
**Link tokens** (shared: `--content-docs-link-*`, per-side: `--content-docs-{nav,page-nav}-link-*`):
|
|
125
|
+
- `-font-size`, `-padding-block`, `-padding-inline`, `-margin-block`, `-border-radius`, `-color`, `-bg`, `-hover-bg`, `-hover-color`, `-active-bg`, `-active-color`
|
|
126
|
+
|
|
127
|
+
**Column-width tokens** (fixed-width grid tracks at tablet/desktop):
|
|
128
|
+
- `--content-docs-nav-column-width` (default `23rem`, desktop `docsNav` track)
|
|
129
|
+
- `--content-docs-page-nav-column-width` (default `22rem`, desktop `docsPageNav` track)
|
|
130
|
+
- `--content-docs-page-nav-column-width-tablet` (default `20rem`, tablet's single fixed track — `docsNav` is full-width at tablet)
|
|
131
|
+
|
|
132
|
+
**Icon tokens** (not `content-docs-` prefixed — shared with the link, not per-side by default):
|
|
133
|
+
- `--docs-nav-link-icon-gap`, `--docs-nav-link-icon-size`, `--docs-nav-link-icon-order` (`ltr`/`rtl`), `--docs-page-nav-link-icon-order`
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Local style override scaffold
|
|
138
|
+
|
|
139
|
+
```vue
|
|
140
|
+
<ContentDocs :style-class-passthrough="['my-docs']" ...>
|
|
141
|
+
...
|
|
142
|
+
</ContentDocs>
|
|
143
|
+
|
|
144
|
+
<style>
|
|
145
|
+
.content-docs {
|
|
146
|
+
&.my-docs {
|
|
147
|
+
--content-docs-panel-bg: var(--surface-2);
|
|
148
|
+
--content-docs-link-active-bg: var(--brand-01);
|
|
149
|
+
--content-docs-link-active-color: var(--brand-10);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
</style>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Notes
|
|
158
|
+
|
|
159
|
+
- `docsContent` visibility is slot-detected (`useSlots().docsContent`); `docsNav`/`docsPageNav` visibility is item-array-length-detected (`docsNavItems.length > 0`) — different mechanisms, since only `docsContent` is still a real slot.
|
|
160
|
+
- `NuxtLink` resolved via `resolveComponent("NuxtLink")`, not imported from `#components` — required so this component works inside Storybook (see `feedback_no_components_import_storybook`).
|
|
161
|
+
- Auto-imported in Nuxt — no manual import needed.
|
|
162
|
+
- File: `app/components/01.atoms/content-wrappers/docs-pages/ContentDocs.vue`
|
|
163
|
+
- Types: `app/types/components/content-docs.d.ts` (`DocsNavItem`)
|
|
164
|
+
- Tests: `app/components/01.atoms/content-wrappers/docs-pages/tests/ContentDocs.spec.ts`
|
|
165
|
+
- Demo page: `app/pages/ui/layout-content-docs.vue`
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
| `name` | `string` | `useId()` | Identifies the panel. Used in ARIA attributes (`id-{name}-trigger`, `id-{name}-content`). If omitted, a unique id is generated automatically. |
|
|
14
14
|
| `animationDuration` | `number` | `400` | Expand/collapse transition duration in milliseconds. Pass `0` to disable animation. |
|
|
15
15
|
| `forceOpened` | `boolean` | `false` | When `true`, the panel is always open. The toggle icon is hidden and clicks do not close the panel. |
|
|
16
|
+
| `contentIsOnTop` | `boolean` | `false` | When `true`, the content region is taken out of flow and absolutely positioned directly below the summary, raised above surrounding page content via `z-index` — instead of pushing layout down when it opens. Applies a `content-is-on-top` class to the root `.expanding-panel` element (not the content div). |
|
|
16
17
|
| `styleClassPassthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root `.expanding-panel` element. |
|
|
17
18
|
|
|
18
19
|
## Model
|
|
@@ -98,6 +99,29 @@ const isOpen = ref(false);
|
|
|
98
99
|
</ExpandingPanel>
|
|
99
100
|
```
|
|
100
101
|
|
|
102
|
+
### Content on top (overlay instead of pushing layout)
|
|
103
|
+
|
|
104
|
+
```vue
|
|
105
|
+
<ExpandingPanel name="overlay" :content-is-on-top="true" :style-class-passthrough="['my-overlay-panel']">
|
|
106
|
+
<template #summary><span>Open me — content overlays what's below</span></template>
|
|
107
|
+
<template #content>
|
|
108
|
+
<!-- Wrapper INSIDE the slot carries the visual styling — see
|
|
109
|
+
"Styling the content when contentIsOnTop" below for why it can't go on .inner -->
|
|
110
|
+
<div class="my-overlay-panel-body">
|
|
111
|
+
<p>Positioned absolutely below the summary, doesn't push page content down.</p>
|
|
112
|
+
</div>
|
|
113
|
+
</template>
|
|
114
|
+
</ExpandingPanel>
|
|
115
|
+
|
|
116
|
+
<style>
|
|
117
|
+
.my-overlay-panel-body {
|
|
118
|
+
background-color: white;
|
|
119
|
+
padding: 1rem;
|
|
120
|
+
box-shadow: 0 4px 12px rgb(0 0 0 / 15%);
|
|
121
|
+
}
|
|
122
|
+
</style>
|
|
123
|
+
```
|
|
124
|
+
|
|
101
125
|
---
|
|
102
126
|
|
|
103
127
|
## ARIA / accessibility
|
|
@@ -117,6 +141,36 @@ Always supply a meaningful `name` prop when using multiple panels on the same pa
|
|
|
117
141
|
|
|
118
142
|
---
|
|
119
143
|
|
|
144
|
+
## Styling the content when contentIsOnTop
|
|
145
|
+
|
|
146
|
+
When `contentIsOnTop` is `true`, the component deliberately does **not** set `background-color`, `padding`, or a shadow on `.inner` — and consumers must not set them on `.inner` either. Always style a wrapper element placed *inside* the `#content` slot (see example above).
|
|
147
|
+
|
|
148
|
+
Why: `.expanding-panel-content` collapses via `grid-template-rows: 0fr → 1fr`, and `.inner` relies on `overflow: hidden` on its own box to clip its *children* to 0px when collapsed. `overflow: hidden` clips overflow content, but does not shrink the element's own padding/border/background — those are part of `.inner`'s own box model and still render at full size even while the row track is `0fr` and the panel is closed, producing a visible gap under the summary. A wrapper placed inside the slot is a *child* of `.inner`, so its box — including any padding/background/shadow — is correctly clipped to 0px by `.inner`'s `overflow: hidden` while closed. Baking styling into `.inner` itself would require also gating it on the open state (e.g. `.expanding-panel-details[open] ~ .expanding-panel-content .inner`), which is unnecessary complexity — styling the slot content is the correct fix, not a workaround.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## Constraint: don't stack contentIsOnTop panels as direct siblings
|
|
153
|
+
|
|
154
|
+
`contentIsOnTop` takes the content out of document flow (`position: absolute`) specifically so opening the panel does **not** push whatever comes after it down the page — that's the entire point of the prop. The tradeoff: the panel's own container still only occupies the height of its `<summary>` row, so a *sibling* element positioned directly after it in the DOM sits exactly where the overlay renders. When that sibling is another `ExpandingPanel`, opening the first one visually covers the second one's summary — this happens whether or not the two are grouped via a shared `name` (linked accordion) or opened simultaneously; it isn't specific to linking.
|
|
155
|
+
|
|
156
|
+
`contentIsOnTop` is designed for a **single** panel overlaying unrelated trailing page content (e.g. a promo banner, a footer strip) — not for stacking multiple `contentIsOnTop` panels beside each other expecting normal accordion behaviour. If you need several linked/stacked panels, leave `contentIsOnTop` off (the default, in-flow layout handles that case correctly).
|
|
157
|
+
|
|
158
|
+
---
|
|
159
|
+
|
|
160
|
+
## CSS Token Customization
|
|
161
|
+
|
|
162
|
+
All `--expanding-panel-*` tokens can be overridden at global, page, or instance scope. See `CONSUMER-STYLING.md` in the component directory for full token documentation and examples.
|
|
163
|
+
|
|
164
|
+
**Tokens:**
|
|
165
|
+
|
|
166
|
+
- `--expanding-panel-summary-gap` — gap between summary label and icon
|
|
167
|
+
- `--expanding-panel-summary-padding-block` — summary row vertical padding
|
|
168
|
+
- `--expanding-panel-icon-size` — toggle icon size
|
|
169
|
+
- `--expanding-panel-content-z-index` — stacking order when `contentIsOnTop` is `true`
|
|
170
|
+
- `--expanding-panel-content-gap` — space between summary and content when `contentIsOnTop` is `true`
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
120
174
|
## Local style override scaffold
|
|
121
175
|
|
|
122
176
|
When consuming this component, scaffold a style block using `styleClassPassthrough`. Delete the block if unused.
|
|
@@ -150,6 +204,7 @@ See [component-local-style-override.md](../component-local-style-override.md) fo
|
|
|
150
204
|
## Notes
|
|
151
205
|
|
|
152
206
|
- The open/close animation uses `grid-template-rows: 0fr → 1fr` — no JS height measurement needed.
|
|
207
|
+
- `content-is-on-top` is applied to the root `.expanding-panel` element, not `.expanding-panel-content` — style overrides must scope through it, e.g. `.expanding-panel.my-panel .expanding-panel-content .inner { ... }`.
|
|
153
208
|
- When `forceOpened` is `true`, `open` stays `true` regardless of `v-model`, but `v-model` still updates internally on clicks (useful if you later set `forceOpened` back to `false`).
|
|
154
209
|
- Group panels into a native accordion (only one open at a time) by passing the same `name` to multiple panels or use `AccordianCore` which handles this automatically.
|
|
155
210
|
- Auto-imported in Nuxt — no manual import needed.
|
package/.claude/skills/index.md
CHANGED
|
@@ -28,6 +28,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
28
28
|
├── testing-add-playwright.md — create a Playwright visual regression test
|
|
29
29
|
├── setup-postinstall.md — automate nuxt prepare + Claude skills copy via postinstall so neither is forgotten after npm install
|
|
30
30
|
├── theming-colour-ramps.md — parametric oklch ramp system: formula, named palettes, semantic slots, generator, consumer setup
|
|
31
|
+
├── theming-typography-tokens.md — --step-N fluid font-size scale, 62.5% root reset gotcha (1rem=10px, not 16px), page-heading-*/page-body-* utility classes
|
|
31
32
|
├── theming-override-default.md — replace the entire default theme with a custom palette (set --theme-hue/--theme-chroma)
|
|
32
33
|
├── theming-partial-override.md — override a specific token category (palette, buttons, inputs) without a full theme replacement
|
|
33
34
|
├── colour-scheme-disable.md — disable light/dark scheme support in a consumer app
|
|
@@ -45,7 +46,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
45
46
|
├── vercel-node-version.md — .nvmrc pinned to Node 24 is required; without it Vercel uses npm 10 which crashes on versionless optional stubs
|
|
46
47
|
├── robots-env-aware.md — @nuxtjs/robots: allow crawling on prod domain only, block on preview/staging via env var
|
|
47
48
|
├── new-app-scaffold.md — scaffold a new Nuxt consumer app extending this layer (package.json, nuxt.config, app structure, CLAUDE.md)
|
|
48
|
-
├── qa-panel.md — collapsible
|
|
49
|
+
├── qa-panel.md — collapsible panel for toggling component props live on a page (always on for /pages/ui/ demo pages; gate with isDev in consuming apps)
|
|
49
50
|
├── release-notes.md — produce release notes as a fenced markdown block from git log
|
|
50
51
|
├── pull-request-description.md — produce a PR description as a fenced markdown block from git diff vs main
|
|
51
52
|
├── using-component-skills.md — discover and use component skills in consumer apps: where skills land, browsing patterns, workflow for deciding build vs. compose
|
|
@@ -71,7 +72,8 @@ Each skill is a single markdown file named `<area>-<task>.md`.
|
|
|
71
72
|
├── services-section.md — ServicesSection props (incl. heading/CTA copy), summary-link/cta/cta-panel slots, summary vs full mode
|
|
72
73
|
├── contact-section.md — ContactSection props (stepperIndicatorSize pass-through), 3-item info+form layout, slot API
|
|
73
74
|
├── stepper-list.md — StepperList dynamic slots (item-{n}/indicator-{n}), props, connector behaviour
|
|
74
|
-
├── expanding-panel.md — ExpandingPanel v-model, forceOpened, slots (summary/icon/content), ARIA wiring
|
|
75
|
+
├── expanding-panel.md — ExpandingPanel v-model, forceOpened, contentIsOnTop overlay mode, slots (summary/icon/content), ARIA wiring, CSS token API
|
|
76
|
+
├── content-docs.md — ContentDocs docs-page shell: prop-driven docsNav/docsPageNav (not slots), DocsNavItem icons, container-width breakpoint behaviour, shared/per-side CSS token API
|
|
75
77
|
├── glass-panel.md — GlassPanel props, slots, CSS token API (--glass-panel-bg/border-color/shadow/highlight), theming override
|
|
76
78
|
├── navigation-horizontal.md — NavigationHorizontal props, NavItemData type, CSS token API, import path gotcha
|
|
77
79
|
├── pricing-card.md — PricingCard: SaaS-style plan card with highlight, feature list, #cta slot for button customization, CSS token API
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
4
|
|
|
5
|
-
A collapsible
|
|
5
|
+
A collapsible panel that lets you toggle component props live on a page — without touching the component or breaking the visual layout. Uses a native `<details>`/`<summary>` so it takes up no space when collapsed. Every page under `app/pages/ui/` in this library is a demo-only page already, so the panel always renders there — no `isDev` gate needed. If you add one to a page in a consuming app that also serves real production traffic, gate it behind that app's own dev/staging check.
|
|
6
6
|
|
|
7
7
|
## Structure
|
|
8
8
|
|
|
@@ -19,8 +19,7 @@ Each group controls one prop. The status `<code>` in the summary mirrors the cur
|
|
|
19
19
|
### 1. Add the reactive state to `<script setup>`
|
|
20
20
|
|
|
21
21
|
```ts
|
|
22
|
-
// ── QA controls
|
|
23
|
-
const isDev = import.meta.dev;
|
|
22
|
+
// ── QA controls ────────────────────────────────────────────────────
|
|
24
23
|
|
|
25
24
|
// One ref per controllable prop
|
|
26
25
|
const qaMyBoolean = ref(true);
|
|
@@ -47,8 +46,8 @@ const myStringPresets = ["a", "b", "c"] as const;
|
|
|
47
46
|
Place directly above (or below) the component being QA'd, outside any layout wrapper that clips content:
|
|
48
47
|
|
|
49
48
|
```vue
|
|
50
|
-
<!-- ── QA Panel
|
|
51
|
-
<div
|
|
49
|
+
<!-- ── QA Panel ─────────────────────────────────────────────── -->
|
|
50
|
+
<div class="qa-panel">
|
|
52
51
|
<details class="qa-panel__details">
|
|
53
52
|
<summary class="qa-panel__summary">
|
|
54
53
|
<span class="qa-panel__title">QA — MyComponent</span>
|
|
@@ -219,7 +218,7 @@ Scope inside your page body class (e.g. `.my-page`) so styles don't bleed. The p
|
|
|
219
218
|
|
|
220
219
|
## Notes
|
|
221
220
|
|
|
222
|
-
- **
|
|
221
|
+
- **Consuming apps on real production traffic**: if the page hosting the panel isn't demo-only (unlike everything under `app/pages/ui/` in this library), gate the panel with that app's own dev/staging check, e.g. `v-if="isDev"` with `const isDev = import.meta.dev;`. `import.meta.dev` is `false` in production builds, so the gated block is tree-shaken with no runtime cost.
|
|
223
222
|
- **Consuming apps**: The active chip color (`oklch(55% 0.18 240)`) is a neutral blue. Replace with a brand accent token if preferred: `background: var(--color-brand-accent)`.
|
|
224
223
|
- **Panel placement**: Outside any `overflow: hidden` or clipping container, otherwise the panel may be clipped or push layout unexpectedly. Placing it as a direct sibling of the component row works well.
|
|
225
224
|
- **Computed CSS vars**: When a prop controls a CSS custom property (e.g. max-height tiers), use a `computed` that returns a style object and bind it with `:style` on the component wrapper:
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Typography Tokens
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
`html { font-size: 62.5%; }` is set globally by this layer (`setup/01.config/_head.css`), which
|
|
6
|
+
redefines `1rem` to `10px` instead of the browser default `16px`. Every font-size in this design
|
|
7
|
+
system is calibrated against that 10px root, via the fluid `--step-N` custom properties and the
|
|
8
|
+
`page-heading-*`/`page-body-*` utility classes built on top of them — never a raw `rem` literal.
|
|
9
|
+
|
|
10
|
+
**The trap**: a raw value like `font-size: 0.85rem` looks like a reasonable ~13.6px in a normal
|
|
11
|
+
16px-root project. In a consumer of this layer it renders at 8.5px — because `1rem` here is `10px`,
|
|
12
|
+
not `16px`. This silently produces illegibly small text with no error or warning; it only shows up
|
|
13
|
+
visually. Always use `var(--step-N)` (or a `page-heading-*`/`page-body-*` utility class) instead of
|
|
14
|
+
a raw `rem`/`px` font-size when writing new component or page-local CSS in a consumer app.
|
|
15
|
+
|
|
16
|
+
## The token scale
|
|
17
|
+
|
|
18
|
+
Defined in `setup/05.typography/01.tokens/_reponsive-font-sizes.css`, on `:where(html)`. Each step
|
|
19
|
+
is a fluid `clamp()` — smallest at narrow viewports, largest at wide ones:
|
|
20
|
+
|
|
21
|
+
| Token | Approx. range (px, at 10px root) |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `--step-1` | ~7.8–8 |
|
|
24
|
+
| `--step-2` | ~9.4–10 |
|
|
25
|
+
| `--step-3` | ~11.25–12.5 |
|
|
26
|
+
| `--step-4` | ~13.5–15.6 (body default) |
|
|
27
|
+
| `--step-5` | ~16.2–19.5 |
|
|
28
|
+
| `--step-6` | ~19.4–24.4 |
|
|
29
|
+
| `--step-7` | ~23.3–30.5 |
|
|
30
|
+
| `--step-8` | ~28–38.1 |
|
|
31
|
+
| `--step-9` | ~33.6–47.7 |
|
|
32
|
+
| `--step-10` | ~40.3–59.6 |
|
|
33
|
+
|
|
34
|
+
Plus purpose-specific tokens for hero/eyebrow text: `--hero-text-display`, `--hero-text-title`,
|
|
35
|
+
`--hero-text-heading`, `--hero-text-subheading`, `--hero-text-label`, `--eyebrow-text-large`,
|
|
36
|
+
`--eyebrow-text-medium`, `--eyebrow-text-small`.
|
|
37
|
+
|
|
38
|
+
`body` itself is set to `font-size: var(--step-4)` (`setup/01.config/_head.css`), so plain `<p>`/`<li>`
|
|
39
|
+
text inherits the correct scaled size automatically — you only need to reach for a token explicitly
|
|
40
|
+
when setting a font-size on something other than ambient body text (labels, nav links, table cells,
|
|
41
|
+
code blocks, etc.).
|
|
42
|
+
|
|
43
|
+
## Utility classes built on the scale
|
|
44
|
+
|
|
45
|
+
`setup/05.typography/02.utility-classes/_font-classes-page-heading.css` and
|
|
46
|
+
`_font-classes-page-body.css` map the steps to semantic classes:
|
|
47
|
+
|
|
48
|
+
| Class | Token |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `.page-heading-1` | `--step-8` |
|
|
51
|
+
| `.page-heading-2` | `--step-7` |
|
|
52
|
+
| `.page-heading-3` | `--step-6` |
|
|
53
|
+
| `.page-heading-4` | `--step-5` |
|
|
54
|
+
| `.page-heading-5` | `--step-4` |
|
|
55
|
+
| `.page-heading-6` | `--step-3` |
|
|
56
|
+
| `.page-body-large` | `--step-6` |
|
|
57
|
+
| `.page-body-medium` | `--step-5` |
|
|
58
|
+
| `.page-body-normal` | `--step-4` |
|
|
59
|
+
| `.page-body-small` | `--step-3` |
|
|
60
|
+
| `.page-body-xsmall` | `--step-2` |
|
|
61
|
+
|
|
62
|
+
`page-body-*` also has `-light`/`-semibold`/`-bold` weight variants (e.g. `.page-body-normal-bold`).
|
|
63
|
+
|
|
64
|
+
## Steps
|
|
65
|
+
|
|
66
|
+
### 1. Prefer the utility classes for standalone text
|
|
67
|
+
|
|
68
|
+
If a heading or paragraph in your markup can just be a plain element with one of these classes,
|
|
69
|
+
use the class rather than writing new CSS:
|
|
70
|
+
|
|
71
|
+
```vue
|
|
72
|
+
<h1 class="page-heading-1">Dashboard</h1>
|
|
73
|
+
<p class="page-body-normal">Overview of your account activity.</p>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### 2. Use `var(--step-N)` inside component-scoped CSS
|
|
77
|
+
|
|
78
|
+
For font-sizes inside a component's own `<style>` block (sidebar labels, table text, code blocks,
|
|
79
|
+
badges, etc.), reference the token directly rather than a class:
|
|
80
|
+
|
|
81
|
+
```css
|
|
82
|
+
.my-component__label {
|
|
83
|
+
font-size: var(--step-4);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Don't go below `--step-4` for anything a user is expected to actually read (nav links, table
|
|
88
|
+
cells, code, captions) — `--step-2`/`--step-3` look reasonable in isolation but read as too small
|
|
89
|
+
once placed in real dense UI (sidebars, TOCs, code blocks) next to normal body text. Reserve
|
|
90
|
+
`--step-1`–`--step-3` for genuinely decorative/secondary marks (eyebrow labels, badge counters)
|
|
91
|
+
where legibility isn't the point.
|
|
92
|
+
|
|
93
|
+
### 3. Pick a step by relative scale, not by trying to hit a literal px target
|
|
94
|
+
|
|
95
|
+
Since every step is fluid (`clamp()`), don't reason about "I want 12px" — reason about it relative
|
|
96
|
+
to body text (`--step-4`): one step down (`--step-3`) for slightly smaller text (small labels, table
|
|
97
|
+
cells), two steps down (`--step-2`) for compact caption/label text (sidebar nav group titles, tab
|
|
98
|
+
labels), and so on upward for headings.
|
|
99
|
+
|
|
100
|
+
## Notes
|
|
101
|
+
|
|
102
|
+
- This applies to *any* consumer app extending this layer, not just components inside this repo —
|
|
103
|
+
a local/custom component written in a consuming app (e.g. a docs page's own sidebar/TOC component)
|
|
104
|
+
needs the same `var(--step-N)` treatment, since it inherits the same `62.5%` root reset via the
|
|
105
|
+
layer's global CSS.
|
|
106
|
+
- Caught in the wild: a docs-page sidebar/TOC/code-block set of components in a consumer app
|
|
107
|
+
(`guidemyhair`) shipped with raw `0.75rem`/`0.85rem`/`0.9rem` font-sizes, assuming a 16px root —
|
|
108
|
+
rendered far too small once the layer's `62.5%` reset applied. Fixed by switching every one to the
|
|
109
|
+
matching `--step-N` token.
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
{
|
|
2
|
+
"SRCDEV ContentDocs Basic": {
|
|
3
|
+
"description": "ContentDocs with nav + on-this-page items and active-item v-models",
|
|
4
|
+
"scope": "vue,html",
|
|
5
|
+
"body": [
|
|
6
|
+
"<ContentDocs",
|
|
7
|
+
" v-model:active-nav-item=\"$1activeNavItem\"",
|
|
8
|
+
" v-model:active-page-nav-item=\"$2activePageNavItem\"",
|
|
9
|
+
" :docs-nav-items=\"$3docsNavItems\"",
|
|
10
|
+
" :docs-page-nav-items=\"$4docsPageNavItems\"",
|
|
11
|
+
">",
|
|
12
|
+
" <template #docsContent>",
|
|
13
|
+
" <p>$5Page content goes here.</p>",
|
|
14
|
+
" </template>",
|
|
15
|
+
"</ContentDocs>"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"SRCDEV ContentDocs Custom Labels" : {
|
|
19
|
+
"description": "ContentDocs with custom docsNav / docsPageNav panel headings",
|
|
20
|
+
"scope": "vue,html",
|
|
21
|
+
"body": [
|
|
22
|
+
"<ContentDocs",
|
|
23
|
+
" v-model:active-nav-item=\"$1activeNavItem\"",
|
|
24
|
+
" v-model:active-page-nav-item=\"$2activePageNavItem\"",
|
|
25
|
+
" :docs-nav-items=\"$3docsNavItems\"",
|
|
26
|
+
" :docs-page-nav-items=\"$4docsPageNavItems\"",
|
|
27
|
+
" docs-nav-label=\"$5Sections\"",
|
|
28
|
+
" docs-page-nav-label=\"$6Contents\"",
|
|
29
|
+
">",
|
|
30
|
+
" <template #docsContent>",
|
|
31
|
+
" <p>$7Page content goes here.</p>",
|
|
32
|
+
" </template>",
|
|
33
|
+
"</ContentDocs>"
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"SRCDEV ContentDocs Items Script": {
|
|
37
|
+
"description": "docsNavItems / docsPageNavItems + active-item refs for ContentDocs",
|
|
38
|
+
"scope": "typescript,vue",
|
|
39
|
+
"body": [
|
|
40
|
+
"const docsNavItems: DocsNavItem[] = [",
|
|
41
|
+
" { label: \"$1Getting started\", to: \"$2/docs\" },",
|
|
42
|
+
"];",
|
|
43
|
+
"",
|
|
44
|
+
"const docsPageNavItems: DocsNavItem[] = [",
|
|
45
|
+
" { label: \"$3Overview\", to: \"$2/docs#overview\" },",
|
|
46
|
+
"];",
|
|
47
|
+
"",
|
|
48
|
+
"const activeNavItem = ref<string | undefined>(docsNavItems[0]?.to);",
|
|
49
|
+
"const activePageNavItem = ref<string | undefined>(undefined);"
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
"SRCDEV ContentDocs Items With Icons Script": {
|
|
53
|
+
"description": "docsNavItems / docsPageNavItems with per-item icons for ContentDocs",
|
|
54
|
+
"scope": "typescript,vue",
|
|
55
|
+
"body": [
|
|
56
|
+
"const docsNavItems: DocsNavItem[] = [",
|
|
57
|
+
" { label: \"$1Getting started\", to: \"$2/docs\", icon: \"$3lucide:rocket\" },",
|
|
58
|
+
"];",
|
|
59
|
+
"",
|
|
60
|
+
"const docsPageNavItems: DocsNavItem[] = [",
|
|
61
|
+
" { label: \"$4Overview\", to: \"$2/docs#overview\", icon: \"$5lucide:list\" },",
|
|
62
|
+
"];",
|
|
63
|
+
"",
|
|
64
|
+
"const activeNavItem = ref<string | undefined>(docsNavItems[0]?.to);",
|
|
65
|
+
"const activePageNavItem = ref<string | undefined>(undefined);"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"SRCDEV ContentDocs CSS Override — Icons": {
|
|
69
|
+
"description": "CSS override scaffold for ContentDocs nav-link icon tokens (gap, size, and start/end order)",
|
|
70
|
+
"scope": "css",
|
|
71
|
+
"body": [
|
|
72
|
+
".$1my-content-docs {",
|
|
73
|
+
" .content-docs {",
|
|
74
|
+
" --docs-nav-link-icon-gap: $2;",
|
|
75
|
+
" --docs-nav-link-icon-size: $3;",
|
|
76
|
+
" --docs-nav-link-icon-order: $4rtl; /* icon at the end */",
|
|
77
|
+
" --docs-page-nav-link-icon-order: $5ltr; /* icon at the start (default) */",
|
|
78
|
+
" }",
|
|
79
|
+
"}"
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
"SRCDEV ContentDocs CSS Override — Shared Theme": {
|
|
83
|
+
"description": "CSS override scaffold for ContentDocs heading/panel/link tokens, applied to both docsNav and docsPageNav at once",
|
|
84
|
+
"scope": "css",
|
|
85
|
+
"body": [
|
|
86
|
+
".$1my-content-docs {",
|
|
87
|
+
" .content-docs {",
|
|
88
|
+
" --content-docs-heading-font-size: $2;",
|
|
89
|
+
" --content-docs-heading-color: $3;",
|
|
90
|
+
" --content-docs-heading-bg: $4;",
|
|
91
|
+
" --content-docs-heading-padding-block: $5;",
|
|
92
|
+
"",
|
|
93
|
+
" --content-docs-panel-bg: $6;",
|
|
94
|
+
" --content-docs-panel-padding-block: $7;",
|
|
95
|
+
" --content-docs-panel-padding-inline: $8;",
|
|
96
|
+
"",
|
|
97
|
+
" --content-docs-link-font-size: $9;",
|
|
98
|
+
" --content-docs-link-color: $10;",
|
|
99
|
+
" --content-docs-link-hover-bg: $11;",
|
|
100
|
+
" --content-docs-link-active-bg: $12;",
|
|
101
|
+
" --content-docs-link-active-color: $13;",
|
|
102
|
+
"",
|
|
103
|
+
" --content-docs-nav-column-width: $14;",
|
|
104
|
+
" --content-docs-page-nav-column-width: $15;",
|
|
105
|
+
" --content-docs-page-nav-column-width-tablet: $16;",
|
|
106
|
+
" }",
|
|
107
|
+
"}"
|
|
108
|
+
]
|
|
109
|
+
},
|
|
110
|
+
"SRCDEV ContentDocs CSS Override — Per Side": {
|
|
111
|
+
"description": "CSS override scaffold for independently theming docsNav vs docsPageNav heading/panel/link tokens",
|
|
112
|
+
"scope": "css",
|
|
113
|
+
"body": [
|
|
114
|
+
".$1my-content-docs {",
|
|
115
|
+
" .content-docs {",
|
|
116
|
+
" /* docsNav (primary) */",
|
|
117
|
+
" --content-docs-nav-heading-color: $2;",
|
|
118
|
+
" --content-docs-nav-panel-bg: $3;",
|
|
119
|
+
" --content-docs-nav-link-active-bg: $4;",
|
|
120
|
+
"",
|
|
121
|
+
" /* docsPageNav (on-this-page / secondary) */",
|
|
122
|
+
" --content-docs-page-nav-heading-color: $5;",
|
|
123
|
+
" --content-docs-page-nav-panel-bg: $6;",
|
|
124
|
+
" --content-docs-page-nav-link-active-bg: $7;",
|
|
125
|
+
" }",
|
|
126
|
+
"}"
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
}
|