@conduction/docusaurus-preset 1.0.0 → 1.1.0
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/README.md +19 -9
- package/package.json +1 -1
- package/src/components/ContactCta/ContactCta.jsx +74 -0
- package/src/components/ContactCta/ContactCta.module.css +121 -0
- package/src/components/ContentDetailHero/ContentDetailHero.jsx +15 -14
- package/src/components/ContentDetailHero/ContentDetailHero.module.css +0 -1
- package/src/components/NextSteps/NextSteps.jsx +71 -0
- package/src/components/NextSteps/NextSteps.module.css +89 -0
- package/src/components/Prerequisites/Prerequisites.jsx +48 -0
- package/src/components/Prerequisites/Prerequisites.module.css +64 -0
- package/src/components/Troubleshooting/Troubleshooting.jsx +57 -0
- package/src/components/Troubleshooting/Troubleshooting.module.css +83 -0
- package/src/components/index.js +9 -0
package/README.md
CHANGED
|
@@ -139,9 +139,18 @@ This is how product sites such as `mydash.conduction.nl/docs/...` adopt the bran
|
|
|
139
139
|
|
|
140
140
|
## Releasing
|
|
141
141
|
|
|
142
|
-
Releases auto-publish on push to `main
|
|
142
|
+
Releases auto-publish on push to `main`, driven by [semantic-release](https://semantic-release.gitbook.io/) reading [conventional-commit](https://www.conventionalcommits.org/) messages. The [.github/workflows/publish-packages.yml](../.github/workflows/publish-packages.yml) workflow walks every commit since the last `@conduction/docusaurus-preset-v*` tag and decides what to ship:
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
| Commit prefix | Release |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| `feat:` | minor bump |
|
|
147
|
+
| `fix:` | patch bump |
|
|
148
|
+
| `feat!:` or `BREAKING CHANGE:` footer | major bump |
|
|
149
|
+
| anything else (`chore:`, `docs:`, `refactor:`, …) | no release |
|
|
150
|
+
|
|
151
|
+
Path filtering via [semantic-release-monorepo](https://github.com/pmowrer/semantic-release-monorepo) restricts the commit scan to commits that touched files inside `docusaurus-preset/`. Edits to `preview/`, `sites/`, `brand/`, etc. never trigger a release. The diagram primitives ship inside the same tarball under `src/diagrams/`, so there is exactly one npm release per qualifying push.
|
|
152
|
+
|
|
153
|
+
A manual `workflow_dispatch` is also accepted, with an optional `dry_run` flag that runs `semantic-release --dry-run` (no publish, no tag, no release) — useful for sanity-checking the next-version decision before merging a feature branch.
|
|
145
154
|
|
|
146
155
|
**One-time setup**: configure the npm Trusted Publisher (OIDC) link.
|
|
147
156
|
|
|
@@ -159,16 +168,17 @@ That's it. There is no token to generate, no secret to install, no expiry to tra
|
|
|
159
168
|
**Per release:**
|
|
160
169
|
|
|
161
170
|
```bash
|
|
162
|
-
#
|
|
163
|
-
|
|
164
|
-
$EDITOR docusaurus-preset/package.json # "version": "0.2.0"
|
|
171
|
+
# Make a change inside docusaurus-preset/ and commit with a conventional prefix.
|
|
172
|
+
$EDITOR docusaurus-preset/src/components/Hero.jsx
|
|
165
173
|
|
|
166
|
-
git add docusaurus-preset/
|
|
167
|
-
git commit -m "
|
|
168
|
-
git push origin main #
|
|
174
|
+
git add docusaurus-preset/src/components/Hero.jsx
|
|
175
|
+
git commit -m "feat: add tagline slot to Hero"
|
|
176
|
+
git push origin main # semantic-release decides + publishes
|
|
169
177
|
```
|
|
170
178
|
|
|
171
|
-
|
|
179
|
+
`package.json#version` on `main` stays stale on purpose — semantic-release uses the `@conduction/docusaurus-preset-v*` tag stream as its source of truth and bumps `package.json` in-place during the publish run without committing it back. The version on npm and the GitHub Releases page are authoritative; the field in `main`'s `package.json` only matters during a publish.
|
|
180
|
+
|
|
181
|
+
If a publish fails mid-run, fix the issue and push another commit — `semantic-release` will retry the bump on the next run. npm rejects re-publishing the same version, so the next attempt picks the following patch.
|
|
172
182
|
|
|
173
183
|
## License
|
|
174
184
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/docusaurus-preset",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Conduction brand preset for Docusaurus 3. Tokens, theme, navbar, footer, i18n config for nl/en/de/fr, and the React component library that powers conduction.nl and the Conduction product sites.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <ContactCta />
|
|
3
|
+
*
|
|
4
|
+
* Soft tinted call-to-action panel for the bottom of academy
|
|
5
|
+
* tutorials, docs pages, or any long-form content. Two-column
|
|
6
|
+
* layout: title + body on the left, single primary action on the
|
|
7
|
+
* right. A subtle pointy-top hex motif decorates the right edge
|
|
8
|
+
* so the panel reads as a Conduction surface, not a generic blue
|
|
9
|
+
* box.
|
|
10
|
+
*
|
|
11
|
+
* Tone: cobalt-50 ground, cobalt-900 type, cobalt-700 body, KNVB
|
|
12
|
+
* orange reserved for the trailing arrow inside the CTA. One
|
|
13
|
+
* orange accent per screen rule still holds: this panel uses the
|
|
14
|
+
* orange only as a 12px arrow, never as the button fill.
|
|
15
|
+
*
|
|
16
|
+
* Distinct from <CtaBanner /> (cobalt-900 marketing footer with
|
|
17
|
+
* dual CTAs and centred type) and from <NewsletterCta /> (form,
|
|
18
|
+
* not a single button). Use ContactCta when:
|
|
19
|
+
* - Reader has finished a tutorial and you want them to email
|
|
20
|
+
* - You're at the end of a docs page and want them to read further
|
|
21
|
+
* - You need a "talk to us" prompt that is calmer than the dark
|
|
22
|
+
* CtaBanner but louder than a plain link
|
|
23
|
+
*
|
|
24
|
+
* Usage in MDX:
|
|
25
|
+
*
|
|
26
|
+
* <ContactCta
|
|
27
|
+
* title="Wil je meer weten?"
|
|
28
|
+
* body="Mail ons. We helpen je in een halve dag op weg met je eigen Woo-publicatieflow."
|
|
29
|
+
* cta={{ label: "Mail ons", href: "mailto:info@conduction.nl" }}
|
|
30
|
+
* />
|
|
31
|
+
*
|
|
32
|
+
* Mirrors the .contact-cta section in
|
|
33
|
+
* preview/components/contact-cta.html.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import styles from './ContactCta.module.css';
|
|
38
|
+
|
|
39
|
+
export default function ContactCta({
|
|
40
|
+
title,
|
|
41
|
+
body,
|
|
42
|
+
cta,
|
|
43
|
+
className,
|
|
44
|
+
}) {
|
|
45
|
+
const composed = [styles.panel, className].filter(Boolean).join(' ');
|
|
46
|
+
return (
|
|
47
|
+
<aside className={composed}>
|
|
48
|
+
<span className={styles.hex1} aria-hidden="true" />
|
|
49
|
+
<span className={styles.hex2} aria-hidden="true" />
|
|
50
|
+
<span className={styles.hex3} aria-hidden="true" />
|
|
51
|
+
|
|
52
|
+
<div className={styles.copy}>
|
|
53
|
+
{title && <h3 className={styles.title}>{title}</h3>}
|
|
54
|
+
{body && <p className={styles.body}>{body}</p>}
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
{cta && (
|
|
58
|
+
<a
|
|
59
|
+
className={styles.button}
|
|
60
|
+
href={cta.href || '#'}
|
|
61
|
+
target={cta.href && /^https?:/.test(cta.href) ? '_blank' : undefined}
|
|
62
|
+
rel={cta.href && /^https?:/.test(cta.href) ? 'noreferrer noopener' : undefined}
|
|
63
|
+
>
|
|
64
|
+
<span>{cta.label}</span>
|
|
65
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" width="14" height="14"
|
|
66
|
+
fill="none" stroke="currentColor" strokeWidth="2"
|
|
67
|
+
strokeLinecap="round" strokeLinejoin="round">
|
|
68
|
+
<path d="M5 12h14M12 5l7 7-7 7"/>
|
|
69
|
+
</svg>
|
|
70
|
+
</a>
|
|
71
|
+
)}
|
|
72
|
+
</aside>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
.panel {
|
|
2
|
+
position: relative;
|
|
3
|
+
display: grid;
|
|
4
|
+
grid-template-columns: 1fr auto;
|
|
5
|
+
gap: var(--space-6);
|
|
6
|
+
align-items: center;
|
|
7
|
+
background: var(--c-cobalt-50);
|
|
8
|
+
border: 1px solid var(--c-cobalt-100);
|
|
9
|
+
border-radius: var(--radius-lg);
|
|
10
|
+
padding: var(--space-7) var(--space-8);
|
|
11
|
+
margin: var(--space-10) 0 var(--space-6);
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@media (max-width: 720px) {
|
|
17
|
+
.panel {
|
|
18
|
+
grid-template-columns: 1fr;
|
|
19
|
+
padding: var(--space-6);
|
|
20
|
+
gap: var(--space-4);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Decorative pointy-top hexes layered on the right edge. They sit
|
|
25
|
+
behind the copy via z-index 0 with the copy and button on z-index 1.
|
|
26
|
+
Pointy-top point-up only — never rotated, never flat-top. */
|
|
27
|
+
.hex1,
|
|
28
|
+
.hex2,
|
|
29
|
+
.hex3 {
|
|
30
|
+
position: absolute;
|
|
31
|
+
background: var(--c-cobalt-100);
|
|
32
|
+
clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
|
|
33
|
+
pointer-events: none;
|
|
34
|
+
z-index: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.hex1 {
|
|
38
|
+
width: 220px;
|
|
39
|
+
height: 254px;
|
|
40
|
+
right: -60px;
|
|
41
|
+
top: -40px;
|
|
42
|
+
opacity: 0.7;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.hex2 {
|
|
46
|
+
width: 110px;
|
|
47
|
+
height: 127px;
|
|
48
|
+
right: 80px;
|
|
49
|
+
bottom: -30px;
|
|
50
|
+
opacity: 0.5;
|
|
51
|
+
background: var(--c-cobalt-200);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.hex3 {
|
|
55
|
+
width: 56px;
|
|
56
|
+
height: 65px;
|
|
57
|
+
right: 220px;
|
|
58
|
+
top: 18px;
|
|
59
|
+
opacity: 0.5;
|
|
60
|
+
background: var(--c-cobalt-200);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@media (max-width: 720px) {
|
|
64
|
+
.hex1 { right: -100px; top: -80px; }
|
|
65
|
+
.hex2, .hex3 { display: none; }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.copy {
|
|
69
|
+
position: relative;
|
|
70
|
+
z-index: 1;
|
|
71
|
+
display: grid;
|
|
72
|
+
gap: var(--space-2);
|
|
73
|
+
max-width: 60ch;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.title {
|
|
77
|
+
font-size: 24px;
|
|
78
|
+
font-weight: 700;
|
|
79
|
+
letter-spacing: -0.01em;
|
|
80
|
+
color: var(--c-cobalt-900);
|
|
81
|
+
margin: 0;
|
|
82
|
+
line-height: 1.25;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.body {
|
|
86
|
+
font-size: 16px;
|
|
87
|
+
color: var(--c-cobalt-700);
|
|
88
|
+
line-height: 1.6;
|
|
89
|
+
margin: 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.button {
|
|
93
|
+
position: relative;
|
|
94
|
+
z-index: 1;
|
|
95
|
+
display: inline-flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: 8px;
|
|
98
|
+
padding: 12px 22px;
|
|
99
|
+
background: var(--c-blue-cobalt);
|
|
100
|
+
color: white;
|
|
101
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
102
|
+
font-size: 12px;
|
|
103
|
+
font-weight: 600;
|
|
104
|
+
letter-spacing: 0.06em;
|
|
105
|
+
text-transform: uppercase;
|
|
106
|
+
text-decoration: none;
|
|
107
|
+
border-radius: var(--radius-pill, 999px);
|
|
108
|
+
transition: background 120ms ease, transform 120ms ease, box-shadow 120ms ease;
|
|
109
|
+
white-space: nowrap;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
.button:hover {
|
|
113
|
+
background: var(--c-cobalt-900);
|
|
114
|
+
transform: translateY(-1px);
|
|
115
|
+
box-shadow: 0 6px 16px rgba(13, 36, 78, 0.18);
|
|
116
|
+
color: white;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.button svg {
|
|
120
|
+
color: var(--c-orange-knvb);
|
|
121
|
+
}
|
|
@@ -91,6 +91,21 @@ export default function ContentDetailHero({
|
|
|
91
91
|
</div>
|
|
92
92
|
)}
|
|
93
93
|
|
|
94
|
+
{title && <h1 className={styles.title}>{title}</h1>}
|
|
95
|
+
|
|
96
|
+
<div className={styles.cover}>
|
|
97
|
+
<span className={styles.watermark} aria-hidden="true" />
|
|
98
|
+
{cover && cover.src
|
|
99
|
+
? <img src={cover.src} alt={cover.alt || ''} className={styles.coverImg} />
|
|
100
|
+
: (
|
|
101
|
+
<HexThumbnail size="xl" tone={cover && cover.tone || 'cobalt'}>
|
|
102
|
+
{cover && cover.icon}
|
|
103
|
+
</HexThumbnail>
|
|
104
|
+
)}
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
{summary && <p className={styles.summary}>{summary}</p>}
|
|
108
|
+
|
|
94
109
|
{(typeLabel || tags.length > 0) && (
|
|
95
110
|
<div className={styles.tags}>
|
|
96
111
|
{typeLabel && (
|
|
@@ -102,9 +117,6 @@ export default function ContentDetailHero({
|
|
|
102
117
|
</div>
|
|
103
118
|
)}
|
|
104
119
|
|
|
105
|
-
{title && <h1 className={styles.title}>{title}</h1>}
|
|
106
|
-
{summary && <p className={styles.summary}>{summary}</p>}
|
|
107
|
-
|
|
108
120
|
{(author || date || duration) && (
|
|
109
121
|
<div className={styles.meta}>
|
|
110
122
|
{(author || date) && (
|
|
@@ -120,17 +132,6 @@ export default function ContentDetailHero({
|
|
|
120
132
|
{duration && <span className={styles.duration}>{duration}</span>}
|
|
121
133
|
</div>
|
|
122
134
|
)}
|
|
123
|
-
|
|
124
|
-
<div className={styles.cover}>
|
|
125
|
-
<span className={styles.watermark} aria-hidden="true" />
|
|
126
|
-
{cover && cover.src
|
|
127
|
-
? <img src={cover.src} alt={cover.alt || ''} className={styles.coverImg} />
|
|
128
|
-
: (
|
|
129
|
-
<HexThumbnail size="xl" tone={cover && cover.tone || 'cobalt'}>
|
|
130
|
-
{cover && cover.icon}
|
|
131
|
-
</HexThumbnail>
|
|
132
|
-
)}
|
|
133
|
-
</div>
|
|
134
135
|
</section>
|
|
135
136
|
);
|
|
136
137
|
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <NextSteps /> + <NextStep />
|
|
3
|
+
*
|
|
4
|
+
* Action-card row for the end of an academy tutorial. Replaces the
|
|
5
|
+
* ad-hoc "Volgende stap" h2 + bullet list pattern that was
|
|
6
|
+
* duplicated across tutorials.
|
|
7
|
+
*
|
|
8
|
+
* Each <NextStep/> is a clickable card with a short title, a
|
|
9
|
+
* one-line description, and a target href. The whole card is the
|
|
10
|
+
* link target so the entire tile is clickable. Use the optional
|
|
11
|
+
* `cta` prop to override the default "Read more" label.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
*
|
|
15
|
+
* <NextSteps title="Volgende stap" lede="Met deze vier modes kun je elk type document koppelen.">
|
|
16
|
+
* <NextStep
|
|
17
|
+
* href="/apps/opencatalogi"
|
|
18
|
+
* title="Toon op een portaal"
|
|
19
|
+
* cta="Bekijk OpenCatalogi"
|
|
20
|
+
* >
|
|
21
|
+
* Combineer publicaties met andere apps op een publiek portaal.
|
|
22
|
+
* </NextStep>
|
|
23
|
+
* <NextStep
|
|
24
|
+
* href="/apps/docudesk"
|
|
25
|
+
* title="Documenten lakken"
|
|
26
|
+
* cta="Bekijk DocuDesk"
|
|
27
|
+
* >
|
|
28
|
+
* Anonimiseer privacygevoelige passages voor publicatie.
|
|
29
|
+
* </NextStep>
|
|
30
|
+
* </NextSteps>
|
|
31
|
+
*
|
|
32
|
+
* Mirrors the .next-steps section in
|
|
33
|
+
* preview/components/next-steps.html.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import styles from './NextSteps.module.css';
|
|
38
|
+
|
|
39
|
+
export function NextStep({href, title, cta = 'Read more', children, className}) {
|
|
40
|
+
const composed = [styles.card, className].filter(Boolean).join(' ');
|
|
41
|
+
const Tag = href ? 'a' : 'div';
|
|
42
|
+
const props = href ? {href} : {};
|
|
43
|
+
return (
|
|
44
|
+
<Tag className={composed} {...props}>
|
|
45
|
+
{title && <div className={styles.title}>{title}</div>}
|
|
46
|
+
{children && <div className={styles.body}>{children}</div>}
|
|
47
|
+
{href && (
|
|
48
|
+
<div className={styles.cta}>
|
|
49
|
+
{cta}
|
|
50
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" width="14" height="14"
|
|
51
|
+
fill="none" stroke="currentColor" strokeWidth="2"
|
|
52
|
+
strokeLinecap="round" strokeLinejoin="round">
|
|
53
|
+
<path d="M5 12h14M12 5l7 7-7 7"/>
|
|
54
|
+
</svg>
|
|
55
|
+
</div>
|
|
56
|
+
)}
|
|
57
|
+
</Tag>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default function NextSteps({title = 'Next steps', lede, children, columns = 3, className}) {
|
|
62
|
+
const composed = [styles.section, className].filter(Boolean).join(' ');
|
|
63
|
+
const gridClass = [styles.grid, styles['cols-' + columns]].join(' ');
|
|
64
|
+
return (
|
|
65
|
+
<section className={composed}>
|
|
66
|
+
{title && <h2 className={styles.title}>{title}</h2>}
|
|
67
|
+
{lede && <p className={styles.lede}>{lede}</p>}
|
|
68
|
+
<div className={gridClass}>{children}</div>
|
|
69
|
+
</section>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
.section {
|
|
2
|
+
margin: var(--space-10) 0 var(--space-8);
|
|
3
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.title {
|
|
7
|
+
font-size: 28px;
|
|
8
|
+
font-weight: 700;
|
|
9
|
+
letter-spacing: -0.01em;
|
|
10
|
+
color: var(--c-cobalt-900);
|
|
11
|
+
margin: 0 0 var(--space-3);
|
|
12
|
+
line-height: 1.2;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.lede {
|
|
16
|
+
font-size: 17px;
|
|
17
|
+
color: var(--c-cobalt-700);
|
|
18
|
+
line-height: 1.6;
|
|
19
|
+
margin: 0 0 var(--space-5);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.grid {
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: var(--space-4);
|
|
25
|
+
}
|
|
26
|
+
.cols-2 { grid-template-columns: repeat(2, 1fr); }
|
|
27
|
+
.cols-3 { grid-template-columns: repeat(3, 1fr); }
|
|
28
|
+
.cols-4 { grid-template-columns: repeat(4, 1fr); }
|
|
29
|
+
|
|
30
|
+
@media (max-width: 800px) {
|
|
31
|
+
.cols-2, .cols-3, .cols-4 { grid-template-columns: 1fr; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.card {
|
|
35
|
+
display: grid;
|
|
36
|
+
gap: var(--space-2);
|
|
37
|
+
padding: var(--space-5) var(--space-5) var(--space-4);
|
|
38
|
+
background: white;
|
|
39
|
+
border: 1px solid var(--c-cobalt-100);
|
|
40
|
+
border-radius: var(--radius-md);
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
color: inherit;
|
|
43
|
+
transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
a.card:hover {
|
|
47
|
+
border-color: var(--c-cobalt-300);
|
|
48
|
+
transform: translateY(-1px);
|
|
49
|
+
box-shadow: 0 6px 20px rgba(13, 36, 78, 0.08);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.card .title {
|
|
53
|
+
font-size: 16px;
|
|
54
|
+
font-weight: 700;
|
|
55
|
+
color: var(--c-cobalt-900);
|
|
56
|
+
margin: 0;
|
|
57
|
+
line-height: 1.3;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.card .body {
|
|
61
|
+
font-size: 14px;
|
|
62
|
+
color: var(--c-cobalt-700);
|
|
63
|
+
line-height: 1.55;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.card .body code {
|
|
67
|
+
background: var(--c-cobalt-100);
|
|
68
|
+
border-radius: 4px;
|
|
69
|
+
padding: 1px 5px;
|
|
70
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
71
|
+
font-size: 13px;
|
|
72
|
+
color: var(--c-cobalt-900);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.cta {
|
|
76
|
+
display: inline-flex;
|
|
77
|
+
align-items: center;
|
|
78
|
+
gap: 6px;
|
|
79
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
80
|
+
font-size: 12px;
|
|
81
|
+
letter-spacing: 0.04em;
|
|
82
|
+
text-transform: uppercase;
|
|
83
|
+
color: var(--c-blue-cobalt);
|
|
84
|
+
margin-top: var(--space-1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
a.card:hover .cta {
|
|
88
|
+
color: var(--c-cobalt-900);
|
|
89
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <Prerequisites /> + <PrerequisiteItem />
|
|
3
|
+
*
|
|
4
|
+
* Tinted card with a checklist of things the reader needs before
|
|
5
|
+
* starting an academy tutorial. Replaces the ad-hoc "What you need"
|
|
6
|
+
* h2 + bullet list pattern that was duplicated across tutorials.
|
|
7
|
+
*
|
|
8
|
+
* Each item renders with a small hex-bullet on the left so the list
|
|
9
|
+
* reads as a checklist instead of generic prose. The card uses the
|
|
10
|
+
* cobalt-50 tinted-surface tone, matching <FeatureList/> and
|
|
11
|
+
* <FAQ/> on academy pages.
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
*
|
|
15
|
+
* <Prerequisites title="Wat je nodig hebt">
|
|
16
|
+
* <PrerequisiteItem>
|
|
17
|
+
* Een werkend Woo-register. Volg eerst <a href="...">Een Woo-register opzetten</a> als je dat nog niet hebt.
|
|
18
|
+
* </PrerequisiteItem>
|
|
19
|
+
* <PrerequisiteItem>Een publicatie-object met bekende UUID</PrerequisiteItem>
|
|
20
|
+
* <PrerequisiteItem><code>curl</code>, basisauth, en een paar testbestanden</PrerequisiteItem>
|
|
21
|
+
* </Prerequisites>
|
|
22
|
+
*
|
|
23
|
+
* Mirrors the .prerequisites section in
|
|
24
|
+
* preview/components/prerequisites.html.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import React from 'react';
|
|
28
|
+
import styles from './Prerequisites.module.css';
|
|
29
|
+
|
|
30
|
+
export function PrerequisiteItem({children, className}) {
|
|
31
|
+
const composed = [styles.item, className].filter(Boolean).join(' ');
|
|
32
|
+
return (
|
|
33
|
+
<li className={composed}>
|
|
34
|
+
<span className={styles.bullet} aria-hidden="true" />
|
|
35
|
+
<span className={styles.body}>{children}</span>
|
|
36
|
+
</li>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export default function Prerequisites({title = 'What you need', children, className}) {
|
|
41
|
+
const composed = [styles.card, className].filter(Boolean).join(' ');
|
|
42
|
+
return (
|
|
43
|
+
<aside className={composed}>
|
|
44
|
+
{title && <h2 className={styles.title}>{title}</h2>}
|
|
45
|
+
<ul className={styles.list}>{children}</ul>
|
|
46
|
+
</aside>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
.card {
|
|
2
|
+
background: var(--c-cobalt-50);
|
|
3
|
+
border: 1px solid var(--c-cobalt-100);
|
|
4
|
+
border-radius: var(--radius-lg);
|
|
5
|
+
padding: var(--space-6) var(--space-7);
|
|
6
|
+
margin: var(--space-6) 0;
|
|
7
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.title {
|
|
11
|
+
font-size: 18px;
|
|
12
|
+
font-weight: 700;
|
|
13
|
+
letter-spacing: -0.01em;
|
|
14
|
+
color: var(--c-cobalt-900);
|
|
15
|
+
margin: 0 0 var(--space-3);
|
|
16
|
+
line-height: 1.3;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.list {
|
|
20
|
+
list-style: none;
|
|
21
|
+
padding: 0;
|
|
22
|
+
margin: 0;
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: var(--space-2);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.item {
|
|
28
|
+
display: grid;
|
|
29
|
+
grid-template-columns: auto 1fr;
|
|
30
|
+
gap: var(--space-2);
|
|
31
|
+
align-items: start;
|
|
32
|
+
font-size: 16px;
|
|
33
|
+
line-height: 1.55;
|
|
34
|
+
color: var(--c-cobalt-700);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.bullet {
|
|
38
|
+
width: 14px;
|
|
39
|
+
height: 14px;
|
|
40
|
+
margin-top: 6px;
|
|
41
|
+
background: var(--c-cobalt-700);
|
|
42
|
+
clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
|
|
43
|
+
flex-shrink: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.body {
|
|
47
|
+
display: block;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.body a {
|
|
51
|
+
color: var(--c-blue-cobalt);
|
|
52
|
+
text-decoration: underline;
|
|
53
|
+
text-underline-offset: 2px;
|
|
54
|
+
}
|
|
55
|
+
.body a:hover { color: var(--c-cobalt-900); }
|
|
56
|
+
|
|
57
|
+
.body code {
|
|
58
|
+
background: var(--c-cobalt-100);
|
|
59
|
+
border-radius: 4px;
|
|
60
|
+
padding: 1px 6px;
|
|
61
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
color: var(--c-cobalt-900);
|
|
64
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <Troubleshooting /> + <TroubleshootingItem />
|
|
3
|
+
*
|
|
4
|
+
* Structured error-recovery list for academy tutorials. Replaces
|
|
5
|
+
* the ad-hoc "Probleemoplossing" h2 + bold-text pattern that was
|
|
6
|
+
* duplicated across tutorials.
|
|
7
|
+
*
|
|
8
|
+
* Each item pairs a `symptom` (the user-visible error or behaviour)
|
|
9
|
+
* with the body content (what to do about it). The symptom renders
|
|
10
|
+
* in a subtle warning-tinted slot on the left; the body fills the
|
|
11
|
+
* rest. Keep symptoms short and specific (literal error strings
|
|
12
|
+
* work best). Keep bodies under three sentences.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
*
|
|
16
|
+
* <Troubleshooting title="Probleemoplossing">
|
|
17
|
+
* <TroubleshootingItem symptom="The uploaded file exceeds upload_max_filesize">
|
|
18
|
+
* Verhoog <code>upload_max_filesize</code> en <code>post_max_size</code> in
|
|
19
|
+
* <code>php.ini</code>, of stap over op Mode 4.
|
|
20
|
+
* </TroubleshootingItem>
|
|
21
|
+
* <TroubleshootingItem symptom="Bestand verschijnt niet in /files-lijst na MOVE">
|
|
22
|
+
* Controleer dat de <code>Destination</code>-header naar <code>Open Registers/...</code> wijst.
|
|
23
|
+
* </TroubleshootingItem>
|
|
24
|
+
* </Troubleshooting>
|
|
25
|
+
*
|
|
26
|
+
* Mirrors the .troubleshooting section in
|
|
27
|
+
* preview/components/troubleshooting.html.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import React from 'react';
|
|
31
|
+
import styles from './Troubleshooting.module.css';
|
|
32
|
+
|
|
33
|
+
export function TroubleshootingItem({symptom, children, className}) {
|
|
34
|
+
const composed = [styles.item, className].filter(Boolean).join(' ');
|
|
35
|
+
return (
|
|
36
|
+
<div className={composed}>
|
|
37
|
+
{symptom && (
|
|
38
|
+
<div className={styles.symptom}>
|
|
39
|
+
<span className={styles.icon} aria-hidden="true">!</span>
|
|
40
|
+
<code className={styles.symptomText}>{symptom}</code>
|
|
41
|
+
</div>
|
|
42
|
+
)}
|
|
43
|
+
<div className={styles.body}>{children}</div>
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default function Troubleshooting({title = 'Troubleshooting', lede, children, className}) {
|
|
49
|
+
const composed = [styles.section, className].filter(Boolean).join(' ');
|
|
50
|
+
return (
|
|
51
|
+
<section className={composed}>
|
|
52
|
+
{title && <h2 className={styles.title}>{title}</h2>}
|
|
53
|
+
{lede && <p className={styles.lede}>{lede}</p>}
|
|
54
|
+
<div className={styles.list}>{children}</div>
|
|
55
|
+
</section>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
.section {
|
|
2
|
+
margin: var(--space-10) 0 var(--space-8);
|
|
3
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
.title {
|
|
7
|
+
font-size: 28px;
|
|
8
|
+
font-weight: 700;
|
|
9
|
+
letter-spacing: -0.01em;
|
|
10
|
+
color: var(--c-cobalt-900);
|
|
11
|
+
margin: 0 0 var(--space-3);
|
|
12
|
+
line-height: 1.2;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.lede {
|
|
16
|
+
font-size: 17px;
|
|
17
|
+
color: var(--c-cobalt-700);
|
|
18
|
+
line-height: 1.6;
|
|
19
|
+
margin: 0 0 var(--space-5);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.list {
|
|
23
|
+
display: grid;
|
|
24
|
+
gap: var(--space-3);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.item {
|
|
28
|
+
background: var(--c-cobalt-50);
|
|
29
|
+
border-left: 3px solid var(--c-orange-knvb);
|
|
30
|
+
border-radius: var(--radius-md);
|
|
31
|
+
padding: var(--space-4) var(--space-5);
|
|
32
|
+
display: grid;
|
|
33
|
+
gap: var(--space-2);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.symptom {
|
|
37
|
+
display: flex;
|
|
38
|
+
align-items: center;
|
|
39
|
+
gap: var(--space-2);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.icon {
|
|
43
|
+
display: inline-flex;
|
|
44
|
+
align-items: center;
|
|
45
|
+
justify-content: center;
|
|
46
|
+
width: 20px;
|
|
47
|
+
height: 20px;
|
|
48
|
+
background: var(--c-orange-knvb);
|
|
49
|
+
color: white;
|
|
50
|
+
font-family: var(--conduction-typography-font-family-display);
|
|
51
|
+
font-weight: 700;
|
|
52
|
+
font-size: 13px;
|
|
53
|
+
clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
|
|
54
|
+
flex-shrink: 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.symptomText {
|
|
58
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
59
|
+
font-size: 14px;
|
|
60
|
+
color: var(--c-cobalt-900);
|
|
61
|
+
background: transparent;
|
|
62
|
+
padding: 0;
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
word-break: break-word;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.body {
|
|
68
|
+
font-size: 16px;
|
|
69
|
+
color: var(--c-cobalt-700);
|
|
70
|
+
line-height: 1.6;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.body code {
|
|
74
|
+
background: var(--c-cobalt-100);
|
|
75
|
+
border-radius: 4px;
|
|
76
|
+
padding: 1px 6px;
|
|
77
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
78
|
+
font-size: 14px;
|
|
79
|
+
color: var(--c-cobalt-900);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.body p { margin: var(--space-2) 0 0; }
|
|
83
|
+
.body p:first-child { margin-top: 0; }
|
package/src/components/index.js
CHANGED
|
@@ -94,3 +94,12 @@ export {
|
|
|
94
94
|
export {default as NewsletterCta} from './NewsletterCta/NewsletterCta.jsx';
|
|
95
95
|
export {default as RelatedPosts} from './RelatedPosts/RelatedPosts.jsx';
|
|
96
96
|
export {default as ContentDetailHero} from './ContentDetailHero/ContentDetailHero.jsx';
|
|
97
|
+
|
|
98
|
+
/* Tutorial-body components. Drop-in replacements for the ad-hoc
|
|
99
|
+
"What you need", "Troubleshooting", and "Next steps" h2 + bullet
|
|
100
|
+
patterns that academy tutorials kept duplicating. Designed for use
|
|
101
|
+
inside an MDX academy post body. */
|
|
102
|
+
export {default as Prerequisites, PrerequisiteItem} from './Prerequisites/Prerequisites.jsx';
|
|
103
|
+
export {default as Troubleshooting, TroubleshootingItem} from './Troubleshooting/Troubleshooting.jsx';
|
|
104
|
+
export {default as NextSteps, NextStep} from './NextSteps/NextSteps.jsx';
|
|
105
|
+
export {default as ContactCta} from './ContactCta/ContactCta.jsx';
|