@conduction/docusaurus-preset 3.34.0 → 3.36.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/ANIMATION_ROADMAP.md +129 -0
- package/MISSING_COMPONENTS.md +13 -4
- package/package.json +3 -2
- package/src/components/AppMock/AppMock.jsx +14 -14
- package/src/components/AppMock/AppMock.module.css +1270 -7
- package/src/components/AppMock/__tests__/AppMock.render.test.js +148 -0
- package/src/components/AppMock/variants/AppVersionsMock.jsx +1 -1
- package/src/components/AppMock/variants/DeciDeskMock.jsx +47 -6
- package/src/components/AppMock/variants/DocuDeskMock.jsx +40 -10
- package/src/components/AppMock/variants/DoriathMock.jsx +29 -14
- package/src/components/AppMock/variants/HermiqMock.jsx +35 -15
- package/src/components/AppMock/variants/HrmqMock.jsx +46 -28
- package/src/components/AppMock/variants/LarpingAppMock.jsx +14 -4
- package/src/components/AppMock/variants/LaunchPadWidgetsMock.jsx +3 -3
- package/src/components/AppMock/variants/NLDesignMock.jsx +1 -1
- package/src/components/AppMock/variants/OpenBuildMock.jsx +21 -6
- package/src/components/AppMock/variants/OpenCatalogiMock.jsx +23 -4
- package/src/components/AppMock/variants/OpenConnectorMock.jsx +26 -4
- package/src/components/AppMock/variants/OpenRegisterMock.jsx +13 -2
- package/src/components/AppMock/variants/PlanixMock.jsx +1 -1
- package/src/components/AppMock/variants/ProcestMock.jsx +36 -9
- package/src/components/AppMock/variants/ScholiqMock.jsx +1 -1
- package/src/components/AppMock/variants/ShillinqMock.jsx +33 -17
- package/src/components/AppMock/variants/SoftwareCatalogMock.jsx +16 -6
- package/src/components/AppMock/variants/ZaakAfhandelAppMock.jsx +19 -4
- package/src/components/BuildMock/BuildMock.jsx +3 -3
- package/src/components/FeaturesPage/FeaturesPage.jsx +3 -3
- package/src/components/IntegrationIcon/registry.js +3 -3
- package/src/components/LeafCard/LeafCard.jsx +2 -2
- package/src/components/NextSteps/NextSteps.jsx +1 -1
- package/src/components/PartnerDirectory/PartnerDirectory.jsx +1 -1
- package/src/components/Pipeline/Pipeline.jsx +2 -2
- package/src/components/PlatformOverview/PlatformOverview.module.css +1 -1
- package/src/components/SidebarMock/SidebarMock.jsx +38 -11
- package/src/components/SidebarMock/SidebarMock.module.css +1 -1
- package/src/components/SidebarMock/__tests__/SidebarMock.render.test.js +115 -0
- package/src/components/SidebarMock/variants/DeciDeskDecision.jsx +1 -1
- package/src/components/SidebarMock/variants/DocuDeskPiiMap.jsx +1 -1
- package/src/components/SidebarMock/variants/DocuDeskSignatures.jsx +1 -1
- package/src/components/SidebarMock/variants/OpenConnectorRunDetail.jsx +1 -1
- package/src/components/SidebarMock/variants/ProcestTimeline.jsx +1 -1
- package/src/components/SidebarMock/variants/ProcestXWiki.jsx +2 -2
- package/src/components/SolutionCard/SolutionCard.jsx +1 -1
- package/src/components/WidgetMock/WidgetMock.jsx +37 -16
- package/src/components/WidgetMock/__tests__/WidgetMock.render.test.js +125 -0
- package/src/components/WidgetMock/variants/DeciDeskActions.jsx +1 -1
- package/src/components/WidgetMock/variants/DocuDeskAnonymise.jsx +7 -2
- package/src/components/WidgetMock/variants/DocuDeskPendingSign.jsx +1 -1
- package/src/components/WidgetMock/variants/OpenConnectorRuns.jsx +1 -1
- package/src/components/WidgetMock/variants/ProcestDueToday.jsx +1 -1
- package/src/components/WidgetMock/variants/ProcestWerkvoorraad.jsx +1 -1
- package/src/components/WidgetShelf/WidgetShelf.jsx +1 -1
- package/src/data/apps-registry.js +15 -15
- package/src/diagrams/cn-pair.js +1 -1
- package/src/theme/brand.jsx +2 -2
|
@@ -170,6 +170,154 @@ test('larpingapp: the scene timeline renders five steps (was an empty shell)', (
|
|
|
170
170
|
assert.equal((html.match(/step now/g) || []).length, 1, 'exactly one active (orange) step');
|
|
171
171
|
});
|
|
172
172
|
|
|
173
|
+
/* ---- Wave 2 — storytelling animation hooks ---- */
|
|
174
|
+
|
|
175
|
+
test('docudesk: word-level rows with five ordered PII marks, and the live drop-zone', () => {
|
|
176
|
+
const html = render({app: 'docudesk'});
|
|
177
|
+
assert.match(html, /class="body opencatalogi docudesk"/);
|
|
178
|
+
assert.equal((html.match(/class="words"/g) || []).length, 5, 'five word-bar rows');
|
|
179
|
+
for (const n of [1, 2, 3, 4, 5]) {
|
|
180
|
+
assert.match(html, new RegExp(`word mark mark-${n}`), `mark-${n} missing`);
|
|
181
|
+
}
|
|
182
|
+
assert.match(html, /w w-upload zoneLive/);
|
|
183
|
+
assert.match(html, /class="zoneFile"/);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
test('shillinq: bank line, reconciling row 3, ledger totals, and the KPI grow hook', () => {
|
|
187
|
+
const html = render({app: 'shillinq'});
|
|
188
|
+
assert.match(html, /class="body decidesk shillinq"/);
|
|
189
|
+
assert.match(html, /class="bankLine"/);
|
|
190
|
+
assert.equal((html.match(/item inv/g) || []).length, 5, 'five invoice rows');
|
|
191
|
+
assert.equal((html.match(/item inv reconciling/g) || []).length, 1, 'exactly one reconciling row');
|
|
192
|
+
// The reconciling row is row 3: two plain rows precede it.
|
|
193
|
+
assert.match(html, /item inv"[\s\S]*?item inv"[\s\S]*?item inv reconciling/);
|
|
194
|
+
assert.equal((html.match(/tick open/g) || []).length, 1, 'one still-open tick (row 5)');
|
|
195
|
+
assert.match(html, /class="totNet"/);
|
|
196
|
+
assert.match(html, /kpi kpiGrow/);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test('doriath: key hex, both mask layers, value, and the countdown hairline', () => {
|
|
200
|
+
const html = render({app: 'doriath'});
|
|
201
|
+
assert.match(html, /class="body decidesk doriath"/);
|
|
202
|
+
assert.match(html, /class="keyHex"/);
|
|
203
|
+
assert.match(html, /class="vMask"/);
|
|
204
|
+
assert.match(html, /class="vValue"/);
|
|
205
|
+
assert.match(html, /class="vCountdown"/);
|
|
206
|
+
assert.equal((html.match(/class="maskDots"/g) || []).length, 5, 'five locked list entries keep their dot masks');
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test('opencatalogi: search bar with query fill; three matches and three dimmed cards', () => {
|
|
210
|
+
const html = render({app: 'opencatalogi'});
|
|
211
|
+
assert.match(html, /class="search"/);
|
|
212
|
+
assert.match(html, /class="q"/);
|
|
213
|
+
assert.equal((html.match(/class="card[^"]*match"/g) || []).length, 3, 'three matching cards');
|
|
214
|
+
assert.equal((html.match(/class="card[^"]*dim"/g) || []).length, 3, 'three dimmed cards');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
test('openconnector: two travel dots on the arrows and the inserted run row with mint tick', () => {
|
|
218
|
+
const html = render({app: 'openconnector'});
|
|
219
|
+
assert.match(html, /class="travelDotA"/);
|
|
220
|
+
assert.match(html, /class="travelDotB"/);
|
|
221
|
+
assert.match(html, /item newRun/);
|
|
222
|
+
assert.match(html, /class="runTick"/);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('procest: advanced base state (2 done, 1 now), two ghost overlays, and the re-sort pair', () => {
|
|
226
|
+
const html = render({app: 'procest'});
|
|
227
|
+
assert.match(html, /class="step"/, 'first step done');
|
|
228
|
+
assert.match(html, /step advanceFrom/, 'second step advanced out of active');
|
|
229
|
+
assert.match(html, /step now advanceTo/, 'third step is the newly active one');
|
|
230
|
+
assert.equal((html.match(/step now/g) || []).length, 1, 'one active step');
|
|
231
|
+
assert.equal((html.match(/step todo/g) || []).length, 2, 'two to-do steps');
|
|
232
|
+
assert.match(html, /ghost ghostNow/);
|
|
233
|
+
assert.match(html, /ghost ghostTodo/);
|
|
234
|
+
assert.match(html, /item sortUp/);
|
|
235
|
+
assert.match(html, /item sortDown/);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
test('openregister: the landing object row and the KPI grow hook', () => {
|
|
239
|
+
const html = render({app: 'openregister'});
|
|
240
|
+
assert.match(html, /item newObj/);
|
|
241
|
+
assert.match(html, /kpi kpiGrow/);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
/* ---- Wave 4 — content reworks ---- */
|
|
245
|
+
|
|
246
|
+
test('decidesk: vote tally (for/against/abstain + quorum) and the adopt-flip decision row', () => {
|
|
247
|
+
const html = render({app: 'decidesk'});
|
|
248
|
+
assert.equal((html.match(/class="tallyRow /g) || []).length, 3, 'three tally rows');
|
|
249
|
+
assert.match(html, /tallyRow for/);
|
|
250
|
+
assert.match(html, /tallyRow against/);
|
|
251
|
+
assert.match(html, /tallyRow abstain/);
|
|
252
|
+
assert.equal((html.match(/class="quorum"/g) || []).length, 1, 'quorum line on the for-track only');
|
|
253
|
+
assert.match(html, /item decisionRow/);
|
|
254
|
+
assert.match(html, /statusPill adoptFlip/);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
test('hrmq: reworked to a timesheet + approval surface (no people-list panels left)', () => {
|
|
258
|
+
const html = render({app: 'hrmq'});
|
|
259
|
+
assert.match(html, /class="body decidesk hrmq"/);
|
|
260
|
+
assert.equal((html.match(/class="dayCol"/g) || []).length, 5, 'five day columns');
|
|
261
|
+
assert.equal((html.match(/class="dayBar"/g) || []).length, 5, 'five hour bars');
|
|
262
|
+
assert.match(html, /btn submitBtn/);
|
|
263
|
+
assert.match(html, /item approveRow/);
|
|
264
|
+
assert.match(html, /class="approvePip"/);
|
|
265
|
+
assert.match(html, /class="payroll"/);
|
|
266
|
+
assert.match(html, /class="pNum"/);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test('larpingapp: XP ripple — lifted source card, travelling token, timeline intact', () => {
|
|
270
|
+
const html = render({app: 'larpingapp'});
|
|
271
|
+
assert.match(html, /class="body opencatalogi larping"/);
|
|
272
|
+
assert.match(html, /card b xpSource/);
|
|
273
|
+
assert.match(html, /class="xpToken"/);
|
|
274
|
+
assert.equal((html.match(/step now/g) || []).length, 1);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
test('softwarecatalog: scan band, CVE-hit row 4, and the vermillion CVE bar (orange accent bar intact)', () => {
|
|
278
|
+
const html = render({app: 'softwarecatalog'});
|
|
279
|
+
assert.match(html, /class="body openregister swc"/);
|
|
280
|
+
assert.match(html, /class="scanBand"/);
|
|
281
|
+
assert.match(html, /item blocked cveHit/);
|
|
282
|
+
assert.match(html, /bar cve/);
|
|
283
|
+
assert.equal((html.match(/bar accent/g) || []).length, 1, 'exactly one orange accent bar');
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test('zaakafhandelapp: travelling submission ghost and the dressed new case row', () => {
|
|
287
|
+
const html = render({app: 'zaakafhandelapp'});
|
|
288
|
+
assert.match(html, /class="body procest zaak"/);
|
|
289
|
+
assert.match(html, /class="zkGhost"/);
|
|
290
|
+
assert.match(html, /item zkNew/);
|
|
291
|
+
assert.match(html, /item zkSent/);
|
|
292
|
+
assert.equal((html.match(/item late/g) || []).length, 1, 'the SLA-late row survives the rework');
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
test('hermiq: inline styles moved to the module — bubbles, typing indicator, chips, approval', () => {
|
|
296
|
+
const html = render({app: 'hermiq'});
|
|
297
|
+
assert.match(html, /class="body decidesk hermiq"/);
|
|
298
|
+
assert.equal((html.match(/bubble user/g) || []).length, 2, 'two user bubbles');
|
|
299
|
+
assert.equal((html.match(/bubble agent/g) || []).length, 2, 'two agent bubbles');
|
|
300
|
+
assert.match(html, /class="typing"/);
|
|
301
|
+
assert.equal((html.match(/class="tDot"/g) || []).length, 3, 'three typing dots');
|
|
302
|
+
assert.match(html, /statusPill chip1/);
|
|
303
|
+
assert.match(html, /chip chip2/);
|
|
304
|
+
assert.match(html, /chip chip3/);
|
|
305
|
+
assert.match(html, /statusPill approveChip/);
|
|
306
|
+
assert.match(html, /class="promptField"/);
|
|
307
|
+
assert.match(html, /btn sendBtn/);
|
|
308
|
+
// The wave-4 requirement: presentation no longer rides inline styles.
|
|
309
|
+
assert.doesNotMatch(html, /style="[^"]*(background|border-radius|align-self)/, 'presentation styles must live in the module');
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
test('openbuild: template highlight, travelling ghost chip, landing app row, publish pulse', () => {
|
|
313
|
+
const html = render({app: 'openbuild'});
|
|
314
|
+
assert.match(html, /item tplSource/);
|
|
315
|
+
assert.match(html, /class="buildGhost"/);
|
|
316
|
+
assert.match(html, /item newApp/);
|
|
317
|
+
assert.match(html, /kpi kpiGrow/);
|
|
318
|
+
assert.match(html, /kpi forest publishedKpi/);
|
|
319
|
+
});
|
|
320
|
+
|
|
173
321
|
test('reserved accent families: no variant inline-styles coral or gold', () => {
|
|
174
322
|
// SKILL.md reserves the coral and gold families; the one-orange rule
|
|
175
323
|
// is enforced per component by review, but coral/gold must never
|
|
@@ -1,14 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* and
|
|
2
|
+
* Decidiq abstract — left nav + centre with action row, KPI strip,
|
|
3
|
+
* vote tally, and decision row. Reference: localhost:8080/apps/decidesk.
|
|
4
4
|
*
|
|
5
5
|
* Hero of the centre is the trio of primary buttons (New Decision /
|
|
6
|
-
* Action Item / Minutes)
|
|
6
|
+
* Action Item / Minutes) rendered as accent-pill rows top right.
|
|
7
|
+
*
|
|
8
|
+
* Content rework (wave 4): the two former placeholder panels (a bare
|
|
9
|
+
* accent row / a bare short row) are now the app's actual story — a
|
|
10
|
+
* vote tally (for / against / abstain bars with a quorum line) and a
|
|
11
|
+
* decision row whose status flips pending → adopted. The tally fills,
|
|
12
|
+
* the "for" bar crosses the quorum line (which ticks mint), and the
|
|
13
|
+
* decision pill flips to adopted. Base styles are the adopted end
|
|
14
|
+
* state. The KPI strip keeps its single amber cell as the variant's
|
|
15
|
+
* one orange; the pending pill replays via the shared beta-pill
|
|
16
|
+
* coral/orange styling only transiently.
|
|
7
17
|
*/
|
|
8
18
|
|
|
9
19
|
import React from 'react';
|
|
10
20
|
import styles from '../AppMock.module.css';
|
|
11
21
|
|
|
22
|
+
/* for / against / abstain — fill widths of the tally tracks. The
|
|
23
|
+
"for" bar carries the quorum line and crosses it as it fills. */
|
|
24
|
+
const TALLY = [
|
|
25
|
+
{cls: 'for', fill: '72%'},
|
|
26
|
+
{cls: 'against', fill: '30%'},
|
|
27
|
+
{cls: 'abstain', fill: '16%'},
|
|
28
|
+
];
|
|
29
|
+
|
|
12
30
|
export default function DeciDeskMock() {
|
|
13
31
|
return (
|
|
14
32
|
<>
|
|
@@ -55,12 +73,35 @@ export default function DeciDeskMock() {
|
|
|
55
73
|
</div>
|
|
56
74
|
</div>
|
|
57
75
|
<div className={styles.panelRow}>
|
|
58
|
-
|
|
76
|
+
{/* Vote tally — for / against / abstain with quorum line */}
|
|
77
|
+
<div className={[styles.panel, styles.tally].join(' ')}>
|
|
59
78
|
<div className={styles.head}><div className={styles.title}></div></div>
|
|
60
|
-
|
|
79
|
+
{TALLY.map(({cls, fill}, i) => (
|
|
80
|
+
<div key={i} className={[styles.tallyRow, styles[cls]].join(' ')}>
|
|
81
|
+
<div className={styles.tLabel}></div>
|
|
82
|
+
<div className={styles.track}>
|
|
83
|
+
<div className={styles.fill} style={{width: fill}}></div>
|
|
84
|
+
{cls === 'for' && <div className={styles.quorum}></div>}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
))}
|
|
61
88
|
</div>
|
|
62
|
-
|
|
89
|
+
{/* Decision row — pending → adopted flip */}
|
|
90
|
+
<div className={[styles.panel, styles.decision].join(' ')}>
|
|
63
91
|
<div className={styles.head}><div className={styles.title}></div></div>
|
|
92
|
+
<div className={[styles.item, styles.decisionRow].join(' ')}>
|
|
93
|
+
<div className={styles.dIco}></div>
|
|
94
|
+
<div className={styles.lines}>
|
|
95
|
+
<div className={styles.l1}></div>
|
|
96
|
+
<div className={styles.l2}></div>
|
|
97
|
+
</div>
|
|
98
|
+
{/* Base pill = adopted (mint). The keyframes replay the
|
|
99
|
+
pending (beta-coloured) phase before the flip. */}
|
|
100
|
+
<div className={[styles.statusPill, styles.adoptFlip].join(' ')}>
|
|
101
|
+
<div className={styles.h}></div><div className={styles.t}></div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
<div className={styles.row}></div>
|
|
64
105
|
<div className={styles.row + ' ' + styles.short}></div>
|
|
65
106
|
</div>
|
|
66
107
|
</div>
|
|
@@ -1,16 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Filinq abstract — three-pane document workshop.
|
|
3
3
|
*
|
|
4
4
|
* Inferred from the app's role (template-driven document generation,
|
|
5
5
|
* anonymisation, signing, archiving): centre stage shows a list of
|
|
6
6
|
* recent documents with status pips (green = signed, amber = awaiting
|
|
7
7
|
* sign, terra = anonymised, red = blocked) plus an anonymise drop-zone
|
|
8
8
|
* widget. Left nav for templates / drafts / signed / archive.
|
|
9
|
+
*
|
|
10
|
+
* Animation (wave 2): the document rows are word-level bars; the
|
|
11
|
+
* marked (PII) words black out one by one — the anonymiser working
|
|
12
|
+
* through the open document set. Base styles are the redacted end
|
|
13
|
+
* state; the keyframes replay the before-state and the black-out.
|
|
14
|
+
* The drop-zone shares the `.zoneLive` marching-ants + file-drop
|
|
15
|
+
* treatment with the docudesk-anonymise dashboard widget.
|
|
9
16
|
*/
|
|
10
17
|
|
|
11
18
|
import React from 'react';
|
|
12
19
|
import styles from '../AppMock.module.css';
|
|
13
20
|
|
|
21
|
+
/* Word-bar layout per document row: widths in px, `mark` = a PII word
|
|
22
|
+
the anonymiser blacks out. Five rows, five marked words total, so
|
|
23
|
+
the black-out cascade reads one word at a time across the list.
|
|
24
|
+
markIndex orders the cascade (drives the amDdMark<N> keyframes). */
|
|
25
|
+
const DOC_ROWS = [
|
|
26
|
+
{pip: '', words: [{w: 16}, {w: 10, mark: 1}, {w: 20}, {w: 12}]},
|
|
27
|
+
{pip: 'review', words: [{w: 12}, {w: 18}, {w: 9, mark: 2}, {w: 14}]},
|
|
28
|
+
{pip: '', words: [{w: 20}, {w: 12}, {w: 16}, {w: 8, mark: 3}]},
|
|
29
|
+
{pip: 'todo', words: [{w: 10, mark: 4}, {w: 16}, {w: 12}, {w: 18}]},
|
|
30
|
+
{pip: '', words: [{w: 14}, {w: 12, mark: 5}, {w: 18}, {w: 10}]},
|
|
31
|
+
];
|
|
32
|
+
|
|
14
33
|
export default function DocuDeskMock() {
|
|
15
34
|
return (
|
|
16
35
|
<>
|
|
@@ -21,7 +40,7 @@ export default function DocuDeskMock() {
|
|
|
21
40
|
<div className={styles.bell}></div>
|
|
22
41
|
<div className={styles.avatar}></div>
|
|
23
42
|
</div>
|
|
24
|
-
<div className={[styles.body, styles.opencatalogi].filter(Boolean).join(' ')}>
|
|
43
|
+
<div className={[styles.body, styles.opencatalogi, styles.docudesk].filter(Boolean).join(' ')}>
|
|
25
44
|
<div className={styles.nav}>
|
|
26
45
|
<div className={styles.navHead}><div className={styles.h}></div><div className={styles.l}></div></div>
|
|
27
46
|
{[true, false, false, false, false].map((active, i) => (
|
|
@@ -39,25 +58,36 @@ export default function DocuDeskMock() {
|
|
|
39
58
|
<div className={styles.btn}></div>
|
|
40
59
|
</div>
|
|
41
60
|
</div>
|
|
42
|
-
{/* Document list with
|
|
61
|
+
{/* Document list — word bars with PII marks blacking out */}
|
|
43
62
|
<div className={[styles.w, styles['w-jira']].join(' ')}>
|
|
44
63
|
<div className={styles.wHead}>
|
|
45
64
|
<div className={styles.h}></div><div className={styles.t}></div>
|
|
46
65
|
</div>
|
|
47
66
|
<div className={styles.list}>
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
{DOC_ROWS.map(({pip, words}, i) => (
|
|
68
|
+
<div key={i} className={[styles.item, pip && styles[pip]].filter(Boolean).join(' ')}>
|
|
69
|
+
<div className={styles.id}></div>
|
|
70
|
+
<div className={styles.words}>
|
|
71
|
+
{words.map(({w, mark}, j) => (
|
|
72
|
+
<div
|
|
73
|
+
key={j}
|
|
74
|
+
className={[styles.word, mark && styles.mark, mark && styles[`mark-${mark}`]].filter(Boolean).join(' ')}
|
|
75
|
+
style={{width: w}}
|
|
76
|
+
></div>
|
|
77
|
+
))}
|
|
78
|
+
</div>
|
|
79
|
+
<div className={styles.pip}></div>
|
|
80
|
+
</div>
|
|
81
|
+
))}
|
|
53
82
|
</div>
|
|
54
83
|
</div>
|
|
55
|
-
{/* Anonymise drop-zone */}
|
|
56
|
-
<div className={[styles.w, styles['w-upload']].join(' ')}>
|
|
84
|
+
{/* Anonymise drop-zone — live marching ants + file drop */}
|
|
85
|
+
<div className={[styles.w, styles['w-upload'], styles.zoneLive].join(' ')}>
|
|
57
86
|
<div className={styles.wHead}>
|
|
58
87
|
<div className={styles.h}></div><div className={styles.t}></div>
|
|
59
88
|
</div>
|
|
60
89
|
<div className={styles.zone}>
|
|
90
|
+
<div className={styles.zoneFile}></div>
|
|
61
91
|
<div className={styles.ico}></div>
|
|
62
92
|
<div className={styles.label}></div>
|
|
63
93
|
</div>
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Keepiq abstract — secrets vault.
|
|
3
3
|
*
|
|
4
4
|
* Inferred from the app role (storing and sharing secrets): a list of
|
|
5
5
|
* locked entries — key hex, name, masked value rendered as a dot
|
|
6
6
|
* pattern — next to one unlocked detail card on a cobalt-900 surface
|
|
7
7
|
* with the revealed value in light. Tones: cobalt-900 for the vault
|
|
8
8
|
* interior, lavender for the keys.
|
|
9
|
+
*
|
|
10
|
+
* Animation (wave 2): the key hex turns, the mask dots unmask, the
|
|
11
|
+
* value wipes in, a mint countdown hairline runs out, and the entry
|
|
12
|
+
* auto-relocks. Base styles are the revealed state (what static
|
|
13
|
+
* frames show); the keyframes replay lock → unlock → countdown →
|
|
14
|
+
* relock as one seamless loop.
|
|
9
15
|
*/
|
|
10
16
|
|
|
11
17
|
import React from 'react';
|
|
@@ -13,9 +19,9 @@ import styles from '../AppMock.module.css';
|
|
|
13
19
|
|
|
14
20
|
export default function DoriathMock() {
|
|
15
21
|
const mask = (n) => (
|
|
16
|
-
<div
|
|
22
|
+
<div className={styles.maskDots}>
|
|
17
23
|
{Array.from({length: n}).map((_, i) => (
|
|
18
|
-
<div key={i}
|
|
24
|
+
<div key={i} className={styles.dot}></div>
|
|
19
25
|
))}
|
|
20
26
|
</div>
|
|
21
27
|
);
|
|
@@ -28,7 +34,7 @@ export default function DoriathMock() {
|
|
|
28
34
|
<div className={styles.bell}></div>
|
|
29
35
|
<div className={styles.avatar}></div>
|
|
30
36
|
</div>
|
|
31
|
-
<div className={[styles.body, styles.decidesk].filter(Boolean).join(' ')}>
|
|
37
|
+
<div className={[styles.body, styles.decidesk, styles.doriath].filter(Boolean).join(' ')}>
|
|
32
38
|
<div className={styles.nav}>
|
|
33
39
|
<div className={styles.navHead}><div className={styles.h}></div><div className={styles.l}></div></div>
|
|
34
40
|
{[true, false, false, false].map((active, i) => (
|
|
@@ -53,23 +59,32 @@ export default function DoriathMock() {
|
|
|
53
59
|
<div className={styles.stack}>
|
|
54
60
|
{[6, 5, 7, 5, 6].map((dots, i) => (
|
|
55
61
|
<div key={i} className={styles.item}>
|
|
56
|
-
<div
|
|
62
|
+
<div className={styles.keyChip}></div>
|
|
57
63
|
<div className={styles.lines}><div className={styles.l1}></div></div>
|
|
58
64
|
{mask(dots)}
|
|
59
65
|
</div>
|
|
60
66
|
))}
|
|
61
67
|
</div>
|
|
62
68
|
</div>
|
|
63
|
-
{/* Unlocked entry — vault-dark card
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
69
|
+
{/* Unlocked entry — vault-dark card. The key turns, the
|
|
70
|
+
masked dots unmask, the value wipes in, the countdown
|
|
71
|
+
hairline runs out, and the card relocks. */}
|
|
72
|
+
<div className={[styles.panel, styles.vaultCard].join(' ')}>
|
|
73
|
+
<div className={styles.vHead}>
|
|
74
|
+
<div className={styles.keyHex}></div>
|
|
75
|
+
<div className={styles.vTitle}></div>
|
|
76
|
+
</div>
|
|
77
|
+
<div className={styles.vMeta}></div>
|
|
78
|
+
<div className={styles.vSecret}>
|
|
79
|
+
<div className={styles.vMask}>
|
|
80
|
+
{Array.from({length: 7}).map((_, i) => (
|
|
81
|
+
<div key={i} className={styles.dot}></div>
|
|
82
|
+
))}
|
|
83
|
+
</div>
|
|
84
|
+
<div className={styles.vValue}></div>
|
|
68
85
|
</div>
|
|
69
|
-
<div
|
|
70
|
-
<div
|
|
71
|
-
<div style={{height: 3, width: '50%', background: 'rgba(255,255,255,0.25)', borderRadius: 1}}></div>
|
|
72
|
-
<div style={{height: 3, width: '70%', background: 'rgba(255,255,255,0.25)', borderRadius: 1}}></div>
|
|
86
|
+
<div className={styles.vCountdown}></div>
|
|
87
|
+
<div className={styles.vMetaShort}></div>
|
|
73
88
|
</div>
|
|
74
89
|
</div>
|
|
75
90
|
</div>
|
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
* user bubbles right, agent bubbles left — with a tool-call chip row
|
|
7
7
|
* between agent turns and a prompt input at the bottom. Tones:
|
|
8
8
|
* workspace-blue for the human side, mint for confirmed tool runs.
|
|
9
|
+
*
|
|
10
|
+
* Wave 4: the inline styles moved into AppMock.module.css (.hermiq
|
|
11
|
+
* scope) so the surface can animate. The loop: the user's bubble
|
|
12
|
+
* pops in, a typing indicator blinks, the agent's answer grows, the
|
|
13
|
+
* tool chips light left-to-right, the approval chip — the variant's
|
|
14
|
+
* single orange — ticks mint once approved, the tool-result bubble
|
|
15
|
+
* grows, and the user follows up. Base styles are the approved end
|
|
16
|
+
* state (all chips lit, approval mint).
|
|
9
17
|
*/
|
|
10
18
|
|
|
11
19
|
import React from 'react';
|
|
@@ -21,13 +29,13 @@ export default function HermiqMock() {
|
|
|
21
29
|
<div className={styles.bell}></div>
|
|
22
30
|
<div className={styles.avatar}></div>
|
|
23
31
|
</div>
|
|
24
|
-
<div className={[styles.body, styles.decidesk].filter(Boolean).join(' ')}>
|
|
32
|
+
<div className={[styles.body, styles.decidesk, styles.hermiq].filter(Boolean).join(' ')}>
|
|
25
33
|
{/* Agent list rail */}
|
|
26
34
|
<div className={styles.nav}>
|
|
27
35
|
<div className={styles.navHead}><div className={styles.h}></div><div className={styles.l}></div></div>
|
|
28
36
|
{[true, false, false, false].map((active, i) => (
|
|
29
37
|
<div key={i} className={[styles.item, active && styles.active].filter(Boolean).join(' ')}>
|
|
30
|
-
<div className={styles.ico
|
|
38
|
+
<div className={[styles.ico, styles.round].join(' ')}></div>
|
|
31
39
|
<div className={styles.l}></div>
|
|
32
40
|
</div>
|
|
33
41
|
))}
|
|
@@ -40,29 +48,41 @@ export default function HermiqMock() {
|
|
|
40
48
|
<div className={styles.btn + ' ' + styles.ghost}></div>
|
|
41
49
|
</div>
|
|
42
50
|
</div>
|
|
43
|
-
<div className={styles.panel
|
|
51
|
+
<div className={[styles.panel, styles.convo].join(' ')}>
|
|
44
52
|
{/* User asks */}
|
|
45
|
-
<div
|
|
53
|
+
<div className={[styles.bubble, styles.user, styles.turn1].join(' ')}></div>
|
|
54
|
+
{/* Typing indicator — blinks while the agent thinks.
|
|
55
|
+
Hidden at rest and in static frames. */}
|
|
56
|
+
<div className={styles.typing}>
|
|
57
|
+
<div className={styles.tDot}></div>
|
|
58
|
+
<div className={styles.tDot}></div>
|
|
59
|
+
<div className={styles.tDot}></div>
|
|
60
|
+
</div>
|
|
46
61
|
{/* Agent answers */}
|
|
47
|
-
<div
|
|
48
|
-
{/* Tool-call chip row —
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
<div className={[styles.bubble, styles.agent, styles.turn2].join(' ')}></div>
|
|
63
|
+
{/* Tool-call chip row — chips light L→R; the approval chip
|
|
64
|
+
(the variant's one orange while pending) ticks mint. */}
|
|
65
|
+
<div className={styles.chips}>
|
|
66
|
+
<div className={[styles.statusPill, styles.chip1].join(' ')}>
|
|
67
|
+
<div className={styles.h}></div>
|
|
68
|
+
<div className={styles.t}></div>
|
|
69
|
+
</div>
|
|
70
|
+
<div className={[styles.chip, styles.chip2].join(' ')}></div>
|
|
71
|
+
<div className={[styles.chip, styles.chip3].join(' ')}></div>
|
|
72
|
+
<div className={[styles.statusPill, styles.approveChip].join(' ')}>
|
|
51
73
|
<div className={styles.h}></div>
|
|
52
74
|
<div className={styles.t}></div>
|
|
53
75
|
</div>
|
|
54
|
-
<div style={{width: 34, height: 9, borderRadius: 999, background: 'var(--c-cobalt-100)'}}></div>
|
|
55
|
-
<div style={{width: 26, height: 9, borderRadius: 999, background: 'var(--c-cobalt-100)'}}></div>
|
|
56
76
|
</div>
|
|
57
77
|
{/* Agent continues with the tool result */}
|
|
58
|
-
<div
|
|
78
|
+
<div className={[styles.bubble, styles.agent, styles.tall, styles.turn3].join(' ')}></div>
|
|
59
79
|
{/* User follows up */}
|
|
60
|
-
<div
|
|
80
|
+
<div className={[styles.bubble, styles.user, styles.narrow, styles.turn4].join(' ')}></div>
|
|
61
81
|
</div>
|
|
62
82
|
{/* Prompt input */}
|
|
63
|
-
<div className={styles.actions
|
|
64
|
-
<div
|
|
65
|
-
<div className={styles.btn
|
|
83
|
+
<div className={[styles.actions, styles.promptRow].join(' ')}>
|
|
84
|
+
<div className={styles.promptField}></div>
|
|
85
|
+
<div className={[styles.btn, styles.sendBtn].join(' ')}></div>
|
|
66
86
|
</div>
|
|
67
87
|
</div>
|
|
68
88
|
</div>
|
|
@@ -1,21 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Humaniq abstract — hours administration.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Content rework (wave 4): the earlier people-list + leave-balance
|
|
5
|
+
* pair misrepresented the app (Humaniq's daily surface is hours and
|
|
6
|
+
* approval, not a personnel directory). The mock now shows the
|
|
7
|
+
* timesheet week — five day columns of hour bars plus a submit
|
|
8
|
+
* button — next to an approval card: the submitted week arriving as
|
|
9
|
+
* a row, its pip ticking mint on approval, and a payroll counter
|
|
10
|
+
* that grows when the approved hours land. Tone: mint — the team's
|
|
11
|
+
* hours are in order.
|
|
12
|
+
*
|
|
13
|
+
* Animation: day bars fill in a stagger → submit press → the
|
|
14
|
+
* approval row's pip ticks mint → the payroll counter widens.
|
|
15
|
+
* Base styles are the approved end state.
|
|
7
16
|
*/
|
|
8
17
|
|
|
9
18
|
import React from 'react';
|
|
10
19
|
import styles from '../AppMock.module.css';
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
{fill: '72%', shade: 'var(--c-mint-500)'},
|
|
15
|
-
{fill: '45%', shade: 'var(--c-mint-500)'},
|
|
16
|
-
{fill: '88%', shade: 'var(--c-mint-300)'},
|
|
17
|
-
{fill: '20%', shade: 'var(--c-mint-300)'},
|
|
18
|
-
];
|
|
21
|
+
/* Hour-bar heights for the five day columns of the week. */
|
|
22
|
+
const WEEK = ['70%', '85%', '60%', '90%', '45%'];
|
|
19
23
|
|
|
20
24
|
export default function HrmqMock() {
|
|
21
25
|
return (
|
|
@@ -27,7 +31,7 @@ export default function HrmqMock() {
|
|
|
27
31
|
<div className={styles.bell}></div>
|
|
28
32
|
<div className={styles.avatar}></div>
|
|
29
33
|
</div>
|
|
30
|
-
<div className={[styles.body, styles.decidesk].filter(Boolean).join(' ')}>
|
|
34
|
+
<div className={[styles.body, styles.decidesk, styles.hrmq].filter(Boolean).join(' ')}>
|
|
31
35
|
<div className={styles.nav}>
|
|
32
36
|
<div className={styles.navHead}><div className={styles.h}></div><div className={styles.l}></div></div>
|
|
33
37
|
{[true, false, false, false, false].map((active, i) => (
|
|
@@ -45,29 +49,43 @@ export default function HrmqMock() {
|
|
|
45
49
|
</div>
|
|
46
50
|
</div>
|
|
47
51
|
<div className={styles.panelRow} style={{gridTemplateColumns: '1.2fr 1fr'}}>
|
|
48
|
-
{/*
|
|
49
|
-
<div className={styles.panel}>
|
|
52
|
+
{/* Timesheet — the week's hour bars + submit */}
|
|
53
|
+
<div className={[styles.panel, styles.timesheet].join(' ')}>
|
|
50
54
|
<div className={styles.head}><div className={styles.title}></div></div>
|
|
51
|
-
<div className={styles.
|
|
52
|
-
{
|
|
53
|
-
<div key={i} className={styles.
|
|
54
|
-
<div style={{
|
|
55
|
-
<div className={styles.
|
|
55
|
+
<div className={styles.week}>
|
|
56
|
+
{WEEK.map((h, i) => (
|
|
57
|
+
<div key={i} className={styles.dayCol}>
|
|
58
|
+
<div className={styles.dayBar} style={{height: h}}></div>
|
|
59
|
+
<div className={styles.dayLabel}></div>
|
|
56
60
|
</div>
|
|
57
61
|
))}
|
|
58
62
|
</div>
|
|
63
|
+
<div className={styles.sheetFoot}>
|
|
64
|
+
<div className={styles.sheetSum}></div>
|
|
65
|
+
<div className={[styles.btn, styles.submitBtn].join(' ')}></div>
|
|
66
|
+
</div>
|
|
59
67
|
</div>
|
|
60
|
-
{/*
|
|
61
|
-
|
|
68
|
+
{/* Approval + payroll — the submitted week arrives, is
|
|
69
|
+
approved (mint tick), and the payroll counter grows. */}
|
|
70
|
+
<div className={[styles.panel, styles.approval].join(' ')}>
|
|
62
71
|
<div className={styles.head}><div className={styles.title}></div></div>
|
|
63
|
-
{
|
|
64
|
-
<div
|
|
65
|
-
<div className={styles.
|
|
66
|
-
<div
|
|
67
|
-
|
|
68
|
-
|
|
72
|
+
<div className={styles.stack}>
|
|
73
|
+
<div className={[styles.item, styles.approveRow].join(' ')}>
|
|
74
|
+
<div className={styles.av}></div>
|
|
75
|
+
<div className={styles.lines}><div className={styles.l1}></div><div className={styles.l2}></div></div>
|
|
76
|
+
<div className={styles.approvePip}></div>
|
|
77
|
+
</div>
|
|
78
|
+
<div className={styles.item}>
|
|
79
|
+
<div className={[styles.av, styles.b].join(' ')}></div>
|
|
80
|
+
<div className={styles.lines}><div className={styles.l1}></div><div className={styles.l2}></div></div>
|
|
81
|
+
<div className={styles.donePip}></div>
|
|
69
82
|
</div>
|
|
70
|
-
|
|
83
|
+
</div>
|
|
84
|
+
{/* Payroll counter — widens when the approval lands */}
|
|
85
|
+
<div className={styles.payroll}>
|
|
86
|
+
<div className={styles.pLabel}></div>
|
|
87
|
+
<div className={styles.pNum}></div>
|
|
88
|
+
</div>
|
|
71
89
|
</div>
|
|
72
90
|
</div>
|
|
73
91
|
</div>
|