@conduction/docusaurus-preset 1.2.0 → 1.3.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/package.json +4 -1
- package/src/components/ContactCta/ContactCta.jsx +33 -37
- package/src/components/ContactCta/ContactCta.module.css +4 -92
- package/src/components/HexCard/HexCard.jsx +115 -0
- package/src/components/HexCard/HexCard.module.css +147 -0
- package/src/components/Outcomes/Outcomes.jsx +8 -8
- package/src/components/Outcomes/Outcomes.module.css +4 -26
- package/src/components/Prerequisites/Prerequisites.jsx +8 -9
- package/src/components/Prerequisites/Prerequisites.module.css +5 -26
- package/src/components/index.js +1 -0
- package/src/css/tokens.css +446 -10
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@conduction/docusaurus-preset",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"prepack": "node scripts/prepack-bundle-css.js"
|
|
6
|
+
},
|
|
4
7
|
"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
8
|
"main": "src/index.js",
|
|
6
9
|
"exports": {
|
|
@@ -2,11 +2,9 @@
|
|
|
2
2
|
* <ContactCta />
|
|
3
3
|
*
|
|
4
4
|
* Soft tinted call-to-action panel for the bottom of academy
|
|
5
|
-
* tutorials, docs pages, or any long-form content.
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* so the panel reads as a Conduction surface, not a generic blue
|
|
9
|
-
* box.
|
|
5
|
+
* tutorials, docs pages, or any long-form content. Composed from
|
|
6
|
+
* <HexCard decoration> with a mail icon in the top-left badge and
|
|
7
|
+
* the primary CTA in the right-side actions slot.
|
|
10
8
|
*
|
|
11
9
|
* Tone: cobalt-50 ground, cobalt-900 type, cobalt-700 body, KNVB
|
|
12
10
|
* orange reserved for the trailing arrow inside the CTA. One
|
|
@@ -34,41 +32,39 @@
|
|
|
34
32
|
*/
|
|
35
33
|
|
|
36
34
|
import React from 'react';
|
|
35
|
+
import HexCard from '../HexCard/HexCard';
|
|
37
36
|
import styles from './ContactCta.module.css';
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
cta,
|
|
43
|
-
className,
|
|
44
|
-
}) {
|
|
45
|
-
const composed = [styles.panel, className].filter(Boolean).join(' ');
|
|
38
|
+
function CtaButton({cta}) {
|
|
39
|
+
if (!cta) return null;
|
|
40
|
+
const isExternal = cta.href && /^https?:/.test(cta.href);
|
|
46
41
|
return (
|
|
47
|
-
<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
<a
|
|
43
|
+
className={styles.button}
|
|
44
|
+
href={cta.href || '#'}
|
|
45
|
+
target={isExternal ? '_blank' : undefined}
|
|
46
|
+
rel={isExternal ? 'noreferrer noopener' : undefined}
|
|
47
|
+
>
|
|
48
|
+
<span>{cta.label}</span>
|
|
49
|
+
<svg viewBox="0 0 24 24" aria-hidden="true" width="14" height="14"
|
|
50
|
+
fill="none" stroke="currentColor" strokeWidth="2"
|
|
51
|
+
strokeLinecap="round" strokeLinejoin="round">
|
|
52
|
+
<path d="M5 12h14M12 5l7 7-7 7"/>
|
|
53
|
+
</svg>
|
|
54
|
+
</a>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<path d="M5 12h14M12 5l7 7-7 7"/>
|
|
69
|
-
</svg>
|
|
70
|
-
</a>
|
|
71
|
-
)}
|
|
72
|
-
</aside>
|
|
58
|
+
export default function ContactCta({title, body, cta, className}) {
|
|
59
|
+
return (
|
|
60
|
+
<HexCard
|
|
61
|
+
title={title}
|
|
62
|
+
icon="mail"
|
|
63
|
+
decoration
|
|
64
|
+
actions={<CtaButton cta={cta} />}
|
|
65
|
+
className={className}
|
|
66
|
+
>
|
|
67
|
+
{body && <p>{body}</p>}
|
|
68
|
+
</HexCard>
|
|
73
69
|
);
|
|
74
70
|
}
|
|
@@ -1,97 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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-12) 0 var(--space-8);
|
|
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
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* <ContactCta /> styles. The shell is now <HexCard decoration>; only
|
|
3
|
+
* the action button keeps its own rules here.
|
|
4
|
+
*/
|
|
91
5
|
|
|
92
6
|
.button {
|
|
93
|
-
position: relative;
|
|
94
|
-
z-index: 1;
|
|
95
7
|
display: inline-flex;
|
|
96
8
|
align-items: center;
|
|
97
9
|
gap: 8px;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <HexCard />
|
|
3
|
+
*
|
|
4
|
+
* Tinted academy/tutorial panel with a top-left hex badge holding an
|
|
5
|
+
* icon. The shared shell behind <ContactCta />, <Outcomes />, and
|
|
6
|
+
* <Prerequisites /> — all three were rebuilt in isolation around the
|
|
7
|
+
* same cobalt-50 surface, so this primitive consolidates the surface,
|
|
8
|
+
* border, padding, and badge slot in one place.
|
|
9
|
+
*
|
|
10
|
+
* Anatomy:
|
|
11
|
+
* ┌──────────────────────────────────────────┐
|
|
12
|
+
* │ ⬢ Title [actions] │
|
|
13
|
+
* │ body / list / paragraph │
|
|
14
|
+
* └──────────────────────────────────────────┘
|
|
15
|
+
*
|
|
16
|
+
* The badge is a <HexThumbnail size="sm" tone="cobalt-deep"> with a
|
|
17
|
+
* white glyph. Cobalt + white keeps the orange accent budget free for
|
|
18
|
+
* the orange checkmark/bullet glyphs inside <Outcomes /> and
|
|
19
|
+
* <Prerequisites />, and for the orange CTA arrow in <ContactCta />.
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
*
|
|
23
|
+
* <HexCard title="Wat je leert" icon="lightbulb">
|
|
24
|
+
* <ul>...</ul>
|
|
25
|
+
* </HexCard>
|
|
26
|
+
*
|
|
27
|
+
* <HexCard
|
|
28
|
+
* title="Wil je meer weten?"
|
|
29
|
+
* icon="mail"
|
|
30
|
+
* decoration
|
|
31
|
+
* actions={<a className="…">Mail ons →</a>}
|
|
32
|
+
* >
|
|
33
|
+
* <p>Mail ons. We helpen je…</p>
|
|
34
|
+
* </HexCard>
|
|
35
|
+
*
|
|
36
|
+
* Mirrors preview/components/hex-card.html.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import React from 'react';
|
|
40
|
+
import HexThumbnail from '../primitives/HexThumbnail';
|
|
41
|
+
import styles from './HexCard.module.css';
|
|
42
|
+
|
|
43
|
+
const ICONS = {
|
|
44
|
+
mail: (
|
|
45
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
46
|
+
<rect x="3" y="5" width="18" height="14" rx="2"/>
|
|
47
|
+
<path d="M3 7l9 7 9-7"/>
|
|
48
|
+
</svg>
|
|
49
|
+
),
|
|
50
|
+
lightbulb: (
|
|
51
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
52
|
+
<path d="M9 18h6"/>
|
|
53
|
+
<path d="M10 21h4"/>
|
|
54
|
+
<path d="M12 3a6 6 0 0 0-4 10.5c.7.8 1 1.6 1 2.5v1h6v-1c0-.9.3-1.7 1-2.5A6 6 0 0 0 12 3z"/>
|
|
55
|
+
</svg>
|
|
56
|
+
),
|
|
57
|
+
clipboard: (
|
|
58
|
+
<svg viewBox="0 0 24 24" aria-hidden="true">
|
|
59
|
+
<rect x="6" y="4" width="12" height="17" rx="2"/>
|
|
60
|
+
<rect x="9" y="2" width="6" height="4" rx="1"/>
|
|
61
|
+
<path d="M9 11h6"/>
|
|
62
|
+
<path d="M9 15h6"/>
|
|
63
|
+
</svg>
|
|
64
|
+
),
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export default function HexCard({
|
|
68
|
+
title,
|
|
69
|
+
icon,
|
|
70
|
+
iconNode,
|
|
71
|
+
decoration = false,
|
|
72
|
+
actions,
|
|
73
|
+
children,
|
|
74
|
+
className,
|
|
75
|
+
as: Tag = 'aside',
|
|
76
|
+
}) {
|
|
77
|
+
const composed = [
|
|
78
|
+
styles.card,
|
|
79
|
+
decoration && styles.hasDecoration,
|
|
80
|
+
actions && styles.hasActions,
|
|
81
|
+
className,
|
|
82
|
+
].filter(Boolean).join(' ');
|
|
83
|
+
|
|
84
|
+
const glyph = iconNode || (icon && ICONS[icon]) || null;
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Tag className={composed}>
|
|
88
|
+
{decoration && (
|
|
89
|
+
<>
|
|
90
|
+
<span className={`${styles.deco} ${styles.deco1}`} aria-hidden="true" />
|
|
91
|
+
<span className={`${styles.deco} ${styles.deco2}`} aria-hidden="true" />
|
|
92
|
+
<span className={`${styles.deco} ${styles.deco3}`} aria-hidden="true" />
|
|
93
|
+
</>
|
|
94
|
+
)}
|
|
95
|
+
|
|
96
|
+
{glyph && (
|
|
97
|
+
<span className={styles.badge} aria-hidden="true">
|
|
98
|
+
<HexThumbnail size="sm" tone="cobalt-deep">{glyph}</HexThumbnail>
|
|
99
|
+
</span>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
<div className={styles.head}>
|
|
103
|
+
{title && <h3 className={styles.title}>{title}</h3>}
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div className={styles.body}>
|
|
107
|
+
{children}
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
{actions && (
|
|
111
|
+
<div className={styles.actions}>{actions}</div>
|
|
112
|
+
)}
|
|
113
|
+
</Tag>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <HexCard /> styles. Tinted academy panel with a top-left hex
|
|
3
|
+
* badge, optional right-edge decorative hex motif, and an optional
|
|
4
|
+
* right-side actions slot.
|
|
5
|
+
*
|
|
6
|
+
* Layout:
|
|
7
|
+
* [badge] [head .................] [actions]
|
|
8
|
+
* [body ......................... ]
|
|
9
|
+
*
|
|
10
|
+
* The badge column auto-sizes to the 56px hex; head spans the
|
|
11
|
+
* remaining width; body lives below the head and spans both
|
|
12
|
+
* non-action columns. The actions cell is only present when an
|
|
13
|
+
* <HexCard actions={…}> prop is passed (e.g. ContactCta button).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
.card {
|
|
17
|
+
position: relative;
|
|
18
|
+
display: grid;
|
|
19
|
+
grid-template-columns: auto 1fr;
|
|
20
|
+
grid-template-areas:
|
|
21
|
+
"badge head"
|
|
22
|
+
"body body";
|
|
23
|
+
column-gap: var(--space-4);
|
|
24
|
+
row-gap: var(--space-3);
|
|
25
|
+
align-items: start;
|
|
26
|
+
background: var(--c-cobalt-50);
|
|
27
|
+
border: 1px solid var(--c-cobalt-100);
|
|
28
|
+
border-radius: var(--radius-lg);
|
|
29
|
+
padding: var(--space-6) var(--space-7);
|
|
30
|
+
margin: var(--space-8) 0;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.hasActions {
|
|
36
|
+
grid-template-columns: auto 1fr auto;
|
|
37
|
+
grid-template-areas:
|
|
38
|
+
"badge head actions"
|
|
39
|
+
"body body actions";
|
|
40
|
+
align-items: center;
|
|
41
|
+
column-gap: var(--space-5);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@media (max-width: 720px) {
|
|
45
|
+
.hasActions {
|
|
46
|
+
grid-template-columns: auto 1fr;
|
|
47
|
+
grid-template-areas:
|
|
48
|
+
"badge head"
|
|
49
|
+
"body body"
|
|
50
|
+
"actions actions";
|
|
51
|
+
}
|
|
52
|
+
.card { padding: var(--space-5) var(--space-5); }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.badge {
|
|
56
|
+
grid-area: badge;
|
|
57
|
+
position: relative;
|
|
58
|
+
z-index: 1;
|
|
59
|
+
display: inline-flex;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.head {
|
|
63
|
+
grid-area: head;
|
|
64
|
+
position: relative;
|
|
65
|
+
z-index: 1;
|
|
66
|
+
align-self: center;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.title {
|
|
70
|
+
font-size: 22px;
|
|
71
|
+
font-weight: 700;
|
|
72
|
+
letter-spacing: -0.01em;
|
|
73
|
+
color: var(--c-cobalt-900);
|
|
74
|
+
margin: 0;
|
|
75
|
+
line-height: 1.25;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.body {
|
|
79
|
+
grid-area: body;
|
|
80
|
+
position: relative;
|
|
81
|
+
z-index: 1;
|
|
82
|
+
font-size: 16px;
|
|
83
|
+
line-height: 1.6;
|
|
84
|
+
color: var(--c-cobalt-700);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.body > p { margin: 0; }
|
|
88
|
+
.body > p + p { margin-top: var(--space-3); }
|
|
89
|
+
.body > ul {
|
|
90
|
+
list-style: none;
|
|
91
|
+
padding: 0;
|
|
92
|
+
margin: 0;
|
|
93
|
+
display: grid;
|
|
94
|
+
gap: var(--space-3);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.actions {
|
|
98
|
+
grid-area: actions;
|
|
99
|
+
position: relative;
|
|
100
|
+
z-index: 1;
|
|
101
|
+
display: inline-flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Decorative pointy-top hexes layered on the right edge. Only
|
|
107
|
+
rendered when the parent passes <HexCard decoration>. They sit
|
|
108
|
+
behind copy via z-index 0 with everything else on z-index 1.
|
|
109
|
+
Pointy-top point-up — never rotated. */
|
|
110
|
+
.deco {
|
|
111
|
+
position: absolute;
|
|
112
|
+
background: var(--c-cobalt-100);
|
|
113
|
+
clip-path: var(--hex-pointy-top);
|
|
114
|
+
pointer-events: none;
|
|
115
|
+
z-index: 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.deco1 {
|
|
119
|
+
width: 220px;
|
|
120
|
+
height: 254px;
|
|
121
|
+
right: -60px;
|
|
122
|
+
top: -40px;
|
|
123
|
+
opacity: 0.7;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.deco2 {
|
|
127
|
+
width: 110px;
|
|
128
|
+
height: 127px;
|
|
129
|
+
right: 80px;
|
|
130
|
+
bottom: -30px;
|
|
131
|
+
opacity: 0.5;
|
|
132
|
+
background: var(--c-cobalt-200);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.deco3 {
|
|
136
|
+
width: 56px;
|
|
137
|
+
height: 65px;
|
|
138
|
+
right: 220px;
|
|
139
|
+
top: 18px;
|
|
140
|
+
opacity: 0.5;
|
|
141
|
+
background: var(--c-cobalt-200);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@media (max-width: 720px) {
|
|
145
|
+
.deco1 { right: -100px; top: -80px; }
|
|
146
|
+
.deco2, .deco3 { display: none; }
|
|
147
|
+
}
|
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
* - "What do I need before I start?" (Prerequisites)
|
|
11
11
|
* - the actual tutorial body
|
|
12
12
|
*
|
|
13
|
-
* Visual:
|
|
14
|
-
* uses an orange checkmark glyph
|
|
15
|
-
* hex bullet (need)
|
|
13
|
+
* Visual: shared <HexCard> shell with a lightbulb icon in the
|
|
14
|
+
* top-left badge. Each item uses an orange checkmark glyph
|
|
15
|
+
* (achievement) instead of the orange hex bullet (need) used in
|
|
16
|
+
* <Prerequisites />. Same surface, distinct semantics.
|
|
16
17
|
*
|
|
17
18
|
* Usage:
|
|
18
19
|
*
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
*/
|
|
28
29
|
|
|
29
30
|
import React from 'react';
|
|
31
|
+
import HexCard from '../HexCard/HexCard';
|
|
30
32
|
import styles from './Outcomes.module.css';
|
|
31
33
|
|
|
32
34
|
export function Outcome({children, className}) {
|
|
@@ -44,11 +46,9 @@ export function Outcome({children, className}) {
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export default function Outcomes({title = "What you'll learn", children, className}) {
|
|
47
|
-
const composed = [styles.card, className].filter(Boolean).join(' ');
|
|
48
49
|
return (
|
|
49
|
-
<
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
</aside>
|
|
50
|
+
<HexCard title={title} icon="lightbulb" className={className}>
|
|
51
|
+
<ul>{children}</ul>
|
|
52
|
+
</HexCard>
|
|
53
53
|
);
|
|
54
54
|
}
|
|
@@ -1,29 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
padding: var(--space-6) var(--space-7);
|
|
6
|
-
margin: var(--space-8) 0;
|
|
7
|
-
font-family: var(--conduction-typography-font-family-body);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
.title {
|
|
11
|
-
font-size: 22px;
|
|
12
|
-
font-weight: 700;
|
|
13
|
-
letter-spacing: -0.01em;
|
|
14
|
-
color: var(--c-cobalt-900);
|
|
15
|
-
margin: 0 0 var(--space-4);
|
|
16
|
-
line-height: 1.25;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
.list {
|
|
20
|
-
list-style: none;
|
|
21
|
-
padding: 0;
|
|
22
|
-
margin: 0;
|
|
23
|
-
display: grid;
|
|
24
|
-
gap: var(--space-3);
|
|
25
|
-
max-width: none;
|
|
26
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* <Outcomes /> styles. The shell is provided by <HexCard>; only the
|
|
3
|
+
* orange-checkmark item layout lives here.
|
|
4
|
+
*/
|
|
27
5
|
|
|
28
6
|
.item {
|
|
29
7
|
display: grid;
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* starting an academy tutorial. Replaces the ad-hoc "What you need"
|
|
6
6
|
* h2 + bullet list pattern that was duplicated across tutorials.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Visual: shared <HexCard> shell with a clipboard icon in the
|
|
9
|
+
* top-left badge. Each item renders with a small orange hex-bullet
|
|
10
|
+
* on the left so the list reads as a checklist instead of generic
|
|
11
|
+
* prose.
|
|
12
12
|
*
|
|
13
13
|
* Usage:
|
|
14
14
|
*
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import React from 'react';
|
|
28
|
+
import HexCard from '../HexCard/HexCard';
|
|
28
29
|
import styles from './Prerequisites.module.css';
|
|
29
30
|
|
|
30
31
|
export function PrerequisiteItem({children, className}) {
|
|
@@ -38,11 +39,9 @@ export function PrerequisiteItem({children, className}) {
|
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export default function Prerequisites({title = 'What you need', children, className}) {
|
|
41
|
-
const composed = [styles.card, className].filter(Boolean).join(' ');
|
|
42
42
|
return (
|
|
43
|
-
<
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
</aside>
|
|
43
|
+
<HexCard title={title} icon="clipboard" className={className}>
|
|
44
|
+
<ul>{children}</ul>
|
|
45
|
+
</HexCard>
|
|
47
46
|
);
|
|
48
47
|
}
|
|
@@ -1,28 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
padding: var(--space-6) var(--space-7);
|
|
6
|
-
margin: var(--space-10) 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
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* <Prerequisites /> styles. The shell is provided by <HexCard>; only
|
|
3
|
+
* the orange hex-bullet item layout lives here.
|
|
4
|
+
*/
|
|
26
5
|
|
|
27
6
|
.item {
|
|
28
7
|
display: grid;
|
|
@@ -39,7 +18,7 @@
|
|
|
39
18
|
height: 14px;
|
|
40
19
|
margin-top: 6px;
|
|
41
20
|
background: var(--c-orange-knvb);
|
|
42
|
-
clip-path:
|
|
21
|
+
clip-path: var(--hex-pointy-top);
|
|
43
22
|
flex-shrink: 0;
|
|
44
23
|
}
|
|
45
24
|
|
package/src/components/index.js
CHANGED
|
@@ -99,6 +99,7 @@ export {default as ContentDetailHero} from './ContentDetailHero/ContentDetailHer
|
|
|
99
99
|
"What you need", "Troubleshooting", and "Next steps" h2 + bullet
|
|
100
100
|
patterns that academy tutorials kept duplicating. Designed for use
|
|
101
101
|
inside an MDX academy post body. */
|
|
102
|
+
export {default as HexCard} from './HexCard/HexCard.jsx';
|
|
102
103
|
export {default as Outcomes, Outcome} from './Outcomes/Outcomes.jsx';
|
|
103
104
|
export {default as Prerequisites, PrerequisiteItem} from './Prerequisites/Prerequisites.jsx';
|
|
104
105
|
export {default as Troubleshooting, TroubleshootingItem} from './Troubleshooting/Troubleshooting.jsx';
|
package/src/css/tokens.css
CHANGED
|
@@ -1,12 +1,448 @@
|
|
|
1
|
-
|
|
2
|
-
*
|
|
1
|
+
/* AUTO-GENERATED by docusaurus-preset/scripts/prepack-bundle-css.js
|
|
2
|
+
* during `npm publish`. Bundles the design-system monorepo's canonical
|
|
3
|
+
* tokens.css + typography.css into a self-contained file so consumer
|
|
4
|
+
* sites can resolve the imports through node_modules.
|
|
3
5
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* When the preset is published to npm, this file becomes the bundled
|
|
9
|
-
* copy; until then it imports relatively from the workspace.
|
|
6
|
+
* Do NOT edit this file in a published version. The working-tree
|
|
7
|
+
* src/css/tokens.css keeps the relative-import version that points
|
|
8
|
+
* back at the monorepo's source of truth.
|
|
10
9
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
|
|
11
|
+
/* ============================================================
|
|
12
|
+
Conduction Design System — theme-conduction-2026
|
|
13
|
+
Generated from brand/tokens.json (DTCG)
|
|
14
|
+
============================================================ */
|
|
15
|
+
|
|
16
|
+
/* Fonts: Figtree (body+heading), IBM Plex Mono (code) — both OFL */
|
|
17
|
+
@import url("https://fonts.googleapis.com/css2?family=Figtree:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap");
|
|
18
|
+
|
|
19
|
+
:root {
|
|
20
|
+
/* ---------- Color primitives ---------- */
|
|
21
|
+
--c-blue-cobalt: #21468B; /* Dutch flag blue — primary brand */
|
|
22
|
+
--c-orange-knvb: #F36C21; /* KNVB orange — accent */
|
|
23
|
+
--c-red-vermillion: #AE1C28; /* Dutch flag red — sparingly */
|
|
24
|
+
--c-white: #FFFFFF;
|
|
25
|
+
--c-nextcloud-blue: #0082C9; /* Nextcloud official */
|
|
26
|
+
--c-nextcloud-cyan: #1CAFFF; /* Nextcloud gradient end */
|
|
27
|
+
--gradient-nextcloud: linear-gradient(45deg, #0082C9, #1CAFFF);
|
|
28
|
+
--c-commonground-yellow: #F6AD00; /* Common Ground official, commonground.nl */
|
|
29
|
+
|
|
30
|
+
/* Cobalt tints — derived for surfaces, hex-prism faces, soft fills */
|
|
31
|
+
--c-cobalt-50: #EEF2F8;
|
|
32
|
+
--c-cobalt-100: #DCE3F0;
|
|
33
|
+
--c-cobalt-200: #B6C2DD;
|
|
34
|
+
--c-cobalt-300: #8095BD;
|
|
35
|
+
--c-cobalt-400: #4D69A4;
|
|
36
|
+
--c-cobalt-500: #21468B; /* = primary */
|
|
37
|
+
--c-cobalt-600: #1B3A75;
|
|
38
|
+
--c-cobalt-700: #152D5C;
|
|
39
|
+
--c-cobalt-800: #102246;
|
|
40
|
+
--c-cobalt-900: #0A172F;
|
|
41
|
+
|
|
42
|
+
/* Pastel families for hex-prism categories (per visual-motifs.md)
|
|
43
|
+
Each family has FIVE roles for prism construction:
|
|
44
|
+
-50 ultra-light wash (ground / page bg accents)
|
|
45
|
+
-100 top-face fill (the "lit" face you see in plan view)
|
|
46
|
+
-300 left-face fill (the slightly shaded vertical face)
|
|
47
|
+
-500 right-face / stroke (the deeper vertical face + outlines)
|
|
48
|
+
-700 ink — text on prism, pill outline, chip text
|
|
49
|
+
|
|
50
|
+
PRISM-FAMILY POLICY (locked 2026-04):
|
|
51
|
+
Component prisms get ONE of: lavender, mint, forest, terracotta.
|
|
52
|
+
The workspace prism uses workspace-blue (= Nextcloud's own brand blue).
|
|
53
|
+
Cobalt is brand chrome, NOT a prism family.
|
|
54
|
+
"Kernel" is a banned word in the brand vocabulary (see
|
|
55
|
+
identity/voice.html); use "workspace" everywhere.
|
|
56
|
+
Coral, gold, gray are NOT prism families. They serve different jobs:
|
|
57
|
+
· coral = KNVB-orange accent (focus, hover, single-use highlights). ≤ 8 % page area.
|
|
58
|
+
· gold = "Conduction Certified" mark ONLY. Never on a generic prism.
|
|
59
|
+
· gray = neutral surfaces / strokes. Not a category.
|
|
60
|
+
*/
|
|
61
|
+
|
|
62
|
+
/* — Component family 1: lavender (process / workflow) — */
|
|
63
|
+
--c-lavender-50: #F6F2FC;
|
|
64
|
+
--c-lavender-100: #ECE6F8;
|
|
65
|
+
--c-lavender-300: #B7A7E3;
|
|
66
|
+
--c-lavender-500: #7E66C9;
|
|
67
|
+
--c-lavender-700: #483982;
|
|
68
|
+
|
|
69
|
+
/* — Component family 2: mint (integrate / connect) — */
|
|
70
|
+
--c-mint-50: #EAF7F0;
|
|
71
|
+
--c-mint-100: #DCF1E6;
|
|
72
|
+
--c-mint-300: #87CFA8;
|
|
73
|
+
--c-mint-500: #2E9866;
|
|
74
|
+
--c-mint-700: #155234;
|
|
75
|
+
|
|
76
|
+
/* — Component family 3: forest (data / trustworthy / NLDS-compliant)
|
|
77
|
+
Distinct from mint — deeper, denser, more "official." Use
|
|
78
|
+
this for prisms that handle data and registers. — */
|
|
79
|
+
--c-forest-50: #EEF5EE;
|
|
80
|
+
--c-forest-100: #D7E8D6;
|
|
81
|
+
--c-forest-300: #7DAA7C;
|
|
82
|
+
--c-forest-500: #3D7C3A;
|
|
83
|
+
--c-forest-700: #1E461C;
|
|
84
|
+
|
|
85
|
+
/* — Component family 4: terracotta (documents / human work)
|
|
86
|
+
Tuned around the brand vermillion (#AE1C28) as its 700-deep,
|
|
87
|
+
so it ties to the Dutch flag without the "alarm" of pure red. — */
|
|
88
|
+
--c-terracotta-50: #FBF1EE;
|
|
89
|
+
--c-terracotta-100: #F4DCD3;
|
|
90
|
+
--c-terracotta-300: #DA9D8A;
|
|
91
|
+
--c-terracotta-500: #B25E48;
|
|
92
|
+
--c-terracotta-700: #6E2A1C;
|
|
93
|
+
|
|
94
|
+
/* — Workspace family: workspace-blue (= Nextcloud's own brand blue tints) — */
|
|
95
|
+
--c-workspaceblue-50: #E5F2FA;
|
|
96
|
+
--c-workspaceblue-100: #C8E5F5;
|
|
97
|
+
--c-workspaceblue-300: #67BEEA;
|
|
98
|
+
--c-workspaceblue-500: #0082C9; /* Nextcloud blue */
|
|
99
|
+
--c-workspaceblue-700: #014C77;
|
|
100
|
+
|
|
101
|
+
/* ----- Reserved colors (NOT prism families) -----
|
|
102
|
+
Kept in tokens because they have specific jobs elsewhere. */
|
|
103
|
+
|
|
104
|
+
/* Coral = KNVB orange accent only — focus rings, hover, occasional highlight. */
|
|
105
|
+
--c-coral-50: #FFF3ED;
|
|
106
|
+
--c-coral-100: #FFE4DA;
|
|
107
|
+
--c-coral-300: #FAB29C;
|
|
108
|
+
--c-coral-500: #F36C21; /* = KNVB */
|
|
109
|
+
--c-coral-700: #9B3A0E;
|
|
110
|
+
|
|
111
|
+
/* Gold = Conduction Certified mark ONLY. Reserved for the cert avatar
|
|
112
|
+
and trustmark badges. Do not use as a generic family color. */
|
|
113
|
+
--c-gold-50: #FDF8E8;
|
|
114
|
+
--c-gold-100: #FBF1D5;
|
|
115
|
+
--c-gold-300: #ECC668;
|
|
116
|
+
--c-gold-500: #C99A1F;
|
|
117
|
+
--c-gold-700: #765806;
|
|
118
|
+
|
|
119
|
+
/* Gray = neutral surfaces, strokes, side-box chrome. Not a category. */
|
|
120
|
+
--c-gray-50: #F4F5F8;
|
|
121
|
+
--c-gray-100: #ECEEF2;
|
|
122
|
+
--c-gray-300: #B7BDC9;
|
|
123
|
+
--c-gray-500: #6B7280;
|
|
124
|
+
--c-gray-700: #3A4150;
|
|
125
|
+
|
|
126
|
+
/* Workspace family alias — points to workspace-blue (Nextcloud).
|
|
127
|
+
The hex-prism API stays uniform: --c-workspace-{50,100,300,500,700} */
|
|
128
|
+
--c-workspace-50: var(--c-workspaceblue-50);
|
|
129
|
+
--c-workspace-100: var(--c-workspaceblue-100);
|
|
130
|
+
--c-workspace-300: var(--c-workspaceblue-300);
|
|
131
|
+
--c-workspace-500: var(--c-workspaceblue-500);
|
|
132
|
+
--c-workspace-700: var(--c-workspaceblue-700);
|
|
133
|
+
|
|
134
|
+
/* ---------- Semantic theme.conduction-2026 ---------- */
|
|
135
|
+
/* Brand */
|
|
136
|
+
--conduction-color-brand-primary: var(--c-blue-cobalt);
|
|
137
|
+
--conduction-color-brand-secondary: var(--c-orange-knvb);
|
|
138
|
+
--conduction-color-brand-tertiary: var(--c-red-vermillion);
|
|
139
|
+
--conduction-color-brand-nextcloud: var(--c-nextcloud-blue);
|
|
140
|
+
--conduction-color-brand-commonground: var(--c-commonground-yellow);
|
|
141
|
+
|
|
142
|
+
/* Background */
|
|
143
|
+
--conduction-color-background-default: var(--c-white);
|
|
144
|
+
--conduction-color-background-inverse: var(--c-blue-cobalt);
|
|
145
|
+
--conduction-color-background-muted: var(--c-cobalt-50);
|
|
146
|
+
|
|
147
|
+
/* Text */
|
|
148
|
+
--conduction-color-text-default: var(--c-blue-cobalt);
|
|
149
|
+
--conduction-color-text-inverse: var(--c-white);
|
|
150
|
+
--conduction-color-text-accent: var(--c-orange-knvb);
|
|
151
|
+
--conduction-color-text-muted: var(--c-cobalt-400);
|
|
152
|
+
|
|
153
|
+
/* Link */
|
|
154
|
+
--conduction-color-link-default: var(--c-blue-cobalt);
|
|
155
|
+
--conduction-color-link-hover: var(--c-orange-knvb);
|
|
156
|
+
|
|
157
|
+
/* Status */
|
|
158
|
+
--conduction-color-status-error: var(--c-red-vermillion);
|
|
159
|
+
|
|
160
|
+
/* Border */
|
|
161
|
+
--conduction-color-border-default: var(--c-cobalt-200);
|
|
162
|
+
--conduction-color-border-strong: var(--c-blue-cobalt);
|
|
163
|
+
|
|
164
|
+
/* ---------- Typography primitives ---------- */
|
|
165
|
+
--conduction-typography-font-family-body: 'Figtree', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
166
|
+
--conduction-typography-font-family-heading: 'Figtree', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
167
|
+
--conduction-typography-font-family-code: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
168
|
+
|
|
169
|
+
--fw-regular: 400;
|
|
170
|
+
--fw-medium: 500;
|
|
171
|
+
--fw-semibold: 600;
|
|
172
|
+
--fw-bold: 700;
|
|
173
|
+
|
|
174
|
+
--fs-xs: 12px;
|
|
175
|
+
--fs-sm: 14px;
|
|
176
|
+
--fs-base: 16px;
|
|
177
|
+
--fs-lg: 18px;
|
|
178
|
+
--fs-xl: 20px;
|
|
179
|
+
--fs-2xl: 24px;
|
|
180
|
+
--fs-3xl: 32px;
|
|
181
|
+
--fs-4xl: 40px;
|
|
182
|
+
--fs-5xl: 48px;
|
|
183
|
+
|
|
184
|
+
--lh-tight: 1.2;
|
|
185
|
+
--lh-normal: 1.5;
|
|
186
|
+
--lh-relaxed: 1.75;
|
|
187
|
+
|
|
188
|
+
/* ---------- Spacing (proposed scope-B) ---------- */
|
|
189
|
+
--space-1: 4px;
|
|
190
|
+
--space-2: 8px;
|
|
191
|
+
--space-3: 12px;
|
|
192
|
+
--space-4: 16px;
|
|
193
|
+
--space-5: 20px;
|
|
194
|
+
--space-6: 24px;
|
|
195
|
+
--space-8: 32px;
|
|
196
|
+
--space-10: 40px;
|
|
197
|
+
--space-12: 48px;
|
|
198
|
+
--space-16: 64px;
|
|
199
|
+
--space-20: 80px;
|
|
200
|
+
--space-24: 96px;
|
|
201
|
+
|
|
202
|
+
/* ---------- Radii ---------- */
|
|
203
|
+
--radius-sm: 4px;
|
|
204
|
+
--radius-md: 6px; /* default for buttons/inputs */
|
|
205
|
+
--radius-lg: 10px;
|
|
206
|
+
--radius-xl: 16px;
|
|
207
|
+
--radius-pill: 999px;
|
|
208
|
+
|
|
209
|
+
/* ---------- Shadows (subtle, brand-quiet) ---------- */
|
|
210
|
+
--shadow-1: 0 1px 2px rgba(33, 70, 139, 0.08);
|
|
211
|
+
--shadow-2: 0 2px 8px rgba(33, 70, 139, 0.10);
|
|
212
|
+
--shadow-3: 0 8px 24px rgba(33, 70, 139, 0.12);
|
|
213
|
+
|
|
214
|
+
/* ---------- Hex motif clip-paths ---------- */
|
|
215
|
+
--hex-pointy-top: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
|
|
216
|
+
|
|
217
|
+
/* ---------- Cut-corner clip-paths ---------- */
|
|
218
|
+
/* Triangular bevels mimic the hex motif on rectangles —
|
|
219
|
+
use these instead of (or in addition to) border-radius for
|
|
220
|
+
panels, cards, hero containers, modals. Use the size-specific
|
|
221
|
+
vars below; the polygon strings are inlined per size because
|
|
222
|
+
polygon() does not re-resolve var() at use time. */
|
|
223
|
+
--cut-sm: 6px;
|
|
224
|
+
--cut-md: 10px;
|
|
225
|
+
--cut-lg: 16px;
|
|
226
|
+
--cut-xl: 24px;
|
|
227
|
+
|
|
228
|
+
/* Top-left + bottom-right cut — diagonal asymmetry, our default */
|
|
229
|
+
--clip-cut-tlbr-sm: polygon( 6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
|
|
230
|
+
--clip-cut-tlbr-md: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
|
|
231
|
+
--clip-cut-tlbr-lg: polygon(16px 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%, 0 16px);
|
|
232
|
+
--clip-cut-tlbr-xl: polygon(24px 0, 100% 0, 100% calc(100% - 24px), calc(100% - 24px) 100%, 0 100%, 0 24px);
|
|
233
|
+
--clip-cut-tlbr: var(--clip-cut-tlbr-md);
|
|
234
|
+
|
|
235
|
+
/* Top-right + bottom-left cut — mirror */
|
|
236
|
+
--clip-cut-trbl-sm: polygon(0 0, calc(100% - 6px) 0, 100% 6px, 100% 100%, 6px 100%, 0 calc(100% - 6px));
|
|
237
|
+
--clip-cut-trbl-md: polygon(0 0, calc(100% - 10px) 0, 100% 10px, 100% 100%, 10px 100%, 0 calc(100% - 10px));
|
|
238
|
+
--clip-cut-trbl-lg: polygon(0 0, calc(100% - 16px) 0, 100% 16px, 100% 100%, 16px 100%, 0 calc(100% - 16px));
|
|
239
|
+
--clip-cut-trbl-xl: polygon(0 0, calc(100% - 24px) 0, 100% 24px, 100% 100%, 24px 100%, 0 calc(100% - 24px));
|
|
240
|
+
--clip-cut-trbl: var(--clip-cut-trbl-md);
|
|
241
|
+
|
|
242
|
+
/* All four corners cut */
|
|
243
|
+
--clip-cut-all-sm: polygon( 6px 0, calc(100% - 6px) 0, 100% 6px, 100% calc(100% - 6px), calc(100% - 6px) 100%, 6px 100%, 0 calc(100% - 6px), 0 6px);
|
|
244
|
+
--clip-cut-all-md: polygon(10px 0, calc(100% - 10px) 0, 100% 10px, 100% calc(100% - 10px), calc(100% - 10px) 100%, 10px 100%, 0 calc(100% - 10px), 0 10px);
|
|
245
|
+
--clip-cut-all-lg: polygon(16px 0, calc(100% - 16px) 0, 100% 16px, 100% calc(100% - 16px), calc(100% - 16px) 100%, 16px 100%, 0 calc(100% - 16px), 0 16px);
|
|
246
|
+
--clip-cut-all-xl: polygon(24px 0, calc(100% - 24px) 0, 100% 24px, 100% calc(100% - 24px), calc(100% - 24px) 100%, 24px 100%, 0 calc(100% - 24px), 0 24px);
|
|
247
|
+
--clip-cut-all: var(--clip-cut-all-md);
|
|
248
|
+
|
|
249
|
+
/* ============================================================
|
|
250
|
+
Print + paper sizes
|
|
251
|
+
----------------------------------------------------------------
|
|
252
|
+
Real-world dimensions in millimetres. The HTML preview renders
|
|
253
|
+
these as on-screen mock-ups; the print stylesheet at the bottom
|
|
254
|
+
of each artefact maps them to @page rules. No bleed yet —
|
|
255
|
+
--bleed is plumbed at 0 and will flip to 3mm when we move to
|
|
256
|
+
real print runs. Don't bake bleed into individual layouts;
|
|
257
|
+
reference the token. */
|
|
258
|
+
|
|
259
|
+
/* Paper formats — width / height */
|
|
260
|
+
--paper-a4-w: 210mm;
|
|
261
|
+
--paper-a4-h: 297mm;
|
|
262
|
+
--paper-a5-w: 148mm;
|
|
263
|
+
--paper-a5-h: 210mm;
|
|
264
|
+
--paper-a3-w: 297mm;
|
|
265
|
+
--paper-a3-h: 420mm;
|
|
266
|
+
|
|
267
|
+
/* Business card — Dutch / European standard */
|
|
268
|
+
--card-w: 85mm;
|
|
269
|
+
--card-h: 55mm;
|
|
270
|
+
|
|
271
|
+
/* Envelopes */
|
|
272
|
+
--env-c5-w: 229mm;
|
|
273
|
+
--env-c5-h: 162mm;
|
|
274
|
+
--env-c4-w: 324mm;
|
|
275
|
+
--env-c4-h: 229mm;
|
|
276
|
+
--env-dl-w: 220mm;
|
|
277
|
+
--env-dl-h: 110mm;
|
|
278
|
+
|
|
279
|
+
/* Slide deck — 16:9 landscape, 1280×720 nominal at 96dpi */
|
|
280
|
+
--slide-w: 338.67mm; /* 1280px → mm */
|
|
281
|
+
--slide-h: 190.5mm; /* 720px → mm */
|
|
282
|
+
--slide-w-px: 1280px;
|
|
283
|
+
--slide-h-px: 720px;
|
|
284
|
+
|
|
285
|
+
/* Banner / signage — placed on screen, scale to real-world print later */
|
|
286
|
+
--banner-rollup-w: 850mm; /* 85cm × 200cm pull-up */
|
|
287
|
+
--banner-rollup-h: 2000mm;
|
|
288
|
+
--banner-event-w: 3000mm; /* 3m × 2m event backdrop */
|
|
289
|
+
--banner-event-h: 2000mm;
|
|
290
|
+
|
|
291
|
+
/* Web banners — pixel-native, kept here for one source of truth */
|
|
292
|
+
--banner-linkedin-w: 1584px;
|
|
293
|
+
--banner-linkedin-h: 396px;
|
|
294
|
+
--banner-x-w: 1500px;
|
|
295
|
+
--banner-x-h: 500px;
|
|
296
|
+
--banner-fb-w: 820px;
|
|
297
|
+
--banner-fb-h: 312px;
|
|
298
|
+
|
|
299
|
+
/* mm-based spacing for paper layouts (4mm step) */
|
|
300
|
+
--space-mm-1: 2mm;
|
|
301
|
+
--space-mm-2: 4mm;
|
|
302
|
+
--space-mm-3: 6mm;
|
|
303
|
+
--space-mm-4: 8mm;
|
|
304
|
+
--space-mm-5: 10mm;
|
|
305
|
+
--space-mm-6: 12mm;
|
|
306
|
+
--space-mm-8: 16mm;
|
|
307
|
+
--space-mm-10: 20mm;
|
|
308
|
+
--space-mm-12: 24mm;
|
|
309
|
+
|
|
310
|
+
/* Bleed — 0 on screen, flip to 3mm when sending to a real printer.
|
|
311
|
+
Keep this token referenced from artefact stylesheets (not hard-
|
|
312
|
+
coded) so the change is one place. */
|
|
313
|
+
--bleed: 0mm;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* ============================================================
|
|
317
|
+
Base typography
|
|
318
|
+
============================================================ */
|
|
319
|
+
html { font-family: var(--conduction-typography-font-family-body); }
|
|
320
|
+
body {
|
|
321
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
322
|
+
font-size: var(--fs-base);
|
|
323
|
+
line-height: var(--lh-normal);
|
|
324
|
+
color: var(--conduction-color-text-default);
|
|
325
|
+
background: var(--conduction-color-background-default);
|
|
326
|
+
-webkit-font-smoothing: antialiased;
|
|
327
|
+
text-rendering: optimizeLegibility;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
h1, h2, h3, h4, h5, h6 {
|
|
331
|
+
font-family: var(--conduction-typography-font-family-heading);
|
|
332
|
+
color: var(--conduction-color-text-default);
|
|
333
|
+
line-height: var(--lh-tight);
|
|
334
|
+
margin: 0;
|
|
335
|
+
text-wrap: balance;
|
|
336
|
+
}
|
|
337
|
+
h1 { font-size: var(--fs-5xl); font-weight: var(--fw-bold); letter-spacing: -0.02em; }
|
|
338
|
+
h2 { font-size: var(--fs-4xl); font-weight: var(--fw-bold); letter-spacing: -0.015em; }
|
|
339
|
+
h3 { font-size: var(--fs-3xl); font-weight: var(--fw-semibold); letter-spacing: -0.01em; }
|
|
340
|
+
h4 { font-size: var(--fs-2xl); font-weight: var(--fw-semibold); }
|
|
341
|
+
h5 { font-size: var(--fs-xl); font-weight: var(--fw-semibold); }
|
|
342
|
+
h6 { font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
|
|
343
|
+
|
|
344
|
+
p { margin: 0; text-wrap: pretty; }
|
|
345
|
+
|
|
346
|
+
code, kbd, samp, pre {
|
|
347
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
348
|
+
font-size: 0.92em;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
a {
|
|
352
|
+
color: var(--conduction-color-link-default);
|
|
353
|
+
text-decoration: underline;
|
|
354
|
+
text-decoration-thickness: 1px;
|
|
355
|
+
text-underline-offset: 2px;
|
|
356
|
+
transition: color 120ms ease;
|
|
357
|
+
}
|
|
358
|
+
a:hover { color: var(--conduction-color-link-hover); }
|
|
359
|
+
|
|
360
|
+
/* ============================================================
|
|
361
|
+
Brand-citation: "Next" in Nextcloud-blue
|
|
362
|
+
============================================================ */
|
|
363
|
+
.next-blue { color: var(--conduction-color-brand-nextcloud); }
|
|
364
|
+
.cg-yellow { color: var(--conduction-color-brand-commonground); }
|
|
365
|
+
|
|
366
|
+
/* ============================================================
|
|
367
|
+
Hex-pattern background utility
|
|
368
|
+
----------------------------------------------------------------
|
|
369
|
+
A subtle pointy-top hexagon lattice for footers, section dividers,
|
|
370
|
+
empty states. The lattice itself is an inline SVG data-URI, tiled.
|
|
371
|
+
Use the convenience classes below or set the custom properties
|
|
372
|
+
directly on any element:
|
|
373
|
+
|
|
374
|
+
.hex-pattern default cobalt-100 lines @ ~6% opacity
|
|
375
|
+
.hex-pattern--soft barely-there (4%) — for footers
|
|
376
|
+
.hex-pattern--bold visible (12%) — for empty states / dividers
|
|
377
|
+
|
|
378
|
+
Override:
|
|
379
|
+
style="--hex-pattern-color: #21468B; --hex-pattern-opacity: 0.08;"
|
|
380
|
+
|
|
381
|
+
The pattern repeats at 56px, which matches our spacing rhythm
|
|
382
|
+
(multiple of --space-4 / --space-8). Don't go below 4% opacity or
|
|
383
|
+
the texture disappears at small sizes; don't go above 14% or it
|
|
384
|
+
fights the foreground.
|
|
385
|
+
============================================================ */
|
|
386
|
+
.hex-pattern,
|
|
387
|
+
.hex-pattern--soft,
|
|
388
|
+
.hex-pattern--bold {
|
|
389
|
+
--hex-pattern-color: var(--c-blue-cobalt);
|
|
390
|
+
--hex-pattern-opacity: 0.06;
|
|
391
|
+
background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='56' height='64' viewBox='0 0 56 64'><g fill='none' stroke='%2321468B' stroke-width='1'><path d='M28 1 L55 16 L55 48 L28 63 L1 48 L1 16 Z'/><path d='M0 32 L1 32 M55 32 L56 32'/></g></svg>");
|
|
392
|
+
background-size: 56px 64px;
|
|
393
|
+
background-repeat: repeat;
|
|
394
|
+
/* layer the color tint via a mask: easier — lower the whole bg's opacity */
|
|
395
|
+
background-blend-mode: multiply;
|
|
396
|
+
position: relative;
|
|
397
|
+
}
|
|
398
|
+
.hex-pattern::before,
|
|
399
|
+
.hex-pattern--soft::before,
|
|
400
|
+
.hex-pattern--bold::before {
|
|
401
|
+
content: "";
|
|
402
|
+
position: absolute;
|
|
403
|
+
inset: 0;
|
|
404
|
+
pointer-events: none;
|
|
405
|
+
background-image: inherit;
|
|
406
|
+
background-size: inherit;
|
|
407
|
+
background-repeat: inherit;
|
|
408
|
+
opacity: var(--hex-pattern-opacity);
|
|
409
|
+
}
|
|
410
|
+
.hex-pattern--soft { --hex-pattern-opacity: 0.04; }
|
|
411
|
+
.hex-pattern--bold { --hex-pattern-opacity: 0.12; }
|
|
412
|
+
/* When applied to a container, the pseudo-element handles the texture
|
|
413
|
+
so foreground content doesn't get tinted. Make children stack above: */
|
|
414
|
+
.hex-pattern > *,
|
|
415
|
+
.hex-pattern--soft > *,
|
|
416
|
+
.hex-pattern--bold > * { position: relative; z-index: 1; }
|
|
417
|
+
/* Strip the base-image (we paint via ::before only) so blend-mode
|
|
418
|
+
doesn't double up: */
|
|
419
|
+
.hex-pattern, .hex-pattern--soft, .hex-pattern--bold {
|
|
420
|
+
background-image: none;
|
|
421
|
+
background-blend-mode: normal;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/* Typography & colour defaults, applied via the semantic tokens.
|
|
425
|
+
Pages link this alongside tokens.css. Per-page CSS only overrides
|
|
426
|
+
when a surface needs something other than the brand default
|
|
427
|
+
(e.g. white text on a cobalt panel). */
|
|
428
|
+
|
|
429
|
+
@import url("./tokens.css");
|
|
430
|
+
|
|
431
|
+
body {
|
|
432
|
+
color: var(--conduction-color-text-default);
|
|
433
|
+
font-family: var(--conduction-typography-font-family-body);
|
|
434
|
+
-webkit-font-smoothing: antialiased;
|
|
435
|
+
text-rendering: optimizeLegibility;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
h1, h2, h3, h4, h5, h6 {
|
|
439
|
+
color: var(--conduction-color-text-default);
|
|
440
|
+
font-family: var(--conduction-typography-font-family-heading);
|
|
441
|
+
margin: 0;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
a {
|
|
445
|
+
color: var(--conduction-color-link-default);
|
|
446
|
+
transition: color 140ms ease;
|
|
447
|
+
}
|
|
448
|
+
a:hover { color: var(--conduction-color-link-hover); }
|