From 7c3d13f3f8ca6d3a6e18ca615433c2eab90da970 Mon Sep 17 00:00:00 2001 From: Guy MANDINA Date: Sat, 22 Aug 2026 00:49:05 +0200 Subject: [PATCH 1/3] refactor(ui): extract canonical eyebrow label component MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Normalize 120+ hand-rolled eyebrow label variants (size × tracking × weight × tone combinations across 36 files) to a single canonical .eyebrow class with modifiers (--caption, --strong, --subtle, --blue) defined in @pulse/ui. Rare one-off tones remain call-site utilities, which override the component color by layer precedence. Also remove dead code found during extraction: - ui/actions/ripple.ts (duplicate of @pulse/ui export) + its test - ui/atoms/RadarIcon.svelte (0 refs, only untokenized hex colors) - .card / .tag--* CSS and accent-* @theme aliases in design-tokens.css - GRADE_COLORS in core/types/score.ts Fix 3 untokenized text-[#0c0a09] in MissionCard → text-text-primary. Document the eyebrow spec in packages/design/DESIGN.md. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- apps/extension/src/lib/core/types/score.ts | 12 -- apps/extension/src/ui/actions/ripple.ts | 41 ------ .../src/ui/atoms/ConnectionIndicator.svelte | 2 +- apps/extension/src/ui/atoms/RadarIcon.svelte | 135 ------------------ apps/extension/src/ui/design-tokens.css | 63 -------- .../src/ui/molecules/AlertBuilderCard.svelte | 16 +-- .../ui/molecules/BackupRestoreModal.svelte | 28 +--- .../src/ui/molecules/ConnectorAlertBar.svelte | 4 +- .../src/ui/molecules/ExperienceCard.svelte | 4 +- .../src/ui/molecules/FeedTourOverlay.svelte | 2 +- .../ui/molecules/KeyboardShortcutsHelp.svelte | 9 +- .../src/ui/molecules/MissionCard.svelte | 30 ++-- .../ui/molecules/OperationalEmptyState.svelte | 6 +- .../ui/molecules/OperationalStoryCard.svelte | 6 +- .../src/ui/molecules/PageHeader.svelte | 2 +- .../ApplicationPipelineSummary.svelte | 6 +- .../src/ui/organisms/CopilotPanel.svelte | 20 +-- .../src/ui/organisms/DangerZone.svelte | 4 +- .../src/ui/organisms/ExperienceFeed.svelte | 2 +- .../ui/organisms/FeedActionDashboard.svelte | 12 +- .../src/ui/organisms/FormAssistPanel.svelte | 4 +- .../src/ui/organisms/MetricsPanel.svelte | 34 ++--- .../ui/organisms/MissionArrivalStack.svelte | 6 +- .../src/ui/organisms/MissionComparison.svelte | 16 +-- .../MissionInvestigationDrawer.svelte | 8 +- .../src/ui/organisms/OnboardingFlow.svelte | 10 +- .../ui/organisms/PlatformAccountsPanel.svelte | 6 +- .../src/ui/organisms/ProfileSection.svelte | 16 +-- .../src/ui/organisms/ScanProgress.svelte | 6 +- .../src/ui/organisms/ScanSettings.svelte | 12 +- .../src/ui/organisms/ScanSummary.svelte | 2 +- .../src/ui/organisms/SourceHealthPanel.svelte | 6 +- .../src/ui/organisms/TJMDashboard.svelte | 36 ++--- .../src/ui/pages/ApplicationsPage.svelte | 16 +-- apps/extension/src/ui/pages/FeedPage.svelte | 10 +- .../extension/src/ui/pages/ProfilePage.svelte | 4 +- .../src/ui/pages/SettingsPage.svelte | 28 ++-- apps/extension/src/ui/pages/TJMPage.svelte | 7 +- .../src/ui/templates/OnboardingLayout.svelte | 6 +- apps/extension/tests/unit/ui/ripple.test.ts | 44 ------ packages/design/DESIGN.md | 12 +- packages/ui/src/app.css | 27 +++- 42 files changed, 161 insertions(+), 559 deletions(-) delete mode 100644 apps/extension/src/ui/actions/ripple.ts delete mode 100644 apps/extension/src/ui/atoms/RadarIcon.svelte delete mode 100644 apps/extension/tests/unit/ui/ripple.test.ts diff --git a/apps/extension/src/lib/core/types/score.ts b/apps/extension/src/lib/core/types/score.ts index c0af210c..fb141235 100644 --- a/apps/extension/src/lib/core/types/score.ts +++ b/apps/extension/src/lib/core/types/score.ts @@ -75,15 +75,3 @@ export function scoreToGrade(score: number): Grade { } return 'F'; } - -/** - * Grade to color mapping for UI display. - * Matches the existing design tokens. - */ -export const GRADE_COLORS: Record = { - A: { text: 'text-accent-emerald', bg: 'bg-accent-emerald/15' }, - B: { text: 'text-accent-blue', bg: 'bg-accent-blue/15' }, - C: { text: 'text-accent-amber', bg: 'bg-accent-amber/15' }, - D: { text: 'text-text-subtle', bg: 'bg-subtle-gray' }, - F: { text: 'text-text-subtle', bg: 'bg-subtle-gray' }, -}; diff --git a/apps/extension/src/ui/actions/ripple.ts b/apps/extension/src/ui/actions/ripple.ts deleted file mode 100644 index c4c810fd..00000000 --- a/apps/extension/src/ui/actions/ripple.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Inject keyframes once -if (typeof document !== 'undefined' && !document.getElementById('ripple-keyframes')) { - const style = document.createElement('style'); - style.id = 'ripple-keyframes'; - style.textContent = `@keyframes ripple-expand { to { transform: scale(1); opacity: 0; } }`; - document.head.appendChild(style); -} - -export function ripple(node: HTMLElement) { - node.style.overflow = 'hidden'; - if (!node.style.position || node.style.position === 'static') { - node.style.position = 'relative'; - } - - function handlePointerDown(e: PointerEvent) { - const rect = node.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - const size = Math.max(rect.width, rect.height) * 2; - - const span = document.createElement('span'); - span.style.cssText = ` - position: absolute; border-radius: 50%; pointer-events: none; - width: ${size}px; height: ${size}px; - left: ${x - size / 2}px; top: ${y - size / 2}px; - background: rgba(255,255,255,0.2); - transform: scale(0); opacity: 1; - animation: ripple-expand 400ms ease-out forwards; - `; - node.appendChild(span); - setTimeout(() => span.remove(), 450); - } - - node.addEventListener('pointerdown', handlePointerDown); - - return { - destroy() { - node.removeEventListener('pointerdown', handlePointerDown); - }, - }; -} diff --git a/apps/extension/src/ui/atoms/ConnectionIndicator.svelte b/apps/extension/src/ui/atoms/ConnectionIndicator.svelte index d5675a60..993de7cf 100644 --- a/apps/extension/src/ui/atoms/ConnectionIndicator.svelte +++ b/apps/extension/src/ui/atoms/ConnectionIndicator.svelte @@ -114,7 +114,7 @@ - {statusConfig.label} + {statusConfig.label} {#if showDetails} diff --git a/apps/extension/src/ui/atoms/RadarIcon.svelte b/apps/extension/src/ui/atoms/RadarIcon.svelte deleted file mode 100644 index 0a5b9459..00000000 --- a/apps/extension/src/ui/atoms/RadarIcon.svelte +++ /dev/null @@ -1,135 +0,0 @@ - - - - -
- {#if isAnimating} -
- {/if} - - -
diff --git a/apps/extension/src/ui/design-tokens.css b/apps/extension/src/ui/design-tokens.css index facf090b..81604e4f 100644 --- a/apps/extension/src/ui/design-tokens.css +++ b/apps/extension/src/ui/design-tokens.css @@ -5,17 +5,6 @@ @import '@pulse/ui/app.css'; -/* ================================================ - * Compatibility aliases for existing extension UI classes - * These stay local to the extension until all references are migrated. - * ================================================ */ - -@theme { - --color-accent-blue: #0b64e9; - --color-accent-emerald: #0b64e9; - --color-accent-red: #f24149; -} - /* ================================================ * Base Styles (extension-specific) * ================================================ */ @@ -66,58 +55,6 @@ textarea:focus-visible, overflow-x: hidden; } -/* ================================================ - * Card Container - * ================================================ */ - -.card { - background: var(--color-surface-white); - border-radius: var(--radius-md); - box-shadow: var(--shadow-sm); - padding: var(--spacing-16); -} - -/* ================================================ - * Status Tags - * ================================================ */ - -.tag { - display: inline-flex; - align-items: center; - gap: var(--spacing-4); - padding: var(--spacing-4) var(--spacing-8); - border-radius: var(--radius-md); - font-family: var(--font-system); - font-size: var(--text-meta); - font-weight: 400; - line-height: var(--text-meta--line-height); -} - -.tag--red { - background: var(--color-status-red); - color: #ffffff; -} -.tag--orange { - background: var(--color-status-orange); - color: #ffffff; -} -.tag--yellow { - background: var(--color-status-yellow); - color: #ffffff; -} -.tag--violet { - background: var(--color-status-violet); - color: #ffffff; -} -.tag--blue { - background: var(--color-blueprint-blue); - color: #ffffff; -} -.tag--gray { - background: var(--color-subtle-gray); - color: var(--color-text-secondary); -} - /* ================================================ * Extension shell utilities — Analytical Blueprint * ================================================ */ diff --git a/apps/extension/src/ui/molecules/AlertBuilderCard.svelte b/apps/extension/src/ui/molecules/AlertBuilderCard.svelte index 264ebed5..7160cba0 100644 --- a/apps/extension/src/ui/molecules/AlertBuilderCard.svelte +++ b/apps/extension/src/ui/molecules/AlertBuilderCard.svelte @@ -218,9 +218,7 @@
-

- Alerte prioritaire -

+

Alerte prioritaire

Définir ce qui mérite une action

@@ -314,7 +312,7 @@

{alertPreview.matchingCount}

-

Éligibles

+

Éligibles

{alertPreview.notifyCount}

-

Notifiées

+

Notifiées

{#if alertPreview.seenCount > 0} diff --git a/apps/extension/src/ui/molecules/BackupRestoreModal.svelte b/apps/extension/src/ui/molecules/BackupRestoreModal.svelte index 69e6da36..70c8f0d2 100644 --- a/apps/extension/src/ui/molecules/BackupRestoreModal.svelte +++ b/apps/extension/src/ui/molecules/BackupRestoreModal.svelte @@ -144,9 +144,7 @@ {#if error}
-

- Restauration bloquée -

+

Restauration bloquée

{getErrorMessage(error)}

Choisissez un autre fichier ou recréez une sauvegarde depuis cet appareil. @@ -168,9 +166,7 @@

- - Profil - + Profil {stats.profileName || 'Non renseigné'} {#if stats.jobTitle} @@ -180,9 +176,7 @@
- - Favoris - + Favoris {stats.favoritesCount} mission(s)
- - Masquées - + Masquées @@ -201,9 +193,7 @@
- - Version - + Version v{stats.version} @@ -211,9 +201,7 @@
-

+

Décision requise

@@ -247,9 +235,7 @@ role="alert" aria-live="assertive" > -

+

Restauration échouée

diff --git a/apps/extension/src/ui/molecules/ConnectorAlertBar.svelte b/apps/extension/src/ui/molecules/ConnectorAlertBar.svelte index 91f202f4..a2ca5200 100644 --- a/apps/extension/src/ui/molecules/ConnectorAlertBar.svelte +++ b/apps/extension/src/ui/molecules/ConnectorAlertBar.svelte @@ -37,9 +37,7 @@

-

- Impact opérationnel -

+

Impact opérationnel

Pulse peut sous-estimer les nouvelles missions tant que {brokenConnectors.length === 1 diff --git a/apps/extension/src/ui/molecules/ExperienceCard.svelte b/apps/extension/src/ui/molecules/ExperienceCard.svelte index 294c7a83..1d802708 100644 --- a/apps/extension/src/ui/molecules/ExperienceCard.svelte +++ b/apps/extension/src/ui/molecules/ExperienceCard.svelte @@ -387,7 +387,7 @@ {/if}

- {sourceLabel} + {sourceLabel} {#if snapshot.context.input.isBusy} @@ -407,7 +407,7 @@ {/if}
- {sourceLabel} + {sourceLabel} {#if snapshot.context.input.isBusy} diff --git a/apps/extension/src/ui/molecules/FeedTourOverlay.svelte b/apps/extension/src/ui/molecules/FeedTourOverlay.svelte index a6525af8..46c76b92 100644 --- a/apps/extension/src/ui/molecules/FeedTourOverlay.svelte +++ b/apps/extension/src/ui/molecules/FeedTourOverlay.svelte @@ -36,7 +36,7 @@
-

+

Tour du feed · {stepIndex + 1}/{totalSteps}

{step.title}

diff --git a/apps/extension/src/ui/molecules/KeyboardShortcutsHelp.svelte b/apps/extension/src/ui/molecules/KeyboardShortcutsHelp.svelte index d3b225bc..af319ca3 100644 --- a/apps/extension/src/ui/molecules/KeyboardShortcutsHelp.svelte +++ b/apps/extension/src/ui/molecules/KeyboardShortcutsHelp.svelte @@ -98,9 +98,7 @@
-

- Navigation rapide -

+

Navigation rapide

Raccourcis clavier

@@ -126,10 +124,7 @@
{#each shortcutsByCategory as [category, shortcuts] (category)}
-

+

{category}

Nouveau {:else if showSeenStatus} Vu @@ -397,9 +397,7 @@ >
-

- Note expliquée -

+

Note expliquée

{#if missionGrade !== null} Note finale {missionGrade}, calculée depuis le profil, l’annonce et les critères @@ -434,11 +432,11 @@ {@const grade = scoreToGrade(line.value)} {@const color = grade === 'A' - ? 'bg-accent-green text-[#0c0a09]' + ? 'bg-accent-green text-text-primary' : grade === 'B' - ? 'bg-accent-amber text-[#0c0a09]' + ? 'bg-accent-amber text-text-primary' : grade === 'C' - ? 'bg-status-orange text-[#0c0a09]' + ? 'bg-status-orange text-text-primary' : 'bg-disabled-gray text-text-secondary'}

{line.label} @@ -486,14 +484,14 @@ transition:slide={{ duration: isVirtualized ? 0 : 200 }} >
-

{decisionInsight.label}

+

{decisionInsight.label}

{decisionInsight.text}

{#if mission.tjm !== null}
-

TJM

+

TJM

{formatTJMValue(mission.tjm)}/j

@@ -501,32 +499,30 @@ {/if} {#if mission.location}
-

Zone

+

Zone

{mission.location}

{/if} {#if mission.duration}
-

Durée

+

Durée

{mission.duration}

{/if} {#if mission.startDate}
-

Début

+

Début

{mission.startDate}

{/if} {#if seniorityLabel}
-

- Séniorité -

+

Séniorité

{seniorityLabel}

{/if}
-

Source

+

Source

{mission.source}

diff --git a/apps/extension/src/ui/molecules/OperationalEmptyState.svelte b/apps/extension/src/ui/molecules/OperationalEmptyState.svelte index 16ae9881..ec00db90 100644 --- a/apps/extension/src/ui/molecules/OperationalEmptyState.svelte +++ b/apps/extension/src/ui/molecules/OperationalEmptyState.svelte @@ -66,9 +66,7 @@
-

- Décision -

+

Décision

{#if statusLabel} {/if} @@ -80,7 +78,7 @@ {#if proofLabel && proofValue !== null}
-

+

{proofLabel}

diff --git a/apps/extension/src/ui/molecules/OperationalStoryCard.svelte b/apps/extension/src/ui/molecules/OperationalStoryCard.svelte index 7c5508de..a6f5f3fd 100644 --- a/apps/extension/src/ui/molecules/OperationalStoryCard.svelte +++ b/apps/extension/src/ui/molecules/OperationalStoryCard.svelte @@ -141,7 +141,7 @@

{#if eyebrow} -

+

{eyebrow}

{/if} @@ -160,9 +160,7 @@
{#each evidence as item, i (i)}
-

+

{#if item.icon} {/if} diff --git a/apps/extension/src/ui/molecules/PageHeader.svelte b/apps/extension/src/ui/molecules/PageHeader.svelte index d41a0365..7d2d68a7 100644 --- a/apps/extension/src/ui/molecules/PageHeader.svelte +++ b/apps/extension/src/ui/molecules/PageHeader.svelte @@ -33,7 +33,7 @@

{/if}
-

{eyebrow}

+

{eyebrow}

{title}

{#if badge} diff --git a/apps/extension/src/ui/organisms/ApplicationPipelineSummary.svelte b/apps/extension/src/ui/organisms/ApplicationPipelineSummary.svelte index 79244cfc..f5fcb02c 100644 --- a/apps/extension/src/ui/organisms/ApplicationPipelineSummary.svelte +++ b/apps/extension/src/ui/organisms/ApplicationPipelineSummary.svelte @@ -91,7 +91,7 @@ >
-

+

{card.label}

@@ -120,9 +120,7 @@

-

- Avancement -

+

Avancement

{#if summary.bottleneck}

diff --git a/apps/extension/src/ui/organisms/CopilotPanel.svelte b/apps/extension/src/ui/organisms/CopilotPanel.svelte index 78265fdb..ead4612b 100644 --- a/apps/extension/src/ui/organisms/CopilotPanel.svelte +++ b/apps/extension/src/ui/organisms/CopilotPanel.svelte @@ -353,7 +353,7 @@ {#if store.dossier.approvedArtifacts.length > 0}

-

+

Brouillons approuvés ({store.dossier.approvedArtifacts.length})

{#each store.dossier.approvedArtifacts as artifact (artifact.artifactId)} @@ -447,9 +447,7 @@
- - Mission - + Mission
{#each store.missionFieldOptions as field (field)}
- - Profil - + Profil
{#each store.profileFieldOptions as field (field)}