@conduction/docusaurus-preset 3.31.0 → 3.33.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/MISSING_COMPONENTS.md +6 -2
- package/package.json +1 -1
- package/src/components/BuildMock/BuildMock.jsx +101 -0
- package/src/components/BuildMock/BuildMock.module.css +290 -0
- package/src/components/DetailHero/DetailHero.jsx +68 -16
- package/src/components/DetailHero/DetailHero.module.css +31 -1
- package/src/components/FlowMock/FlowMock.jsx +151 -0
- package/src/components/FlowMock/FlowMock.module.css +164 -0
- package/src/components/KanbanMock/KanbanMock.jsx +149 -0
- package/src/components/KanbanMock/KanbanMock.module.css +325 -0
- package/src/components/KanbanMock/__tests__/KanbanMock.render.test.js +114 -0
- package/src/components/LeafMock/LeafMock.jsx +173 -0
- package/src/components/LeafMock/LeafMock.module.css +237 -0
- package/src/components/RotatingCards/RotatingCards.module.css +5 -2
- package/src/components/Showcase/Showcase.module.css +5 -2
- package/src/components/WidgetShelf/WidgetShelf.jsx +346 -14
- package/src/components/WidgetShelf/WidgetShelf.module.css +276 -5
- package/src/components/WidgetShelf/__tests__/WidgetShelf.render.test.js +149 -0
- package/src/components/index.js +4 -0
- package/src/components/primitives/SectionHead.module.css +6 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <FlowMock />
|
|
3
|
+
*
|
|
4
|
+
* Token-built abstract representation of the flow editor: white node
|
|
5
|
+
* cards on a dotted canvas, a coloured 4px left bar per node (mint =
|
|
6
|
+
* trigger, lavender = steps, vermillion = end), greeked title +
|
|
7
|
+
* mono subtitle lines, and curved grey edges with small pill labels
|
|
8
|
+
* between the nodes. Same abstraction level as <AppMock> (reference:
|
|
9
|
+
* honeycomb.io/technologies/*) — recognisable as the flow canvas,
|
|
10
|
+
* never a literal screenshot.
|
|
11
|
+
*
|
|
12
|
+
* Five nodes: trigger → two parallel steps → approval (join) → end.
|
|
13
|
+
* A mint run-line travels the trigger → step → approval → end route
|
|
14
|
+
* on a slow loop, with a subtle halo pulse on each node as the line
|
|
15
|
+
* passes. `prefers-reduced-motion: reduce` (and `running={false}`)
|
|
16
|
+
* renders the full route as a static mint path with no animation.
|
|
17
|
+
*
|
|
18
|
+
* Tokens only; no images; rectangles (the nodes *do* work, so no
|
|
19
|
+
* hexes); no orange accent used.
|
|
20
|
+
*
|
|
21
|
+
* Usage:
|
|
22
|
+
*
|
|
23
|
+
* <FlowMock />
|
|
24
|
+
* <FlowMock size="sm" caption="Automate" />
|
|
25
|
+
* <FlowMock running={false} />
|
|
26
|
+
*
|
|
27
|
+
* Props:
|
|
28
|
+
* - size: 'sm' | 'md' (default) — frame width, as AppMock
|
|
29
|
+
* - caption: string | true — small caption below the
|
|
30
|
+
* frame; `true` renders the default "Flow editor"
|
|
31
|
+
* - running: boolean (default true) — false freezes the
|
|
32
|
+
* run-line to the static full mint path
|
|
33
|
+
* - className: string
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import styles from './FlowMock.module.css';
|
|
38
|
+
|
|
39
|
+
/* The run-line route: trigger right port, up along the first edge,
|
|
40
|
+
across step A, down to the approval join, across it, into the end
|
|
41
|
+
node. pathLength="1" normalises the dash arithmetic so the CSS
|
|
42
|
+
animation is geometry-independent. */
|
|
43
|
+
const RUN_PATH =
|
|
44
|
+
'M164,211 C205,211 200,91 240,91 L380,91 C420,91 416,211 456,211 L596,211 C614,211 618,211 636,211';
|
|
45
|
+
|
|
46
|
+
/* Grey edges, drawn separately from the run-line so the second
|
|
47
|
+
(parallel) branch and the join edge stay visible under it. */
|
|
48
|
+
const EDGES = [
|
|
49
|
+
'M164,211 C205,211 200,91 240,91', /* trigger → step A */
|
|
50
|
+
'M164,211 C205,211 200,331 240,331', /* trigger → step B */
|
|
51
|
+
'M380,91 C420,91 416,211 456,211', /* step A → approval */
|
|
52
|
+
'M380,331 C420,331 416,211 456,211', /* step B → approval */
|
|
53
|
+
'M596,211 C614,211 618,211 636,211', /* approval → end */
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/* Small pill labels sitting mid-edge, greeked (a bar, not words). */
|
|
57
|
+
const PILLS = [
|
|
58
|
+
{cx: 202, cy: 151},
|
|
59
|
+
{cx: 202, cy: 271},
|
|
60
|
+
{cx: 418, cy: 151},
|
|
61
|
+
{cx: 418, cy: 271},
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/* Node cards. kind drives the left-bar colour class; pulse marks the
|
|
65
|
+
nodes the run-line passes (trigger, step A, approval, end). */
|
|
66
|
+
const NODES = [
|
|
67
|
+
{x: 24, y: 176, w: 140, h: 70, kind: 'trigger', label: 'Trigger', pulse: 0},
|
|
68
|
+
{x: 240, y: 56, w: 140, h: 70, kind: 'step', label: 'Step', pulse: 1},
|
|
69
|
+
{x: 240, y: 296, w: 140, h: 70, kind: 'step', label: 'Step'},
|
|
70
|
+
{x: 456, y: 172, w: 140, h: 78, kind: 'approval', label: 'Approval', pulse: 2},
|
|
71
|
+
{x: 636, y: 183, w: 62, h: 56, kind: 'end', label: 'End', pulse: 3},
|
|
72
|
+
];
|
|
73
|
+
|
|
74
|
+
function Node({node}) {
|
|
75
|
+
const {x, y, w, h, kind, label, pulse} = node;
|
|
76
|
+
const pad = 12;
|
|
77
|
+
const compact = w < 100;
|
|
78
|
+
return (
|
|
79
|
+
<g>
|
|
80
|
+
{pulse !== undefined && (
|
|
81
|
+
<rect
|
|
82
|
+
className={[styles.halo, styles[`halo-${pulse}`]].join(' ')}
|
|
83
|
+
x={x - 3} y={y - 3} width={w + 6} height={h + 6} rx={10}
|
|
84
|
+
/>
|
|
85
|
+
)}
|
|
86
|
+
<rect className={styles.card} x={x} y={y} width={w} height={h} rx={8} />
|
|
87
|
+
<rect className={[styles.bar, styles[`bar-${kind}`]].join(' ')} x={x + 3} y={y + 6} width={4} height={h - 12} rx={2} />
|
|
88
|
+
<text className={styles.kindLabel} x={x + pad} y={y + 18}>{label}</text>
|
|
89
|
+
{!compact && (
|
|
90
|
+
<>
|
|
91
|
+
<rect className={styles.titleGreek} x={x + pad} y={y + 26} width={w * 0.55} height={5} rx={1.5} />
|
|
92
|
+
<rect className={styles.subGreek} x={x + pad} y={y + 40} width={w * 0.68} height={3} rx={1} />
|
|
93
|
+
<rect className={styles.subGreek} x={x + pad} y={y + 48} width={w * 0.44} height={3} rx={1} />
|
|
94
|
+
</>
|
|
95
|
+
)}
|
|
96
|
+
{compact && (
|
|
97
|
+
<rect className={styles.subGreek} x={x + pad} y={y + 28} width={w - pad * 2} height={3} rx={1} />
|
|
98
|
+
)}
|
|
99
|
+
</g>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default function FlowMock({size = 'md', caption, running = true, className}) {
|
|
104
|
+
/* Unique pattern id per instance so several mocks on one page
|
|
105
|
+
don't collide on the dot-grid <pattern>. */
|
|
106
|
+
const dotsId = `fm-dots-${React.useId().replace(/[^a-zA-Z0-9-]/g, '')}`;
|
|
107
|
+
return (
|
|
108
|
+
<div className={styles.fm}>
|
|
109
|
+
<figure className={[styles.figure, className].filter(Boolean).join(' ')}>
|
|
110
|
+
<div className={[styles.frame, styles[`size-${size}`], !running && styles.static].filter(Boolean).join(' ')}>
|
|
111
|
+
<svg
|
|
112
|
+
className={styles.canvas}
|
|
113
|
+
viewBox="0 0 720 450"
|
|
114
|
+
role="img"
|
|
115
|
+
aria-label="Abstract flow-editor canvas: a trigger fans out to two parallel steps, joins at an approval, and ends."
|
|
116
|
+
>
|
|
117
|
+
<defs>
|
|
118
|
+
<pattern id={dotsId} width="16" height="16" patternUnits="userSpaceOnUse">
|
|
119
|
+
<circle className={styles.dot} cx="2" cy="2" r="1" />
|
|
120
|
+
</pattern>
|
|
121
|
+
</defs>
|
|
122
|
+
<rect className={styles.surface} x="0" y="0" width="720" height="450" />
|
|
123
|
+
<rect fill={`url(#${dotsId})`} x="0" y="0" width="720" height="450" />
|
|
124
|
+
|
|
125
|
+
{EDGES.map((d, i) => (
|
|
126
|
+
<path key={i} className={styles.edge} d={d} />
|
|
127
|
+
))}
|
|
128
|
+
|
|
129
|
+
<path className={styles.runline} d={RUN_PATH} pathLength="1" />
|
|
130
|
+
|
|
131
|
+
{PILLS.map((p, i) => (
|
|
132
|
+
<g key={i}>
|
|
133
|
+
<rect className={styles.pill} x={p.cx - 17} y={p.cy - 7} width={34} height={14} rx={7} />
|
|
134
|
+
<rect className={styles.pillGreek} x={p.cx - 9} y={p.cy - 1.5} width={18} height={3} rx={1} />
|
|
135
|
+
</g>
|
|
136
|
+
))}
|
|
137
|
+
|
|
138
|
+
{NODES.map((n, i) => (
|
|
139
|
+
<Node key={i} node={n} />
|
|
140
|
+
))}
|
|
141
|
+
</svg>
|
|
142
|
+
</div>
|
|
143
|
+
{caption && (
|
|
144
|
+
<figcaption className={styles.caption}>
|
|
145
|
+
{caption === true ? 'Flow editor' : caption}
|
|
146
|
+
</figcaption>
|
|
147
|
+
)}
|
|
148
|
+
</figure>
|
|
149
|
+
</div>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <FlowMock /> styles.
|
|
3
|
+
*
|
|
4
|
+
* Every rule is scoped under a `.fm` parent, the same convention as
|
|
5
|
+
* AppMock's `.am`: React wraps the mock in `<div className={styles.fm}>`,
|
|
6
|
+
* a static-HTML specimen wraps it in `<div class="fm">` and loads this
|
|
7
|
+
* file as a plain global stylesheet (CSS Modules keeps the literal
|
|
8
|
+
* selector text). `display: contents` keeps the scope wrapper
|
|
9
|
+
* transparent to layout.
|
|
10
|
+
*
|
|
11
|
+
* Tokens only. Node bars: mint = trigger, lavender = steps/approval,
|
|
12
|
+
* vermillion = end. The run-line is mint (--c-mint-500); no orange.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
.fm { display: contents; }
|
|
16
|
+
|
|
17
|
+
.fm .figure {
|
|
18
|
+
margin: 0;
|
|
19
|
+
display: inline-flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
gap: var(--space-2);
|
|
22
|
+
width: 100%;
|
|
23
|
+
max-width: 100%;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.fm .frame {
|
|
27
|
+
width: 100%;
|
|
28
|
+
max-width: 720px;
|
|
29
|
+
aspect-ratio: 16 / 10;
|
|
30
|
+
background: white;
|
|
31
|
+
border: 1px solid var(--c-cobalt-100);
|
|
32
|
+
border-radius: var(--radius-lg);
|
|
33
|
+
box-shadow: var(--shadow-3);
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
position: relative;
|
|
36
|
+
}
|
|
37
|
+
.fm .size-sm { max-width: 480px; }
|
|
38
|
+
.fm .size-md { max-width: 720px; }
|
|
39
|
+
|
|
40
|
+
.fm .canvas { display: block; width: 100%; height: 100%; }
|
|
41
|
+
|
|
42
|
+
.fm .caption {
|
|
43
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
44
|
+
font-size: 11px;
|
|
45
|
+
letter-spacing: 0.06em;
|
|
46
|
+
color: var(--c-cobalt-400);
|
|
47
|
+
text-transform: uppercase;
|
|
48
|
+
text-align: center;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* ---- Canvas ---- */
|
|
52
|
+
|
|
53
|
+
.fm .surface { fill: var(--c-cobalt-50); }
|
|
54
|
+
.fm .dot { fill: var(--c-cobalt-200); }
|
|
55
|
+
|
|
56
|
+
/* ---- Edges + pill labels ---- */
|
|
57
|
+
|
|
58
|
+
.fm .edge {
|
|
59
|
+
fill: none;
|
|
60
|
+
stroke: var(--c-cobalt-200);
|
|
61
|
+
stroke-width: 2;
|
|
62
|
+
stroke-linecap: round;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.fm .pill {
|
|
66
|
+
fill: white;
|
|
67
|
+
stroke: var(--c-cobalt-100);
|
|
68
|
+
stroke-width: 1;
|
|
69
|
+
}
|
|
70
|
+
.fm .pillGreek { fill: var(--c-cobalt-300); }
|
|
71
|
+
|
|
72
|
+
/* ---- Nodes ---- */
|
|
73
|
+
|
|
74
|
+
.fm .card {
|
|
75
|
+
fill: white;
|
|
76
|
+
stroke: var(--c-cobalt-100);
|
|
77
|
+
stroke-width: 1;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.fm .bar { fill: var(--c-cobalt-300); }
|
|
81
|
+
.fm .bar-trigger { fill: var(--c-mint-500); }
|
|
82
|
+
.fm .bar-step { fill: var(--c-lavender-500); }
|
|
83
|
+
.fm .bar-approval { fill: var(--c-lavender-500); }
|
|
84
|
+
.fm .bar-end { fill: var(--c-red-vermillion); }
|
|
85
|
+
|
|
86
|
+
.fm .kindLabel {
|
|
87
|
+
font-family: var(--conduction-typography-font-family-code);
|
|
88
|
+
font-size: 9px;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
letter-spacing: 0.08em;
|
|
91
|
+
text-transform: uppercase;
|
|
92
|
+
fill: var(--c-cobalt-400);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.fm .titleGreek { fill: var(--c-cobalt-700); }
|
|
96
|
+
.fm .subGreek { fill: var(--c-cobalt-200); }
|
|
97
|
+
|
|
98
|
+
/* ---- Run-line animation ----
|
|
99
|
+
*
|
|
100
|
+
* The route path carries pathLength="1", so the dash arithmetic is
|
|
101
|
+
* geometry-independent: a 0.28-long mint segment on a 1.28 period
|
|
102
|
+
* travels the full route once per cycle. Animating the offset from
|
|
103
|
+
* 1.28 to 0 shifts the pattern forward exactly one period, so the
|
|
104
|
+
* loop is seamless (the segment exits the end node as its successor
|
|
105
|
+
* enters the trigger). */
|
|
106
|
+
|
|
107
|
+
.fm .runline {
|
|
108
|
+
fill: none;
|
|
109
|
+
stroke: var(--c-mint-500);
|
|
110
|
+
stroke-width: 3;
|
|
111
|
+
stroke-linecap: round;
|
|
112
|
+
stroke-dasharray: 0.28 1;
|
|
113
|
+
stroke-dashoffset: 1.28;
|
|
114
|
+
animation: fmRun var(--fm-dur, 7s) linear infinite;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@keyframes fmRun {
|
|
118
|
+
from { stroke-dashoffset: 1.28; }
|
|
119
|
+
to { stroke-dashoffset: 0; }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Halo pulse on the nodes the run-line passes. Delays approximate
|
|
123
|
+
where along the route each node sits (trigger 0%, step ~30%,
|
|
124
|
+
approval ~62%, end ~85% of the cycle). */
|
|
125
|
+
.fm .halo {
|
|
126
|
+
fill: none;
|
|
127
|
+
stroke: var(--c-mint-500);
|
|
128
|
+
stroke-width: 2;
|
|
129
|
+
opacity: 0;
|
|
130
|
+
animation: fmPulse var(--fm-dur, 7s) linear infinite;
|
|
131
|
+
}
|
|
132
|
+
.fm .halo-0 { animation-delay: 0s; }
|
|
133
|
+
.fm .halo-1 { animation-delay: calc(var(--fm-dur, 7s) * 0.3); }
|
|
134
|
+
.fm .halo-2 { animation-delay: calc(var(--fm-dur, 7s) * 0.62); }
|
|
135
|
+
.fm .halo-3 { animation-delay: calc(var(--fm-dur, 7s) * 0.85); }
|
|
136
|
+
|
|
137
|
+
@keyframes fmPulse {
|
|
138
|
+
0% { opacity: 0; }
|
|
139
|
+
4% { opacity: 0.55; }
|
|
140
|
+
12% { opacity: 0; }
|
|
141
|
+
100% { opacity: 0; }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* ---- Static renderings ----
|
|
145
|
+
*
|
|
146
|
+
* Both `running={false}` (the .static class) and the user's
|
|
147
|
+
* prefers-reduced-motion setting freeze the mock to the full mint
|
|
148
|
+
* route with no dash travel and no pulse. */
|
|
149
|
+
|
|
150
|
+
.fm .static .runline {
|
|
151
|
+
animation: none;
|
|
152
|
+
stroke-dasharray: none;
|
|
153
|
+
stroke-dashoffset: 0;
|
|
154
|
+
}
|
|
155
|
+
.fm .static .halo { animation: none; opacity: 0; }
|
|
156
|
+
|
|
157
|
+
@media (prefers-reduced-motion: reduce) {
|
|
158
|
+
.fm .runline {
|
|
159
|
+
animation: none;
|
|
160
|
+
stroke-dasharray: none;
|
|
161
|
+
stroke-dashoffset: 0;
|
|
162
|
+
}
|
|
163
|
+
.fm .halo { animation: none; opacity: 0; }
|
|
164
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* <KanbanMock />
|
|
3
|
+
*
|
|
4
|
+
* Token-built abstract of the pipelinq kanban board with a looping
|
|
5
|
+
* drag animation: a cursor picks up the top lead card in the first
|
|
6
|
+
* column (the card lifts), drags it to the second column, drops it,
|
|
7
|
+
* and at the drop moment the column counts nudge (3→2, 2→3) and the
|
|
8
|
+
* per-lane € KPI tiles above the board shift the moved deal's value
|
|
9
|
+
* (€ 48k→€ 30k, € 27k→€ 45k; the third lane stays € 64k). Loops
|
|
10
|
+
* every ~7 seconds and resets cleanly at loop start. Pipelinq's
|
|
11
|
+
* hero/panel illustration.
|
|
12
|
+
*
|
|
13
|
+
* Named KanbanMock rather than PipelineMock because the preset
|
|
14
|
+
* already ships a `Pipeline` component (the hex-numbered process
|
|
15
|
+
* strip) and a `cn-pipeline` diagram; this one is the *board*.
|
|
16
|
+
*
|
|
17
|
+
* Same abstraction level as <AppMock>: greeked cards, tokens only,
|
|
18
|
+
* short labels at most, no orange. `prefers-reduced-motion: reduce`
|
|
19
|
+
* (and `running={false}`) renders the static board — no cursor, no
|
|
20
|
+
* lift, the card resting in its origin column.
|
|
21
|
+
*
|
|
22
|
+
* Usage:
|
|
23
|
+
*
|
|
24
|
+
* <KanbanMock />
|
|
25
|
+
* <KanbanMock size="sm" caption />
|
|
26
|
+
* <KanbanMock running={false} />
|
|
27
|
+
*
|
|
28
|
+
* Props:
|
|
29
|
+
* - size: 'sm' | 'md' (default) — frame width, as AppMock
|
|
30
|
+
* - caption: string | true — small label below the frame;
|
|
31
|
+
* `true` renders the default "Pipeline board"
|
|
32
|
+
* - running: boolean (default true) — false freezes the board
|
|
33
|
+
* - className: string
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import React from 'react';
|
|
37
|
+
import styles from './KanbanMock.module.css';
|
|
38
|
+
|
|
39
|
+
function CardGreek({wide, dot}) {
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<span className={styles.cardTop}>
|
|
43
|
+
<span className={styles.cardBar} style={{width: wide ? '72%' : '55%'}} />
|
|
44
|
+
{dot && <span className={styles.cardDot} />}
|
|
45
|
+
</span>
|
|
46
|
+
<span className={styles.cardLine} />
|
|
47
|
+
<span className={styles.cardLine} style={{width: '58%'}} />
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function Count({from, to}) {
|
|
53
|
+
/* Two stacked digits crossfading on the shared timeline: `from`
|
|
54
|
+
shows until the drop settles (54%), `to` after it, back again for
|
|
55
|
+
the next loop. Static renderings show `from`. */
|
|
56
|
+
return (
|
|
57
|
+
<span className={styles.count}>
|
|
58
|
+
<span className={styles.countBefore}>{from}</span>
|
|
59
|
+
<span className={styles.countAfter}>{to}</span>
|
|
60
|
+
</span>
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function Kpi({from, to}) {
|
|
65
|
+
/* Small € tile above a lane. Reuses the count crossfade classes so
|
|
66
|
+
the value swaps at the same drop moment as the column counts and
|
|
67
|
+
shows `from` in static renderings. A `to` of undefined renders a
|
|
68
|
+
lane whose total never changes. */
|
|
69
|
+
return (
|
|
70
|
+
<div className={styles.kpi}>
|
|
71
|
+
<span className={styles.kpiBar} />
|
|
72
|
+
<span className={styles.kpiValue}>
|
|
73
|
+
{to != null ? (
|
|
74
|
+
<>
|
|
75
|
+
<span className={styles.countBefore}>{from}</span>
|
|
76
|
+
<span className={styles.countAfter}>{to}</span>
|
|
77
|
+
</>
|
|
78
|
+
) : (
|
|
79
|
+
<span className={styles.kpiStill}>{from}</span>
|
|
80
|
+
)}
|
|
81
|
+
</span>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export default function KanbanMock({size = 'md', caption, running = true, className}) {
|
|
87
|
+
return (
|
|
88
|
+
<div className={styles.km}>
|
|
89
|
+
<figure className={[styles.figure, className].filter(Boolean).join(' ')}>
|
|
90
|
+
<div
|
|
91
|
+
className={[styles.frame, styles[`size-${size}`], !running && styles.static].filter(Boolean).join(' ')}
|
|
92
|
+
role="img"
|
|
93
|
+
aria-label="Abstract kanban board: a lead card is dragged from the first column to the second; the column counts and the lane value totals update at the drop."
|
|
94
|
+
>
|
|
95
|
+
<div className={styles.board}>
|
|
96
|
+
<div className={styles.kpis}>
|
|
97
|
+
<Kpi from="€ 48k" to="€ 30k" />
|
|
98
|
+
<Kpi from="€ 27k" to="€ 45k" />
|
|
99
|
+
<Kpi from="€ 64k" />
|
|
100
|
+
</div>
|
|
101
|
+
<div className={styles.col}>
|
|
102
|
+
<div className={styles.colHead}>
|
|
103
|
+
<span className={styles.colBar} />
|
|
104
|
+
<Count from="3" to="2" />
|
|
105
|
+
</div>
|
|
106
|
+
{/* The top slot belongs to the dragged card (rendered
|
|
107
|
+
absolutely so it can travel); it reads as an empty
|
|
108
|
+
gap while the card is away. */}
|
|
109
|
+
<div className={styles.slotGap} />
|
|
110
|
+
<div className={styles.card}><CardGreek wide /></div>
|
|
111
|
+
<div className={styles.card}><CardGreek /></div>
|
|
112
|
+
</div>
|
|
113
|
+
<div className={styles.col}>
|
|
114
|
+
<div className={styles.colHead}>
|
|
115
|
+
<span className={styles.colBar} />
|
|
116
|
+
<Count from="2" to="3" />
|
|
117
|
+
</div>
|
|
118
|
+
<div className={styles.slotGap} />
|
|
119
|
+
<div className={styles.card}><CardGreek /></div>
|
|
120
|
+
<div className={styles.card}><CardGreek wide /></div>
|
|
121
|
+
</div>
|
|
122
|
+
<div className={styles.col}>
|
|
123
|
+
<div className={styles.colHead}>
|
|
124
|
+
<span className={styles.colBar} />
|
|
125
|
+
<span className={styles.countStatic}>4</span>
|
|
126
|
+
</div>
|
|
127
|
+
<div className={styles.card}><CardGreek /></div>
|
|
128
|
+
<div className={styles.card}><CardGreek wide /></div>
|
|
129
|
+
<div className={styles.card}><CardGreek /></div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
{/* The travelling lead card. */}
|
|
134
|
+
<div className={styles.mover}><CardGreek wide dot /></div>
|
|
135
|
+
|
|
136
|
+
{/* The cursor doing the drag. */}
|
|
137
|
+
<svg className={styles.cursor} viewBox="0 0 24 24" aria-hidden="true">
|
|
138
|
+
<path d="M3 3l7.07 16.97 2.51-7.39 7.39-2.51L3 3z" />
|
|
139
|
+
</svg>
|
|
140
|
+
</div>
|
|
141
|
+
{caption && (
|
|
142
|
+
<figcaption className={styles.caption}>
|
|
143
|
+
{caption === true ? 'Pipeline board' : caption}
|
|
144
|
+
</figcaption>
|
|
145
|
+
)}
|
|
146
|
+
</figure>
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|