steppy-dev 0.3.0__py3-none-any.whl
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.
- steppy/CHANGELOG.md +862 -0
- steppy/__init__.py +9 -0
- steppy/__main__.py +13 -0
- steppy/_cli_common.py +183 -0
- steppy/_docker/Dockerfile.installed +53 -0
- steppy/_parallel/__init__.py +7 -0
- steppy/_parallel/compose.py +349 -0
- steppy/_parallel/event_bus.py +418 -0
- steppy/_parallel/failures.py +267 -0
- steppy/_parallel/fingerprint.py +141 -0
- steppy/_parallel/image.py +380 -0
- steppy/_parallel/lastfailed.py +125 -0
- steppy/_parallel/lifecycle.py +90 -0
- steppy/_parallel/preauth.py +109 -0
- steppy/_parallel/progress.py +101 -0
- steppy/_parallel/queue.py +385 -0
- steppy/_parallel/renderer.py +489 -0
- steppy/_parallel/retry.py +316 -0
- steppy/_player_bundle/THIRD_PARTY_LICENSES.txt +158 -0
- steppy/_player_bundle/__init__.py +100 -0
- steppy/_player_bundle/steppy-cursor-legacy.js +2 -0
- steppy/_player_bundle/steppy-cursor-legacy.js.map +1 -0
- steppy/_player_bundle/steppy-player.js +5419 -0
- steppy/_player_bundle/steppy-player.js.map +1 -0
- steppy/_player_bundle/steppy-video.js +472 -0
- steppy/_player_bundle/steppy-video.js.map +1 -0
- steppy/_templating.py +117 -0
- steppy/assertions.py +251 -0
- steppy/auth.py +493 -0
- steppy/build.py +2798 -0
- steppy/build_models.py +669 -0
- steppy/buildid.py +134 -0
- steppy/bundle/__init__.py +47 -0
- steppy/bundle/archive.py +239 -0
- steppy/bundle/classify.py +329 -0
- steppy/bundle/create.py +490 -0
- steppy/bundle/hashing.py +28 -0
- steppy/bundle/manifest.py +334 -0
- steppy/bundle/results.py +546 -0
- steppy/bundle_cli.py +455 -0
- steppy/captures.py +207 -0
- steppy/cli.py +2489 -0
- steppy/cloud/__init__.py +58 -0
- steppy/cloud/client.py +267 -0
- steppy/cloud/upload.py +497 -0
- steppy/compat.py +109 -0
- steppy/config.py +231 -0
- steppy/config_schema.py +87 -0
- steppy/contracts/__init__.py +54 -0
- steppy/contracts/bundle.py +215 -0
- steppy/contracts/report.py +346 -0
- steppy/contracts/tours.py +505 -0
- steppy/coordinator.py +1352 -0
- steppy/coverage/__init__.py +9 -0
- steppy/coverage/gaps.py +190 -0
- steppy/coverage/manifest.py +193 -0
- steppy/coverage/merge.py +363 -0
- steppy/coverage/normalize.py +174 -0
- steppy/coverage/report.py +178 -0
- steppy/coverage/sourcemap.py +219 -0
- steppy/coverage/store.py +473 -0
- steppy/coverage/triage.py +151 -0
- steppy/coverage_cli.py +265 -0
- steppy/durations.py +48 -0
- steppy/exclusive.py +178 -0
- steppy/flaky_cli.py +169 -0
- steppy/generator.py +633 -0
- steppy/guide.py +1467 -0
- steppy/history.py +352 -0
- steppy/init_cli.py +330 -0
- steppy/locales.py +282 -0
- steppy/migrate/__init__.py +35 -0
- steppy/migrate/apply.py +194 -0
- steppy/migrate/plan.py +199 -0
- steppy/migrate/rules.py +465 -0
- steppy/migrate/verify.py +163 -0
- steppy/migrate_cli.py +152 -0
- steppy/models.py +2539 -0
- steppy/naming.py +37 -0
- steppy/parser.py +475 -0
- steppy/pdf.py +193 -0
- steppy/presets.py +284 -0
- steppy/record_cli.py +796 -0
- steppy/report/__init__.py +37 -0
- steppy/report/assets.py +197 -0
- steppy/report/build.py +261 -0
- steppy/report/coverage_source.py +277 -0
- steppy/report/model.py +423 -0
- steppy/report/render.py +303 -0
- steppy/report/source.py +238 -0
- steppy/report_cli.py +173 -0
- steppy/runmeta.py +114 -0
- steppy/selection.py +183 -0
- steppy/sitemap.py +205 -0
- steppy/skills/steppy-app-tours/SKILL.md +448 -0
- steppy/skills/steppy-ci-report/SKILL.md +567 -0
- steppy/skills/steppy-scenario-author/SKILL.md +2176 -0
- steppy/skills/steppy-template/SKILL.md +676 -0
- steppy/templates/_steppy_events.py +291 -0
- steppy/templates/_steppy_tours.py +404 -0
- steppy/templates/angular/component-interactive.ts.j2 +109 -0
- steppy/templates/angular/component-video.ts.j2 +112 -0
- steppy/templates/angular/component.ts.j2 +229 -0
- steppy/templates/angular/content.ts.j2 +31 -0
- steppy/templates/angular/gitignore.j2 +3 -0
- steppy/templates/angular/group.component.ts.j2 +39 -0
- steppy/templates/angular/onboarding.component.ts.j2 +43 -0
- steppy/templates/angular/routes.ts.j2 +34 -0
- steppy/templates/ci/github-actions.yml +284 -0
- steppy/templates/ci/gitlab-ci.yml +178 -0
- steppy/templates/conftest.py.j2 +2405 -0
- steppy/templates/guide.book.html.j2 +145 -0
- steppy/templates/guide.fragment.html.j2 +257 -0
- steppy/templates/guide.html.j2 +301 -0
- steppy/templates/guide.md.j2 +18 -0
- steppy/templates/init/config.yaml +124 -0
- steppy/templates/init/credentials.yaml.example +30 -0
- steppy/templates/init/scenarios/example--first-flow.md +53 -0
- steppy/templates/report/_head.html.j2 +14 -0
- steppy/templates/report/_mark.html.j2 +3 -0
- steppy/templates/report/coverage.html.j2 +124 -0
- steppy/templates/report/index.html.j2 +203 -0
- steppy/templates/report/report.css +401 -0
- steppy/templates/report/scenario.html.j2 +137 -0
- steppy/templates/static/_headers.j2 +30 -0
- steppy/templates/static/_mode_links.html.j2 +22 -0
- steppy/templates/static/_seo_head.html.j2 +37 -0
- steppy/templates/static/cursor.js.j2 +10 -0
- steppy/templates/static/group.html.j2 +78 -0
- steppy/templates/static/guides.css +678 -0
- steppy/templates/static/index.html.j2 +79 -0
- steppy/templates/static/interactive.html.j2 +100 -0
- steppy/templates/static/onboarding.html.j2 +64 -0
- steppy/templates/static/page.html.j2 +145 -0
- steppy/templates/static/robots.txt.j2 +7 -0
- steppy/templates/static/video.html.j2 +135 -0
- steppy/templates/test_scenario.py.j2 +767 -0
- steppy/testids.py +166 -0
- steppy/totp.py +26 -0
- steppy/tour_spec.py +163 -0
- steppy/tours/__init__.py +22 -0
- steppy/tours/actions.py +402 -0
- steppy/tours/compiler.py +144 -0
- steppy/tours/diagnostics.py +137 -0
- steppy/tours/emit.py +239 -0
- steppy/tours/ids.py +40 -0
- steppy/tours/inference.py +399 -0
- steppy/tours/model.py +120 -0
- steppy/tours/paths.py +126 -0
- steppy/tours/pipeline.py +277 -0
- steppy/tours/publish.py +124 -0
- steppy/tours/replay.py +234 -0
- steppy/tours/routes.py +175 -0
- steppy/tours/settings.py +164 -0
- steppy/tours/text.py +237 -0
- steppy/tours_cli.py +219 -0
- steppy/tts/__init__.py +280 -0
- steppy/tts/cache.py +185 -0
- steppy/tts/presets.py +125 -0
- steppy/tts/providers/__init__.py +6 -0
- steppy/tts/providers/http.py +184 -0
- steppy/tts/providers/local.py +207 -0
- steppy/tts/providers/null.py +28 -0
- steppy/tts/registry.py +201 -0
- steppy/tts/track.py +158 -0
- steppy/tts/types.py +94 -0
- steppy/update_cli.py +460 -0
- steppy/video.py +730 -0
- steppy/video_cache.py +239 -0
- steppy/video_cli.py +271 -0
- steppy/worker.py +301 -0
- steppy_dev-0.3.0.dist-info/METADATA +1335 -0
- steppy_dev-0.3.0.dist-info/RECORD +177 -0
- steppy_dev-0.3.0.dist-info/WHEEL +4 -0
- steppy_dev-0.3.0.dist-info/entry_points.txt +2 -0
- steppy_dev-0.3.0.dist-info/licenses/LICENSE +202 -0
- steppy_dev-0.3.0.dist-info/licenses/NOTICE +13 -0
|
@@ -0,0 +1,676 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: steppy-template
|
|
3
|
+
description: |
|
|
4
|
+
How to STYLE and customize the appearance of Steppy guides — the whole surface, both
|
|
5
|
+
render modes. Use whenever a user wants to change how guides LOOK: "style the guides",
|
|
6
|
+
"brand the guides / match our brand", "change the guide colors / accent / fonts",
|
|
7
|
+
"restyle the step-by-step guide", "customize the static site / navbar / landing page",
|
|
8
|
+
"override a guide template", "theme the interactive player", "use the sidebar layout",
|
|
9
|
+
"set a default template", "hide the cursor in the player", "style the PDF / print layout",
|
|
10
|
+
"brand the handbook", "brand the narrated video", "restyle / brand the run report",
|
|
11
|
+
"theme the in-app tour", "style the tour popover", or edits guide CSS,
|
|
12
|
+
`templates/guide.fragment.html.j2`,
|
|
13
|
+
`templates/static/guides.css`, the `--steppy-*` variables, `<steppy-tour-host>` /
|
|
14
|
+
`::part` rules, or `defaultTemplate` / `cursor` /
|
|
15
|
+
a guide's `template` field in `steppy.guide.config.ts`. Covers: the project `templates/`
|
|
16
|
+
override mechanism, step-by-step (`.steppy-guide`) CSS, the static-site chrome (navbar/index/
|
|
17
|
+
landing pages), the interactive `<steppy-guide>` player templates (overlay/sidebar/inline),
|
|
18
|
+
its cursor modes and `--steppy-*` theme tokens, the in-app tour overlay's
|
|
19
|
+
`--steppy-tour-*` tokens, `::part()` names and chrome strings, the print/PDF + handbook
|
|
20
|
+
layout, and video branding — plus how each maps to the Angular and static build
|
|
21
|
+
targets. For writing the scenario STEPS themselves, see the steppy-scenario-author skill;
|
|
22
|
+
for mounting the tour overlay in the app at all, see steppy-app-tours.
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Styling Steppy guides
|
|
26
|
+
|
|
27
|
+
Steppy renders a guide in up to three modes, and **they are styled by different
|
|
28
|
+
systems** that happen to share the `steppy-` name prefix:
|
|
29
|
+
|
|
30
|
+
| Mode | What it is | Styled by | Isolated? |
|
|
31
|
+
|---|---|---|---|
|
|
32
|
+
| **step-by-step** | A scrollable HTML guide (numbered step cards + animated cursor over screenshots). Default mode. | `.steppy-guide`-scoped CSS in Jinja **templates** you can override. | No — global CSS (`ViewEncapsulation.None` / linked stylesheet). You can target the classes directly. |
|
|
33
|
+
| **interactive** | The Lit `<steppy-guide>` **web component** (a click-through player with overlay/sidebar/inline templates). Opt-in via `modes: ['interactive']`. | `--steppy-*` **CSS custom properties** on the element. | Yes — Shadow DOM. Only custom properties cross the boundary; you cannot target inner classes. |
|
|
34
|
+
| **video** | A narrated MP4 rendered from the interactive manifest. Opt-in via `modes: ['video']` **and** `--video`. | The `video:` block in `config.yaml` (branding, captions, dimensions) — **not CSS**. The page around it is a template. | N/A — it's a baked file. Restyling means re-rendering. |
|
|
35
|
+
| **in-app tour** | The `<steppy-tour-host>` overlay: popovers over **your live app**, compiled from scenarios with `tour:`. Opt-in via `tours.enabled` in `config.yaml`. Not a guide mode — it never appears on a guide page. | `--steppy-tour-*` **CSS custom properties** + `::part()` rules, in the **app's** global stylesheet. | Yes — Shadow DOM, but every visible piece is exposed as a `::part()`. |
|
|
36
|
+
|
|
37
|
+
A guide can use any combination (`modes: ['stepbystep', 'interactive', 'video']`). On top of the
|
|
38
|
+
guide modes there's a **third surface — the site chrome and landing pages** (home/index,
|
|
39
|
+
group landing pages, the onboarding "meta-guide" page, the per-guide onboarding strip, navbar,
|
|
40
|
+
footer). **How that third surface is styled depends entirely on the build target:**
|
|
41
|
+
|
|
42
|
+
- **`target: 'static'`** ships **one stylesheet, `guides.css`, that styles everything** — chrome,
|
|
43
|
+
every landing page, and guide content. Override that one file to rebrand the whole site.
|
|
44
|
+
- **`target: 'angular'` (default) ships NO stylesheet for the chrome/landing pages.** Steppy emits
|
|
45
|
+
the group/onboarding/guide components with bare `.steppy-*` classes (`ViewEncapsulation.None`,
|
|
46
|
+
no `styles:` block), so **your host Angular app owns all of that CSS** — and the home page +
|
|
47
|
+
navbar aren't generated at all (the host renders them from the emitted `nav.json`).
|
|
48
|
+
|
|
49
|
+
Pick the section below for what you're restyling. **Interactive features require steppy ≥ 0.2.0**;
|
|
50
|
+
re-run `steppy build` after upgrading so the new `steppy-player.js` bundle is copied.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## The `templates/` override mechanism (step-by-step + static chrome)
|
|
55
|
+
|
|
56
|
+
Steppy renders guides through Jinja templates resolved by a `ChoiceLoader` that checks your
|
|
57
|
+
**project's `templates/` directory first**, then falls back to the bundled copies inside the
|
|
58
|
+
installed `steppy` package. So you restyle the step-by-step guides and the static site by
|
|
59
|
+
dropping an **overriding copy** of a template into your project root, mirroring its path:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
your-project/
|
|
63
|
+
steppy.guide.config.ts
|
|
64
|
+
templates/ # ← create this; project copies win
|
|
65
|
+
guide.fragment.html.j2 # step-by-step CSS (Angular + standalone)
|
|
66
|
+
static/
|
|
67
|
+
guides.css # static-site stylesheet (chrome + guide content)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
You override **whole files**, not fragments — copy the bundled original as your starting
|
|
71
|
+
point, then edit. Locate the bundled originals to copy from:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
python -c "import steppy, pathlib; print(pathlib.Path(steppy.__file__).parent / 'templates')"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Because you own the full copy, re-diff it against the bundled version after a `steppy`
|
|
78
|
+
upgrade so you don't miss upstream changes. There is exactly **one** tree you edit — your
|
|
79
|
+
project's `templates/`. (`steppy update` reconciles the rest of the Steppy-owned scaffold
|
|
80
|
+
after an upgrade, but it will never touch a template you have overridden; merging upstream
|
|
81
|
+
template changes is manual, by design.)
|
|
82
|
+
|
|
83
|
+
The same rule serves every command — `generate`, `guide`, and `build` all resolve templates
|
|
84
|
+
this way — and it works **per file and per subdirectory**: a project containing only
|
|
85
|
+
`templates/static/guides.css` overrides that one file and inherits every other bundled
|
|
86
|
+
template, with no top-level `*.j2` required.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Step-by-step guide CSS (`.steppy-guide`)
|
|
91
|
+
|
|
92
|
+
The step-by-step guide markup is scoped under `.steppy-guide`. Its style block lives in
|
|
93
|
+
`templates/guide.fragment.html.j2` (Angular target + the standalone `steppy guide` output
|
|
94
|
+
uses `guide.html.j2`). The class surface:
|
|
95
|
+
|
|
96
|
+
- `.steppy-guide` — root (font, max-width, base color)
|
|
97
|
+
- `.steppy-guide h1` + `.steppy-role-badge` — guide title + role pill
|
|
98
|
+
- `.steppy-step`, `.steppy-step h2`, `.steppy-step-number` (the numbered circle),
|
|
99
|
+
`.steppy-step-subtitle`, `.steppy-step-content` — the step card
|
|
100
|
+
- `.steppy-stage`, `.steppy-cursor`, `.steppy-ripple`, `.steppy-kbd` — the screenshot stage +
|
|
101
|
+
animated cursor
|
|
102
|
+
|
|
103
|
+
**What's a variable vs. hardcoded:** only the cursor and z-index layers are CSS variables
|
|
104
|
+
(set on `.steppy-guide`); the rest are **literal colours** (a blue `#3498db`/`#2563eb`
|
|
105
|
+
accent, slate `#2c3e50`, grey `#7f8c8d`). There is **no palette-token system here** (unlike
|
|
106
|
+
the interactive player).
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
/* the only variables the step-by-step layer exposes */
|
|
110
|
+
.steppy-guide {
|
|
111
|
+
--steppy-cursor-size: 24px;
|
|
112
|
+
--steppy-cursor-color: #0f172a;
|
|
113
|
+
--steppy-cursor-accent: #2563eb;
|
|
114
|
+
--steppy-cursor-ring: rgba(37, 99, 235, 0.55);
|
|
115
|
+
--steppy-cursor-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
|
|
116
|
+
--steppy-z-screenshot: 1; --steppy-z-cursor: 10; --steppy-z-ripple: 11; --steppy-z-glyph: 12;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Restyling it
|
|
121
|
+
|
|
122
|
+
- **Cursor / stacking** — set the `--steppy-cursor-*` / `--steppy-z-*` variables. You can do
|
|
123
|
+
this from your host app's **global** CSS (`.steppy-guide { --steppy-cursor-color: … }`)
|
|
124
|
+
without overriding any template, because step-by-step CSS is global.
|
|
125
|
+
- **Cards, badges, titles, accent colour** (the hardcoded parts) — two ways:
|
|
126
|
+
- **Angular target:** the styles are global (`ViewEncapsulation.None`), so add global CSS
|
|
127
|
+
rules targeting the classes — `.steppy-guide .steppy-step-number { background: var(--brand); }`,
|
|
128
|
+
`.steppy-guide h1 { border-bottom-color: var(--brand); }`. Match or beat the injected
|
|
129
|
+
block's specificity (the component's `<style>` renders after your `<head>` CSS, so use a
|
|
130
|
+
slightly more specific selector or load your sheet so it wins).
|
|
131
|
+
- **Static target:** restyle in `templates/static/guides.css` (see next section) — the
|
|
132
|
+
static pages don't use the fragment's inline block.
|
|
133
|
+
- **Either, for a deep change:** override `templates/guide.fragment.html.j2` and edit its
|
|
134
|
+
`<style>` block. (`guide.html.j2` for the standalone `steppy guide` HTML.)
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Site chrome & landing pages (index, groups, onboarding)
|
|
139
|
+
|
|
140
|
+
This is the third surface: the home page, group landing pages, the onboarding meta-guide page,
|
|
141
|
+
the onboarding strip shown on guide pages, the header/breadcrumb/switchers, and the footer.
|
|
142
|
+
Same class names on both targets — but who provides the CSS differs sharply.
|
|
143
|
+
|
|
144
|
+
The full class inventory (these are what you write/override rules for):
|
|
145
|
+
|
|
146
|
+
| Region | Classes |
|
|
147
|
+
|---|---|
|
|
148
|
+
| Header / breadcrumb | `.steppy-site-header`, `.steppy-site-title`, `.steppy-breadcrumb`, `.steppy-breadcrumb-sep` |
|
|
149
|
+
| Language / layout switch | `.steppy-locale-switch`, `.steppy-layout-switch` |
|
|
150
|
+
| Home / index | `.steppy-index`, `.steppy-index-list`, `.steppy-index-title`, `.steppy-index-eyebrow`, `.steppy-index-meta`, `.steppy-index-desc`, `.steppy-index-empty`, `.steppy-index-onboarding`, `.steppy-index-group` |
|
|
151
|
+
| Group landing | `.steppy-index` (shared) + `.steppy-group-description` |
|
|
152
|
+
| Onboarding landing | `.steppy-onboarding`, `.steppy-onboarding-description`, `.steppy-onboarding-steps`, `.steppy-onboarding-step-number`, `.steppy-onboarding-step-title`, `.steppy-onboarding-cta`, `.steppy-onboarding-start` |
|
|
153
|
+
| Onboarding strip (on guide pages) | `.steppy-onboarding-strip`, `.steppy-onboarding-strip-progress`, `.steppy-onboarding-strip-nav`, `.steppy-onboarding-prev`, `.steppy-onboarding-next`, `.steppy-onboarding-disabled` |
|
|
154
|
+
| Footer | `.steppy-site-footer` |
|
|
155
|
+
|
|
156
|
+
### Static target — restyle `guides.css`
|
|
157
|
+
|
|
158
|
+
`target: 'static'` styles **all** of the above (plus the guide content) through one stylesheet,
|
|
159
|
+
`templates/static/guides.css` (a real file rendered through the Jinja loader, so a project copy
|
|
160
|
+
overrides it). The page templates (`templates/static/{index,page,group,onboarding,interactive}.html.j2`)
|
|
161
|
+
just `<link>` it. **Override `templates/static/guides.css` to rebrand the whole static site**;
|
|
162
|
+
override a page `.j2` only to change markup/structure. The colours there are all hardcoded
|
|
163
|
+
(blue `#3498db` accent, slate `#2c3e50`) — there's no token layer, so edit the literals. The
|
|
164
|
+
static **interactive** page also has a small inline `<style>` for its `.steppy-interactive-*`
|
|
165
|
+
shell (wrapper, back link) in `interactive.html.j2`.
|
|
166
|
+
|
|
167
|
+
### Angular target — the host app owns this CSS
|
|
168
|
+
|
|
169
|
+
`target: 'angular'` emits the group and onboarding landing pages as standalone components
|
|
170
|
+
(`_groups/<group>.group.component.ts`, `_onboarding/onboarding.component.ts`) and the
|
|
171
|
+
onboarding strip inside the guide component — all with `ViewEncapsulation.None` and **no
|
|
172
|
+
`styles:` block**. Steppy ships **no stylesheet** for them. So in Angular:
|
|
173
|
+
|
|
174
|
+
- **Style the landing pages + onboarding strip in your host app's global CSS**, targeting the
|
|
175
|
+
classes above. The fastest start is to **copy the relevant blocks out of the bundled
|
|
176
|
+
`static/guides.css`** into your global stylesheet and rebrand from there.
|
|
177
|
+
- **The home page and navbar are not generated** — your app renders them from the emitted
|
|
178
|
+
`<role>.nav.json` (a tree of `{titleKey, path, kind}` nodes resolved through ngx-translate).
|
|
179
|
+
Their look is 100% your app's.
|
|
180
|
+
- **The mode/layout switchers are PrimeNG `<p-selectButton>`** inside a `.guide-toolbar` wrapper
|
|
181
|
+
(no Steppy CSS) — they inherit your app's **PrimeNG theme**. Style `.guide-toolbar` for layout;
|
|
182
|
+
theme the buttons via PrimeNG.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Interactive player — choosing a template
|
|
187
|
+
|
|
188
|
+
The interactive player has three swappable **templates**. They apply **only** to guides built
|
|
189
|
+
with `modes: ['interactive']` (step-by-step ignores them).
|
|
190
|
+
|
|
191
|
+
| Template | Layout | Best for |
|
|
192
|
+
|---|---|---|
|
|
193
|
+
| `overlay` *(default)* | Full-bleed preview + a floating callout pinned to the target + a bottom bar. | Short, spatial flows. |
|
|
194
|
+
| `sidebar` | Left rail (title, "N steps · ~duration", a step **timeline**, the current description) beside the preview. | Longer guides; overview + jump-to-step. |
|
|
195
|
+
| `inline` | Full-bleed preview + one slim bottom bar (counter, description, sub-label, nav). | Minimal, embedded walkthroughs. |
|
|
196
|
+
|
|
197
|
+
Set the default in `steppy.guide.config.ts` (both fields optional):
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
export default defineGuideConfig({
|
|
201
|
+
// …
|
|
202
|
+
defaultTemplate: 'sidebar', // project-wide (falls back to 'overlay')
|
|
203
|
+
guides: [
|
|
204
|
+
{ slug: 'settings', title: '…', scenario: 'editor/settings.md',
|
|
205
|
+
modes: ['stepbystep', 'interactive'],
|
|
206
|
+
template: 'inline' }, // per-guide override; beats defaultTemplate
|
|
207
|
+
],
|
|
208
|
+
});
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Resolution order** (what a viewer sees): explicit `template="…"` attribute → the viewer's
|
|
212
|
+
persisted choice in `localStorage['steppy:active-template']` → the guide's `defaultTemplate`
|
|
213
|
+
→ `'overlay'`. The player renders its own `[Sidebar | Overlay | Inline]` switcher (plus
|
|
214
|
+
language + viewport switchers), so your configured default is only the **initial** template;
|
|
215
|
+
the viewer's pick persists across reloads and never resets the current step.
|
|
216
|
+
|
|
217
|
+
### Make `guide-text` fit the template
|
|
218
|
+
|
|
219
|
+
The templates read the three structured `guide-text` fields (see steppy-scenario-author):
|
|
220
|
+
|
|
221
|
+
| field | overlay | sidebar | inline |
|
|
222
|
+
|---|---|---|---|
|
|
223
|
+
| `title` | (unused) | **timeline heading**; falls back to `text` | (unused) |
|
|
224
|
+
| `text` | callout body | description panel | bar description |
|
|
225
|
+
| `subtitle` | mono sub-label | mono sub-label per row | mono sub-label |
|
|
226
|
+
|
|
227
|
+
**If a guide uses `sidebar`, author a short structured `title` (+ a `subtitle`) on every
|
|
228
|
+
step** — otherwise the timeline heading falls back to the long description.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Interactive player — cursor mode
|
|
233
|
+
|
|
234
|
+
Orthogonal to the template: how much pointer chrome the player draws, and **how the viewer
|
|
235
|
+
advances**. Set it project-wide with `cursor`, per guide with `guides[].cursor`.
|
|
236
|
+
|
|
237
|
+
| `cursor` | What's drawn | How a step advances |
|
|
238
|
+
|---|---|---|
|
|
239
|
+
| `arrow` *(default)* | Animated arrow travelling to the target, ripple on action, keyboard-glyph overlay, pulsing hotspot | Viewer clicks the hotspot |
|
|
240
|
+
| `hotspot` | No arrow, ripple, or glyph — just the pulsing hotspot | Viewer clicks the hotspot (Guideflow-style) |
|
|
241
|
+
| `off` | Nothing — no arrow, no hotspot | **Auto-advances** after each step's `waitAfter`, like a passive walkthrough |
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
export default defineGuideConfig({
|
|
245
|
+
// …
|
|
246
|
+
cursor: 'hotspot', // project-wide (falls back to 'arrow')
|
|
247
|
+
guides: [
|
|
248
|
+
{ slug: 'tour', title: '…', scenario: 'editor/tour.md',
|
|
249
|
+
modes: ['interactive'],
|
|
250
|
+
cursor: 'off' }, // per-guide override
|
|
251
|
+
],
|
|
252
|
+
});
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
`off` is the one that changes *behaviour*, not just looks — nothing is clickable, so the guide
|
|
256
|
+
plays itself. Pick it for a lobby-screen or embedded-demo loop; avoid it when the point is to
|
|
257
|
+
teach someone where to click. `cursor` applies to the interactive player only; the step-by-step
|
|
258
|
+
cursor is styled through `--steppy-cursor-*` (see above) and never disappears.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Interactive player — theming with `--steppy-*` tokens
|
|
263
|
+
|
|
264
|
+
The `<steppy-guide>` web component exposes its whole palette + type scale as CSS custom
|
|
265
|
+
properties. Because custom properties **inherit through the Shadow DOM boundary**, you theme
|
|
266
|
+
it by setting them on the `steppy-guide` element from your host's **global** CSS — you cannot
|
|
267
|
+
target its inner classes (they're shadow-isolated), only the tokens.
|
|
268
|
+
|
|
269
|
+
```css
|
|
270
|
+
steppy-guide {
|
|
271
|
+
--steppy-accent: #0067b8; /* highlight, current node, counters */
|
|
272
|
+
--steppy-accent-weak: rgba(0, 103, 184, 0.35); /* the highlight glow — alpha of accent */
|
|
273
|
+
--steppy-success: #2e7d32; /* completed-step node (sidebar) */
|
|
274
|
+
--steppy-bg: #fff; --steppy-surface: #fff; --steppy-chrome-bg: #f3f4f6;
|
|
275
|
+
--steppy-fg: #111827; --steppy-muted: #6b7280; --steppy-border: #e5e7eb;
|
|
276
|
+
--steppy-font-serif: 'Inter', Georgia, serif; /* titles */
|
|
277
|
+
--steppy-font-sans: 'Inter', system-ui, sans-serif; /* body/buttons */
|
|
278
|
+
--steppy-font-mono: 'JetBrains Mono', ui-monospace, monospace; /* counters/sub-labels */
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
| Token | Controls |
|
|
283
|
+
|---|---|
|
|
284
|
+
| `--steppy-accent` / `--steppy-accent-weak` | Highlight outline + its glow, current node, counters, focus |
|
|
285
|
+
| `--steppy-success` | Completed-step node in the sidebar timeline |
|
|
286
|
+
| `--steppy-bg` / `--steppy-surface` / `--steppy-chrome-bg` | Background / panels-rail / control bars |
|
|
287
|
+
| `--steppy-fg` / `--steppy-muted` / `--steppy-border` | Primary text / secondary / hairlines |
|
|
288
|
+
| `--steppy-font-serif` / `-sans` / `-mono` | Titles / body / counters + sub-labels |
|
|
289
|
+
| `--steppy-cursor-color` / `--steppy-tooltip-bg` / `--steppy-tooltip-fg` | Cursor + overlay callout (default to fg/surface) |
|
|
290
|
+
|
|
291
|
+
Set only what differs from the warm-cream/rust/green defaults. Use **system font stacks** or
|
|
292
|
+
fonts your host already loads — the player bundles none and makes **no network requests**.
|
|
293
|
+
|
|
294
|
+
**Where to put the rule:**
|
|
295
|
+
- **Angular target** *(default)*: a **global** stylesheet (e.g. `src/styles.scss`). Not a
|
|
296
|
+
component's scoped styles — those don't reach the custom element.
|
|
297
|
+
- **Static target:** add the `steppy-guide { … }` rule to your `templates/static/guides.css`
|
|
298
|
+
override (it's already linked by `interactive.html.j2`).
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## In-app tour overlay — tokens, parts, strings
|
|
303
|
+
|
|
304
|
+
In-app tours (opt-in: `tours.enabled: true` in `config.yaml`) render through a **different
|
|
305
|
+
element** from the guide player: `<steppy-tour-host>`, which the app imports into its own
|
|
306
|
+
bundle (`import '@steppy/player/tour'`) and mounts once in its shell. It draws popovers over
|
|
307
|
+
the live application, so it is styled from the **app's global stylesheet** — no `templates/`
|
|
308
|
+
file and no `steppy build` step is involved. It is Shadow DOM with exactly two ways in, both
|
|
309
|
+
deliberate: public custom properties and `::part()`. (Mounting it — the packages, the Angular
|
|
310
|
+
adapter, CSP, the language — is `steppy-app-tours`.)
|
|
311
|
+
|
|
312
|
+
### Custom properties
|
|
313
|
+
|
|
314
|
+
Set them on `:root` or on the element — custom properties inherit through the shadow boundary.
|
|
315
|
+
|
|
316
|
+
| Property | Default | Controls |
|
|
317
|
+
|---|---|---|
|
|
318
|
+
| `--steppy-tour-bubble-bg` | `#1f1d1a` | Popover background; falls back to `--steppy-tooltip-bg` |
|
|
319
|
+
| `--steppy-tour-bubble-fg` | `#fbf9f4` | Popover text; falls back to `--steppy-tooltip-fg` |
|
|
320
|
+
| `--steppy-tour-muted` | `#c9c5bd` | Progress text ("Step 2 of 5") |
|
|
321
|
+
| `--steppy-tour-accent` | `#a8410e` | Primary button, spotlight ring |
|
|
322
|
+
| `--steppy-tour-accent-fg` | `#ffffff` | Primary button text |
|
|
323
|
+
| `--steppy-tour-focus` | `#f09a6a` | Focus ring |
|
|
324
|
+
| `--steppy-tour-scrim` | `rgba(31, 29, 26, 0.45)` | The dimming around the spotlight |
|
|
325
|
+
| `--steppy-tour-radius` | `6px` | Corner radius |
|
|
326
|
+
| `--steppy-font-family` | inherited | Unset, the bubble uses **your app's font** |
|
|
327
|
+
|
|
328
|
+
```css
|
|
329
|
+
/* the app's global stylesheet */
|
|
330
|
+
:root {
|
|
331
|
+
--steppy-tour-accent: #0b5cad; /* primary button + spotlight ring — 6.7:1 against white text */
|
|
332
|
+
--steppy-tour-radius: 10px;
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
The defaults are a dark bubble with a rust accent. Moving to a light bubble means setting
|
|
337
|
+
`-bubble-bg`, `-bubble-fg`, `-muted` and `-focus` **together** — the default muted grey and
|
|
338
|
+
focus ring are tuned for the dark background. A project that already sets
|
|
339
|
+
`--steppy-tooltip-bg` / `-fg` on `:root` gets a matching bubble for free.
|
|
340
|
+
|
|
341
|
+
### Parts
|
|
342
|
+
|
|
343
|
+
Every visible piece is a `::part()`:
|
|
344
|
+
|
|
345
|
+
| Part | Element |
|
|
346
|
+
|---|---|
|
|
347
|
+
| `layer` | The full-page layer holding everything (the top-layer popover) |
|
|
348
|
+
| `spotlight` | The ring and scrim around the target |
|
|
349
|
+
| `bubble` | The popover itself — a labelled, non-modal dialog |
|
|
350
|
+
| `title`, `body`, `progress` | Its heading, its text, and "Step 2 of 5" |
|
|
351
|
+
| `button` | Every button, which also carries `primary` or `secondary` (its style) and one of `next`, `close`, `skip`, `end`, `resume` (which button it is) |
|
|
352
|
+
| `pill` | The "Tour paused" pill, holding `resume` and `close` |
|
|
353
|
+
| `guide-link` | The "Open the full guide" link |
|
|
354
|
+
|
|
355
|
+
```css
|
|
356
|
+
steppy-tour-host::part(bubble) { border-radius: 12px; }
|
|
357
|
+
steppy-tour-host::part(primary) { font-weight: 600; }
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
`::part()` matches the part element itself and nothing inside it — `::part(bubble) span` is an
|
|
361
|
+
invalid selector, not a narrower one. Style the named parts (`title`, `body`, `progress`)
|
|
362
|
+
directly; anything that is not a part is not styleable, on purpose.
|
|
363
|
+
|
|
364
|
+
### Strings
|
|
365
|
+
|
|
366
|
+
The chrome strings — Next, Done, "Step {current} of {total}", Close the tour, Skip this step,
|
|
367
|
+
End the tour, Resume tour, "Can't find this element", "Open the full guide", and the generic
|
|
368
|
+
per-action hint a step shows when its scenario has no text in that locale — ship in **English,
|
|
369
|
+
French, Dutch and German**. They resolve by the **tour file's** locale, never the page's, so the
|
|
370
|
+
buttons and the step text are always in one language; a regional locale reads its base language
|
|
371
|
+
(`fr-BE` → `fr`), and an unknown one falls back to English. Override keys, or add a locale, with
|
|
372
|
+
the host's `strings` property (a JavaScript property, not an attribute):
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
const host = document.querySelector('steppy-tour-host');
|
|
376
|
+
host.strings = {
|
|
377
|
+
en: { next: 'Continue', done: 'Got it' },
|
|
378
|
+
es: { next: 'Siguiente', done: 'Listo', progress: 'Paso {current} de {total}' },
|
|
379
|
+
};
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Keys: `next`, `progress` (`{current}`, `{total}`), `done`, `close`, `skipStep`, `endTour`,
|
|
383
|
+
`resume`, `paused`, `dialogLabel`, `openGuide`, `notFoundTitle`, `notFoundBody`, and
|
|
384
|
+
`instructionClick` / `instructionInput` / `instructionChange` / `instructionVisible` /
|
|
385
|
+
`instructionManual`. A key you leave out keeps the bundled value (English for a locale Steppy
|
|
386
|
+
does not ship — en, fr, nl and de are shipped; the compiler warns `chrome-strings-missing` for
|
|
387
|
+
any other tour language, so give that language every key). Step text itself is not a string
|
|
388
|
+
here — it comes from the scenario's `guide-text` / `tour-text`.
|
|
389
|
+
|
|
390
|
+
**Direction.** The layer carries the tour file's `lang` and `dir`, so an Arabic or Hebrew tour
|
|
391
|
+
lays the bubble out right to left. When you restyle parts, use logical properties
|
|
392
|
+
(`margin-inline-start`, `padding-inline-end`, `inset-inline-end`) rather than `left`/`right`,
|
|
393
|
+
or the override breaks mirroring. Placement around the target stays physical.
|
|
394
|
+
|
|
395
|
+
### Stacking and contrast
|
|
396
|
+
|
|
397
|
+
- **Stacking.** The layer uses the browser's **top layer** (`popover`) where available, so no
|
|
398
|
+
z-index of yours can sit above it — there is nothing to fight. Where the top layer is
|
|
399
|
+
unavailable it falls back to `baseZIndex` (the `base-z-index` attribute, default
|
|
400
|
+
`2147483000`); adjust that, never your own elements' z-index.
|
|
401
|
+
- **Contrast.** The defaults meet WCAG AA; keep that when you override them. Text
|
|
402
|
+
(`-bubble-fg` and `-muted` on `-bubble-bg`) and the primary button (`-accent-fg` on
|
|
403
|
+
`-accent`) need **at least 4.5:1**. The shipped accent `#a8410e` gives 6.13:1 on white; a
|
|
404
|
+
brighter "on-brand" orange is the classic way to break it.
|
|
405
|
+
- **Focus and screen readers are behaviour, not styling.** Focus moves into the popover only for
|
|
406
|
+
manual steps and the "can't find" fallback; each step is announced through a polite live
|
|
407
|
+
region. The focus ring is an outline in `--steppy-tour-focus` — recolour it there rather
|
|
408
|
+
than removing it with a `::part(button)` rule.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## Print / PDF layout (`--pdf`, `--handbook`)
|
|
413
|
+
|
|
414
|
+
Steppy lays out no PDF of its own. `--pdf` prints the **already-rendered guide HTML** through
|
|
415
|
+
headless Chromium — so **the `@media print` blocks in the templates *are* the PDF layout**, and
|
|
416
|
+
restyling the page restyles the PDF for free. There is no separate PDF stylesheet to maintain.
|
|
417
|
+
|
|
418
|
+
Three surfaces carry a `@media print` block; edit whichever one your target uses:
|
|
419
|
+
|
|
420
|
+
| File | Applies to |
|
|
421
|
+
|---|---|
|
|
422
|
+
| `static/guides.css` | Static site pages + everything `build --pdf` prints |
|
|
423
|
+
| `guide.fragment.html.j2` | Angular-embedded guides |
|
|
424
|
+
| `guide.html.j2` | Standalone `steppy guide` HTML |
|
|
425
|
+
|
|
426
|
+
What those blocks already do, and what you inherit by not fighting them:
|
|
427
|
+
|
|
428
|
+
- **Site chrome is hidden** (`.steppy-site-header`, `.steppy-breadcrumb`, both switchers, the
|
|
429
|
+
onboarding strip, the PDF link, the footer). That is exactly what lets `build --pdf` print
|
|
430
|
+
the *published* page as-is instead of needing a print-only page. Inactive layouts are already
|
|
431
|
+
`display:none`, so a multi-layout page prints the layout the reader is looking at.
|
|
432
|
+
- **`print-color-adjust: exact`** on `body`, so step badges and the role chip keep their colour
|
|
433
|
+
when the viewer has background graphics off. Drop this and your accent silently disappears
|
|
434
|
+
from every PDF.
|
|
435
|
+
- **`page-break-inside: avoid`** on each `.steppy-step` and each screenshot.
|
|
436
|
+
- **The cursor, ripple, and keyboard glyph are hidden** — they animate, and a frozen arrow on
|
|
437
|
+
paper reads as an artifact.
|
|
438
|
+
|
|
439
|
+
### The one token you will actually need
|
|
440
|
+
|
|
441
|
+
```css
|
|
442
|
+
:root { --steppy-print-max-image-height: 180mm; } /* default */
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
**Chromium cannot split an image across pages.** An uncapped full-page screenshot taller than
|
|
446
|
+
the printable area gets *clipped*, not continued — so screenshots are capped at this height.
|
|
447
|
+
Symptoms and fixes:
|
|
448
|
+
|
|
449
|
+
- **Screenshots look too small in the PDF** → raise it (`220mm`), or switch `pdf.landscape: true`.
|
|
450
|
+
- **A screenshot is cut off at the page edge** → your override raised it past the printable
|
|
451
|
+
height. Lower it, or add margin headroom in the `pdf:` block.
|
|
452
|
+
|
|
453
|
+
Paper itself (`format`, `margin`, `landscape`, `scale`, `print_background`) is **config, not
|
|
454
|
+
CSS** — the `pdf:` block in `config.yaml`. Keep `print_background: true`; Playwright's own
|
|
455
|
+
default is `false`, which would drop every step badge.
|
|
456
|
+
|
|
457
|
+
### Handbook
|
|
458
|
+
|
|
459
|
+
`--handbook` renders `guide.book.html.j2`: a cover, a table of contents, then every guide
|
|
460
|
+
fragment in order. It **inlines `static/guides.css`** and adds its own `.steppy-book`,
|
|
461
|
+
`.steppy-book-cover`, `.steppy-book-subtitle`, `.steppy-book-toc`, `.steppy-book-section`,
|
|
462
|
+
`.steppy-book-guide` classes. So:
|
|
463
|
+
|
|
464
|
+
- **Rebranding `static/guides.css` rebrands the handbook automatically** — there is no fourth
|
|
465
|
+
copy of the guide CSS to keep in sync.
|
|
466
|
+
- **Restyle the cover / TOC** by overriding `guide.book.html.j2` and editing its own `<style>`
|
|
467
|
+
block.
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## Narrated video (`modes: ['video']`)
|
|
472
|
+
|
|
473
|
+
A video is a **baked MP4**, so none of the CSS above reaches it — restyling means re-rendering
|
|
474
|
+
(`steppy build --video` / `steppy guide --video`). Its look is configured, not styled, in the
|
|
475
|
+
`video:` block of `config.yaml`:
|
|
476
|
+
|
|
477
|
+
```yaml
|
|
478
|
+
video:
|
|
479
|
+
width: 1280 # display width; also affects duration — cursor travel is measured in display px
|
|
480
|
+
max_height: null
|
|
481
|
+
captions: band # band (default) | off
|
|
482
|
+
branding:
|
|
483
|
+
logo: null # path to a logo image
|
|
484
|
+
accent: null # accent colour used by the intro/outro and caption band
|
|
485
|
+
font_family: null
|
|
486
|
+
stamp:
|
|
487
|
+
enabled: false # burn a version/date stamp into the frame
|
|
488
|
+
text: "{version} · {date}"
|
|
489
|
+
version: dev
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
- **`captions: band`** draws the caption band over the footage; `off` removes it (a `.vtt`
|
|
493
|
+
track still ships beside the MP4, so a player can render its own).
|
|
494
|
+
- **`branding.accent`** is the video's equivalent of `--steppy-accent` — set both to the same
|
|
495
|
+
colour or the video will not match the site it links from.
|
|
496
|
+
- **`width` is not only a quality setting**: cursor travel duration is computed from *display*
|
|
497
|
+
distance, so changing it changes the video's length.
|
|
498
|
+
|
|
499
|
+
The **page around** the video is a normal template. The static target's `static/video.html.j2`
|
|
500
|
+
links `assets/guides.css` and adds its own inline `<style>` for the
|
|
501
|
+
`.steppy-video-shell` / `-header` / `-back` / `-player` / `-switch` / `-downloads` classes —
|
|
502
|
+
the same arrangement as `interactive.html.j2`. The Angular target emits
|
|
503
|
+
`angular/component-video.ts.j2`, which your host app styles.
|
|
504
|
+
|
|
505
|
+
**Re-rendering is expensive** (minutes of CPU per video, plus TTS cost). The render cache is
|
|
506
|
+
content-addressed, so a pure styling change to the *page* costs nothing — but touching
|
|
507
|
+
`video.branding`, `width`, or `captions` invalidates every video. Get branding right in one
|
|
508
|
+
pass; `steppy video check` first, and `steppy video cache` to see what you are about to
|
|
509
|
+
invalidate.
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Overridable templates — complete map
|
|
514
|
+
|
|
515
|
+
Every file you can drop into your project's `templates/` to change appearance. **Styling**
|
|
516
|
+
= controls look; **structure** = markup/data only (rarely touched for styling).
|
|
517
|
+
|
|
518
|
+
| File | Controls | Kind |
|
|
519
|
+
|---|---|---|
|
|
520
|
+
| `guide.fragment.html.j2` | Step-by-step guide CSS (`.steppy-guide` block) — Angular inlines it, static suppresses it | **styling** |
|
|
521
|
+
| `guide.html.j2` | Standalone `steppy guide` HTML page (self-contained styles) | **styling** |
|
|
522
|
+
| `guide.book.html.j2` | `--handbook` document: cover, TOC, `.steppy-book-*` classes. Inlines `guides.css` | **styling** (cover/TOC only) |
|
|
523
|
+
| `static/guides.css` | **Static target's entire stylesheet** — chrome, all landing pages, onboarding strip, guide content, **and the `@media print` / PDF layout** | **styling** |
|
|
524
|
+
| `static/index.html.j2` | Static home page markup | structure (styling via guides.css) |
|
|
525
|
+
| `static/group.html.j2` | Static group landing markup | structure (styling via guides.css) |
|
|
526
|
+
| `static/onboarding.html.j2` | Static onboarding landing markup | structure (styling via guides.css) |
|
|
527
|
+
| `static/page.html.j2` | Static guide page (header, switchers, onboarding strip markup) | structure (styling via guides.css) |
|
|
528
|
+
| `static/interactive.html.j2` | Static interactive page + inline `.steppy-interactive-*` shell CSS | **styling** (shell) |
|
|
529
|
+
| `static/video.html.j2` | Static video page + inline `.steppy-video-*` shell CSS (player, version switcher, download links). Links `guides.css` | **styling** (shell) |
|
|
530
|
+
| `static/_seo_head.html.j2` | Shared SEO `<head>` fragment (`robots`/canonical/`hreflang`/description/Open Graph) `{% include %}`d by every static page — no visual output | **not styling** |
|
|
531
|
+
| `static/robots.txt.j2` | Emitted by `seo.mode: 'public'` — no visual output | **not styling** |
|
|
532
|
+
| `static/_headers.j2` | `X-Robots-Tag` rules for artifacts that cannot carry a robots meta (PDFs). Read by Netlify / Cloudflare Pages, ignored by GitHub and GitLab Pages — no visual output | **not styling** |
|
|
533
|
+
| `static/_mode_links.html.j2` | The "Step by Step / Interactive / Video" row, `{% include %}`d by all three renderings of a guide. Styled by `.steppy-mode-links` in `guides.css` | structure (`guides.css` styles it) |
|
|
534
|
+
| `static/sitemap.xml.j2` | **Not bundled.** `sitemap.xml` is generated by `src/steppy/sitemap.py`; add this file to the project to override it (context: `urls` with `.loc` / `.alternates[].hreflang` / `.alternates[].href` / `.lastmod`, plus `lastmod`) | **not styling** |
|
|
535
|
+
| `angular/component.ts.j2` | Guide component markup: `.guide-toolbar`, PrimeNG switchers, onboarding strip (no inline CSS) | structure (host CSS styles it) |
|
|
536
|
+
| `angular/component-interactive.ts.j2` | `<steppy-guide>` host + `.steppy-guide-host` inline CSS | **styling** (host wrapper) |
|
|
537
|
+
| `angular/component-video.ts.j2` | Angular host for a guide's narrated video | structure (host CSS styles it) |
|
|
538
|
+
| `angular/group.component.ts.j2` | Group landing component (bare classes, no CSS) | structure (host CSS styles it) |
|
|
539
|
+
| `angular/onboarding.component.ts.j2` | Onboarding landing component (bare classes, no CSS) | structure (host CSS styles it) |
|
|
540
|
+
| `report/report.css` | **The run report's entire stylesheet** — a separate site, see below | **styling** |
|
|
541
|
+
| `report/{index,scenario,coverage}.html.j2` | Run report pages (`steppy report`) | structure (styling via `report/report.css`) |
|
|
542
|
+
| `report/_head.html.j2` | Shared report `<head>` (always `noindex`) — no visual output | **not styling** |
|
|
543
|
+
| `static/cursor.js.j2`, `angular/{content,routes}.ts.j2`, `angular/gitignore.j2`, `guide.md.j2` | Cursor driver / fragments / routes / nav data | **not styling** |
|
|
544
|
+
|
|
545
|
+
> **Angular reality check:** the `angular/*.component.ts.j2` files carry **no CSS** — overriding
|
|
546
|
+
> them changes markup, not look. To restyle Angular landing pages / onboarding strip, write
|
|
547
|
+
> CSS in your **host app** (seed it from `static/guides.css`), not by editing these templates.
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## The run report is a *separate* site (`steppy report`)
|
|
552
|
+
|
|
553
|
+
`steppy report` renders run results, not guides, and it deliberately does **not** load
|
|
554
|
+
`static/guides.css` — that file is guide-site chrome plus the `@media print` rules that
|
|
555
|
+
*are* the PDF layout, none of which a report inherits. Override
|
|
556
|
+
`templates/report/report.css` instead, and note that only the report pages are affected.
|
|
557
|
+
|
|
558
|
+
It is token-driven, so branding it is usually a handful of custom properties on `:root`
|
|
559
|
+
(the file also redefines them under `@media (prefers-color-scheme: dark)`):
|
|
560
|
+
|
|
561
|
+
```css
|
|
562
|
+
:root {
|
|
563
|
+
--accent: #2f5fd0; /* links */
|
|
564
|
+
--pass: #1a7f45; /* passed chips + verdict */
|
|
565
|
+
--fail: #c02b2b; /* failed chips, cause counts, the failing step number */
|
|
566
|
+
--warn: #9a6200; /* notices: truncated, no timeline, unknown outcomes */
|
|
567
|
+
--surface: #ffffff; /* cards */
|
|
568
|
+
--bg: #f7f7f8;
|
|
569
|
+
--border: #e3e3e7;
|
|
570
|
+
--radius: 8px;
|
|
571
|
+
}
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
Class prefixes: `.steppy-report-*` (header, main, section, meta, table),
|
|
575
|
+
`.steppy-chip[data-outcome="passed|failed|error|skipped|…"]`, `.steppy-verdict`,
|
|
576
|
+
`.steppy-cause*`, `.steppy-step*`, `.steppy-shots`, `.steppy-variant*`, `.steppy-notice`,
|
|
577
|
+
`pre.steppy-tail`.
|
|
578
|
+
|
|
579
|
+
> **Two gotchas, in the order they will bite you.**
|
|
580
|
+
>
|
|
581
|
+
> 1. **`report.css` must contain no Jinja delimiters — not even inside a CSS comment.** It
|
|
582
|
+
> is loaded through the Jinja loader (that is what makes the override work), so a `{{`
|
|
583
|
+
> or `{%` anywhere in the file is a `TemplateSyntaxError`. Writing a comment *warning
|
|
584
|
+
> about* this is how you cause it.
|
|
585
|
+
> 2. **The report's Jinja environment has `autoescape=True`**, unlike every other Steppy
|
|
586
|
+
> template. That is deliberate — it renders failure tails, which are arbitrary page
|
|
587
|
+
> content — but it means an interpolated value would come out HTML-escaped. Use CSS
|
|
588
|
+
> custom properties; there is nothing this file needs from Python.
|
|
589
|
+
>
|
|
590
|
+
> Two things are not styling knobs at all: every page is hardcoded `noindex` (a run report
|
|
591
|
+
> has no SEO value, and publishing one to Pages publishes its screenshots), and the images
|
|
592
|
+
> use `width: auto; max-width: 100%` so a dense capture renders at its true pixels and a
|
|
593
|
+
> low-res one is never upscaled — the same rule the guide stage uses.
|
|
594
|
+
|
|
595
|
+
---
|
|
596
|
+
|
|
597
|
+
## Responsive & motion
|
|
598
|
+
|
|
599
|
+
- The interactive **screenshot variant** (desktop/mobile capture) is the player's
|
|
600
|
+
"Affichage"/View switcher (driven by the `layouts` you captured) — orthogonal to the
|
|
601
|
+
template. The static site has its own desktop/mobile `.steppy-layout-switch`.
|
|
602
|
+
- The `sidebar` template collapses to a single column (rail above preview) below ~640px of
|
|
603
|
+
**container** width; `overlay`/`inline` are already full-bleed.
|
|
604
|
+
- The interactive player honours `prefers-reduced-motion`. The step-by-step cursor animation
|
|
605
|
+
is driven by a script; reduce its motion by lowering the `guide.cursor.*` timings in the
|
|
606
|
+
scenario frontmatter or omitting `guide.enabled`.
|
|
607
|
+
- The **in-app tour overlay** turns its anchored bubble into a **bottom (or top) sheet** on
|
|
608
|
+
narrow screens (640px viewport width and below), and whenever an anchored bubble would cover
|
|
609
|
+
the target. It honours `prefers-reduced-motion`: **reduced motion removes its transitions and
|
|
610
|
+
smooth scrolling**. Neither needs configuring.
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## Common mistakes
|
|
615
|
+
|
|
616
|
+
1. **Confusing the two systems** — step-by-step is global `.steppy-guide` CSS you can target
|
|
617
|
+
directly; the interactive player is shadow-isolated and themeable **only** via `--steppy-*`
|
|
618
|
+
tokens. A rule like `steppy-guide .steppy-step-number {…}` does nothing to the player.
|
|
619
|
+
2. **Looking for a palette token in step-by-step** — only the cursor/z-index are variables;
|
|
620
|
+
card/badge/accent colours are hardcoded. Override the template or add global class rules.
|
|
621
|
+
3. **Editing generated output** (`assets/guides.css`, `interactive.html`, components) — it's
|
|
622
|
+
overwritten on the next `steppy build`. Override via `templates/…` or host CSS instead.
|
|
623
|
+
4. **Theming the player from a scoped component stylesheet** — won't reach the shadow DOM.
|
|
624
|
+
Put `steppy-guide { --steppy-… }` in a **global** stylesheet.
|
|
625
|
+
5. **Changing `--steppy-accent` but not `--steppy-accent-weak`** — the highlight glow keeps
|
|
626
|
+
the old colour. Set it to an alpha of the new accent.
|
|
627
|
+
6. **Setting `template` / `defaultTemplate` on a `stepbystep`-only guide** — templates need
|
|
628
|
+
`modes: ['interactive']`.
|
|
629
|
+
7. **Expecting `defaultTemplate` to stick after a viewer switches** — it's only the *initial*
|
|
630
|
+
template; the viewer's choice persists in `localStorage`. Clear
|
|
631
|
+
`localStorage['steppy:active-template']` to re-test the default.
|
|
632
|
+
8. **Choosing `sidebar` but writing only `text`** — the timeline heading falls back to the
|
|
633
|
+
long description. Author a short structured `title`.
|
|
634
|
+
9. **Forgetting to re-run `steppy build` / not on steppy ≥ 0.2.0** — the templated player only
|
|
635
|
+
appears once the new `steppy-player.js` bundle is copied.
|
|
636
|
+
10. **Overriding a template and never re-diffing after an upgrade** — you own the full copy;
|
|
637
|
+
upstream CSS/markup fixes won't reach you until you merge them.
|
|
638
|
+
11. **Expecting the Angular landing pages / onboarding strip to come pre-styled** — they don't;
|
|
639
|
+
the Angular components ship bare classes with no CSS. Write the rules in your host app
|
|
640
|
+
(seed them from `static/guides.css`). Editing `angular/*.component.ts.j2` changes markup,
|
|
641
|
+
not look.
|
|
642
|
+
12. **Trying to style the Angular mode/layout switcher with Steppy CSS** — it's a PrimeNG
|
|
643
|
+
`<p-selectButton>`; theme it through your app's PrimeNG theme (and `.guide-toolbar` for
|
|
644
|
+
layout).
|
|
645
|
+
13. **Hunting for a generated Angular home page / navbar** — neither is generated. Your app
|
|
646
|
+
renders them from `<role>.nav.json`, and their styling is entirely yours.
|
|
647
|
+
14. **Looking for a PDF stylesheet** — there isn't one. `--pdf` prints the rendered HTML, so
|
|
648
|
+
the `@media print` block in `static/guides.css` (or the fragment/standalone template) *is*
|
|
649
|
+
the PDF layout.
|
|
650
|
+
15. **Raising `--steppy-print-max-image-height` until screenshots look big** — past the
|
|
651
|
+
printable height Chromium **clips** the image rather than splitting it. Raise `pdf.margin`
|
|
652
|
+
headroom or switch to `pdf.landscape: true` instead of pushing the cap.
|
|
653
|
+
16. **Setting `pdf.print_background: false`** (or leaving a viewer's "background graphics" off
|
|
654
|
+
without `print-color-adjust: exact`) — every step badge and role chip prints blank.
|
|
655
|
+
17. **Trying to restyle a video with CSS** — an MP4 is baked. Its look comes from the `video:`
|
|
656
|
+
config block; changing it means re-rendering with `--video`, and `branding` / `width` /
|
|
657
|
+
`captions` invalidate the whole render cache.
|
|
658
|
+
18. **Branding the site and forgetting `video.branding.accent`** — the video is the one surface
|
|
659
|
+
that does not inherit `--steppy-accent`, so it ships in the old colour.
|
|
660
|
+
19. **Reaching for `cursor: 'off'` to "clean up" a teaching guide** — it removes the hotspot
|
|
661
|
+
too, so nothing is clickable and the guide auto-advances. If you only want to drop the
|
|
662
|
+
arrow and ripple, that's `cursor: 'hotspot'`.
|
|
663
|
+
20. **Styling the in-app tour from an Angular component's `styles`** — component-scoped CSS
|
|
664
|
+
cannot reach into the overlay's shadow DOM, so `.bubble { … }` or `.title { … }` there does
|
|
665
|
+
nothing. Use the `--steppy-tour-*` custom properties or
|
|
666
|
+
`steppy-tour-host::part(…)` rules, in the app's **global** stylesheet.
|
|
667
|
+
21. **Writing `steppy-tour-host::part(bubble) span { … }`** — parts cannot be descended into;
|
|
668
|
+
the selector is invalid and the whole rule is dropped. Target the named part instead
|
|
669
|
+
(`::part(title)`, `::part(body)`, `::part(progress)`).
|
|
670
|
+
22. **Lowering `--steppy-tour-accent` below 4.5:1** against `--steppy-tour-accent-fg` —
|
|
671
|
+
the primary button's text fails WCAG AA. The same 4.5:1 floor applies to `-bubble-fg` and
|
|
672
|
+
`-muted` on `-bubble-bg`; check a brand colour before shipping it.
|
|
673
|
+
23. **Fighting z-index to get above (or below) the tour** — the overlay sits in the browser's
|
|
674
|
+
top layer, where no z-index competes with it. Raising your header's z-index changes
|
|
675
|
+
nothing; where the top layer is unavailable, set the host's `baseZIndex`
|
|
676
|
+
(`base-z-index`) instead.
|