@conduction/docusaurus-preset 1.2.1 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/docusaurus-preset",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "scripts": {
5
5
  "prepack": "node scripts/prepack-bundle-css.js"
6
6
  },
@@ -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. 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.
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
- export default function ContactCta({
40
- title,
41
- body,
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
- <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>
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
- {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>
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
- .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-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: tinted card identical to <Prerequisites />, but each item
14
- * uses an orange checkmark glyph (achievement) instead of the orange
15
- * hex bullet (need). Same tone, distinct semantics.
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
- <aside className={composed}>
50
- {title && <h2 className={styles.title}>{title}</h2>}
51
- <ul className={styles.list}>{children}</ul>
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
- .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-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
- * 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.
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
- <aside className={composed}>
44
- {title && <h2 className={styles.title}>{title}</h2>}
45
- <ul className={styles.list}>{children}</ul>
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
- .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-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: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
21
+ clip-path: var(--hex-pointy-top);
43
22
  flex-shrink: 0;
44
23
  }
45
24
 
@@ -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';