From 1ca6ab7117835bce1b68a640ffdb21497bf309a8 Mon Sep 17 00:00:00 2001 From: Jonathan Bourdon Date: Fri, 8 May 2026 13:45:42 -0400 Subject: [PATCH] feat: centralize frontend Vuetify styling --- .../frontend/002-style-system-baseline.md | 27 +++ .../frontend/003-vuetify-button-migration.md | 31 +++ frontend/src/App.vue | 22 +- frontend/src/assets/main.css | 138 +++++++----- frontend/src/assets/styles.css | 2 + frontend/src/components/AppAvatar.vue | 2 +- .../src/components/ImageCropperDialog.vue | 62 +++--- frontend/src/entry-public-ssr.js | 4 +- .../src/features/auth/views/LoginView.vue | 12 +- .../campaigns/views/CampaignDetailView.vue | 24 +- .../campaigns/views/CampaignsView.vue | 42 ++-- .../features/channels/views/ChannelsView.vue | 50 ++--- .../clients/views/ClientDetailView.vue | 80 +++---- .../features/clients/views/ClientsView.vue | 48 ++-- .../content/components/ColorPalette.vue | 10 +- .../components/ContentApprovalPanel.vue | 34 +-- .../components/ContentCommentComposer.vue | 62 +++--- .../content/components/ContentCommentFeed.vue | 56 ++--- .../content/views/ContentItemDetailView.vue | 186 ++++++++-------- .../content/views/ContentItemsView.vue | 207 +++++++++--------- .../content/views/MediaLibraryView.vue | 22 +- .../components/FeedbackFloatingButton.vue | 4 +- .../components/FeedbackSubmissionDialog.vue | 42 ++-- .../views/DeveloperFeedbackDetailView.vue | 56 ++--- .../views/DeveloperFeedbackListView.vue | 52 ++--- .../feedback/views/MyFeedbackDetailView.vue | 42 ++-- .../feedback/views/MyFeedbackListView.vue | 42 ++-- .../views/OrganizationOnboardingView.vue | 20 +- .../views/OrganizationSettingsView.vue | 100 ++++----- .../views/DeveloperReleaseCommitsView.vue | 99 +++------ .../views/UpdatesView.vue | 8 +- .../reviews/views/ReviewQueueView.vue | 16 +- .../views/IntegrationsSettingsView.vue | 14 +- .../settings/views/SettingsLayoutView.vue | 16 +- .../user-profile/views/UserSettingsView.vue | 66 +++--- .../components/ApprovalWorkflowEditor.vue | 48 ++-- .../workspaces/views/DashboardView.vue | 56 ++--- .../workspaces/views/OverviewView.vue | 28 +-- .../workspaces/views/WorkspaceCreateView.vue | 34 +-- .../views/WorkspaceSettingsView.vue | 84 +++---- frontend/src/layouts/main/AppBar.vue | 104 +++++---- frontend/src/layouts/main/AppSidebar.vue | 202 ++++++++++------- frontend/src/layouts/main/SidebarUserMenu.vue | 105 +++++---- .../src/layouts/main/WorkspaceSelector.vue | 149 ++++++++----- frontend/src/main.js | 25 +-- frontend/src/plugins/vuetify.js | 47 ++++ .../src/static/components/LandingSiteMenu.vue | 50 ++--- frontend/src/static/views/BlogsPage.vue | 6 +- frontend/src/static/views/GuidesPage.vue | 6 +- frontend/src/static/views/Landing.vue | 42 ++-- frontend/src/static/views/PricingPage.vue | 42 ++-- .../src/static/views/ProductFeaturePage.vue | 22 +- frontend/src/static/views/ProductPage.vue | 14 +- frontend/vite.config.js | 3 + 54 files changed, 1461 insertions(+), 1304 deletions(-) create mode 100644 docs/TASKS/frontend/002-style-system-baseline.md create mode 100644 docs/TASKS/frontend/003-vuetify-button-migration.md create mode 100644 frontend/src/assets/styles.css create mode 100644 frontend/src/plugins/vuetify.js diff --git a/docs/TASKS/frontend/002-style-system-baseline.md b/docs/TASKS/frontend/002-style-system-baseline.md new file mode 100644 index 00000000..658a7c9d --- /dev/null +++ b/docs/TASKS/frontend/002-style-system-baseline.md @@ -0,0 +1,27 @@ +# Task: Add frontend style system baseline + +## Goal + +Remove app-shell styling drift by routing shared chrome controls through Vuetify components and centralized theme-backed tokens. + +## Scope + +- Expose reusable CSS variables backed by the Vuetify theme. +- Add shared app-shell primitives for navigation buttons, icon buttons, popovers, and menu items. +- Replace native shell buttons with Vuetify controls in `App.vue`, `AppBar`, `AppSidebar`, `SidebarUserMenu`, and `WorkspaceSelector`. +- Leave feature-screen native button migration to a follow-up task because it crosses many workflows. + +## Validation + +```bash +cd frontend +npm run build +``` + +## Done + +- [x] Tailwind preflight loads before Vuetify styles. +- [x] App-owned CSS loads after Vuetify styles. +- [x] Shared Vuetify defaults are centralized. +- [x] Legacy global native button/card selectors were removed. +- [x] App-shell styles use shared theme-backed tokens. diff --git a/docs/TASKS/frontend/003-vuetify-button-migration.md b/docs/TASKS/frontend/003-vuetify-button-migration.md new file mode 100644 index 00000000..e13a8f64 --- /dev/null +++ b/docs/TASKS/frontend/003-vuetify-button-migration.md @@ -0,0 +1,31 @@ +# Task: Replace native feature buttons with Vuetify controls + +## Goal + +Move remaining interactive feature-screen buttons from native ` + @@ -69,8 +70,8 @@ background: radial-gradient(circle at top left, rgba(255, 174, 94, 0.18), transparent 28%), radial-gradient(circle at top right, rgba(52, 211, 153, 0.16), transparent 24%), - linear-gradient(180deg, #fffaf2 0%, #f6efe2 100%); - color: #172033; + linear-gradient(180deg, var(--app-color-on-primary) 0%, #f6efe2 100%); + color: var(--app-color-on-surface); } .shell-main { @@ -86,16 +87,17 @@ } .sidebar-boundary-toggle { - @apply absolute left-full top-[1.48rem] z-40 flex h-[1.8rem] w-[1.8rem] -translate-x-1/2 items-center justify-center rounded-full border transition-colors; + @apply absolute left-full top-[1.48rem] z-40 flex h-[1.8rem] min-w-0 w-[1.8rem] -translate-x-1/2 items-center justify-center rounded-full border p-0 normal-case transition-colors; background: rgba(255, 250, 242, 0.98); - border-color: rgba(23, 32, 51, 0.12); + border-color: var(--app-border-subtle); color: #44516a; - box-shadow: 0 12px 28px rgba(23, 32, 51, 0.12); + box-shadow: 0 12px 28px var(--app-border-subtle); + letter-spacing: 0; } .sidebar-boundary-toggle:hover { - background: #172033; - color: #fffaf2; + background: var(--app-color-on-surface); + color: var(--app-color-on-primary); } .sidebar-boundary-toggle :deep(.v-icon) { diff --git a/frontend/src/assets/main.css b/frontend/src/assets/main.css index b0eaa450..882b77dc 100644 --- a/frontend/src/assets/main.css +++ b/frontend/src/assets/main.css @@ -24,86 +24,110 @@ body, background: #f4f6f3; } +html { + --app-color-background: rgb(var(--v-theme-background)); + --app-color-on-background: rgb(var(--v-theme-on-background)); + --app-color-surface: rgb(var(--v-theme-surface)); + --app-color-surface-muted: rgb(var(--v-theme-surface-muted)); + --app-color-on-surface: rgb(var(--v-theme-on-surface)); + --app-color-control: rgb(var(--v-theme-control)); + --app-color-control-hover: rgb(var(--v-theme-control-hover)); + --app-color-control-focus: rgb(var(--v-theme-control-focus)); + --app-color-border: rgb(var(--v-theme-border)); + --app-color-border-strong: rgb(var(--v-theme-border-strong)); + --app-color-primary: rgb(var(--v-theme-primary)); + --app-color-on-primary: rgb(var(--v-theme-on-primary)); + --app-color-secondary: rgb(var(--v-theme-secondary)); + --app-color-on-secondary: rgb(var(--v-theme-on-secondary)); + --app-color-tertiary: rgb(var(--v-theme-tertiary)); + --app-color-on-tertiary: rgb(var(--v-theme-on-tertiary)); + --app-color-accent: rgb(var(--v-theme-accent)); + --app-color-accent-strong: rgb(var(--v-theme-accent-strong)); + --app-color-highlight: rgb(var(--v-theme-highlight)); + --app-color-danger: rgb(var(--v-theme-error)); + --app-color-on-danger: rgb(var(--v-theme-on-error)); + --app-text-muted: #526178; + --app-text-subtle: #7a8799; + --app-border-subtle: rgba(23, 32, 51, 0.08); + --app-border-muted: rgba(23, 32, 51, 0.06); + --app-surface-glass: rgba(251, 250, 246, 0.84); + --app-surface-raised: #ffffff; + --app-control-subtle: rgb(var(--v-theme-control)); + --app-control-hover: rgb(var(--v-theme-control-hover)); + --app-control-active: rgba(23, 32, 51, 0.1); + --app-danger-muted: rgb(var(--v-theme-error)); + --app-shadow-popover: 0 18px 40px var(--app-border-subtle); +} + +a { + color: inherit; +} + input::placeholder, textarea::placeholder { color: #68778a; - opacity: 1; } @layer components { - .btn { - @apply min-w-24 w-full; - @apply p-4; - @apply flex flex-nowrap gap-4 items-center justify-center; - @apply rounded-lg; - @apply capitalize text-base font-sans font-medium; - @apply px-10; - @apply cursor-pointer; + .app-sidebar .sidebar-control { + @apply flex min-w-0 items-center gap-3 rounded-[1.1rem] px-4 py-3 text-sm font-semibold no-underline transition-colors; + background: transparent; + color: #44516a; } - button.primary { - @apply min-w-24 w-full; - @apply p-4; - @apply flex flex-nowrap gap-4 items-center justify-center; - @apply rounded-lg; - @apply capitalize text-base font-sans font-medium; - @apply px-10; - @apply cursor-pointer; - @apply bg-hPrimary text-hOnPrimary; - @apply hover:brightness-125; + .app-sidebar .sidebar-control:hover { + background: var(--app-control-hover); + color: var(--app-color-on-surface); } - button.secondary { - @apply min-w-24 w-full; - @apply p-4; - @apply flex flex-nowrap gap-4 items-center justify-center; - @apply rounded-lg; - @apply capitalize text-base font-sans font-medium; - @apply px-10; - @apply cursor-pointer; - @apply bg-hSecondary text-hOnSecondary; - @apply hover:brightness-125; + .app-sidebar .sidebar-control-active { + background: linear-gradient(135deg, rgba(255, 138, 61, 0.14), rgba(239, 68, 68, 0.1)); + box-shadow: inset 0 0 0 1px rgba(255, 138, 61, 0.2); + color: var(--app-color-on-surface); } - div.dialog { - @apply max-h-[90vh]; - @apply place-self-center; + .app-sidebar .sidebar-icon-button { + @apply flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-[1rem] transition-colors no-underline; + background: transparent; + color: var(--app-text-muted); } - div.card { - @apply w-full max-w-[1024px]; - @apply rounded-xl p-4; - @apply flex flex-col gap-4; - @apply bg-hSurface text-hOnSurface; + .app-sidebar .sidebar-icon-button:hover { + background: var(--app-control-hover); + color: var(--app-color-on-surface); } - /* Specific styling for dialog cards */ - div.card.dialog { - @apply bg-hSurface text-hOnSurface; - @apply rounded-xl; - @apply shadow-lg; + .app-sidebar .sidebar-menu-surface { + @apply z-30 flex flex-col gap-1 rounded-[1.25rem] border p-2; + background: var(--app-surface-raised); + border-color: var(--app-border-subtle); + box-shadow: var(--app-shadow-popover); } - div.card-title { - @apply font-sans font-bold text-2xl; - @apply p-2; - @apply text-hOnSurface; + .app-sidebar .sidebar-menu-option { + @apply flex items-center gap-3 rounded-[0.95rem] px-4 py-3 text-left text-sm font-semibold transition-colors; + color: var(--app-color-on-surface); } - div.card-content { - @apply flex flex-col gap-4; - @apply p-2; - @apply text-hOnSurface; - @apply overflow-y-auto max-h-[60vh]; + .app-sidebar .sidebar-menu-option:hover { + background: var(--app-control-hover); } - div.card-actions { - @apply p-2; - @apply flex flex-row gap-4 justify-end; + .app-sidebar .sidebar-menu-option .v-icon { + @apply text-base; + color: var(--app-text-muted); } - div.card-actions > * { - @apply w-fit; - @apply sm:min-w-40 min-w-0; + .app-sidebar .sidebar-menu-option-danger { + color: var(--app-danger-muted); + } + + .app-sidebar .sidebar-menu-option-danger .v-icon { + color: var(--app-danger-muted); + } + + .app-sidebar .sidebar-menu-separator { + @apply my-1; + border-top: 1px solid var(--app-border-subtle); } } diff --git a/frontend/src/assets/styles.css b/frontend/src/assets/styles.css new file mode 100644 index 00000000..0647fef7 --- /dev/null +++ b/frontend/src/assets/styles.css @@ -0,0 +1,2 @@ +@import "vuetify/styles"; +@import "./main.css"; diff --git a/frontend/src/components/AppAvatar.vue b/frontend/src/components/AppAvatar.vue index 29421e32..ae8af136 100644 --- a/frontend/src/components/AppAvatar.vue +++ b/frontend/src/components/AppAvatar.vue @@ -59,7 +59,7 @@ .avatar { @apply inline-flex shrink-0 items-center justify-center overflow-hidden rounded-full font-black uppercase; background: linear-gradient(135deg, rgba(15, 118, 110, 0.16) 0%, rgba(255, 138, 61, 0.18) 100%); - color: #172033; + color: var(--app-color-on-surface); } .avatar img { diff --git a/frontend/src/components/ImageCropperDialog.vue b/frontend/src/components/ImageCropperDialog.vue index 8e7b9396..b3401c60 100644 --- a/frontend/src/components/ImageCropperDialog.vue +++ b/frontend/src/components/ImageCropperDialog.vue @@ -148,13 +148,13 @@
Image editor

{{ title }}

- +
@@ -178,42 +178,42 @@ variant="outlined" hide-details /> - +
- - - - +
@@ -271,8 +271,8 @@ @reference "@/assets/main.css"; .cropper-card { @apply flex flex-col gap-5 rounded-[1.75rem] border p-5; - background: rgba(255, 255, 255, 0.98); - border-color: rgba(23, 32, 51, 0.08); + background: var(--app-surface-raised); + border-color: var(--app-border-subtle); } .cropper-header { @@ -281,12 +281,12 @@ .cropper-eyebrow { @apply text-xs font-bold uppercase tracking-[0.24em]; - color: #0f766e; + color: var(--app-color-on-tertiary); } .cropper-header h2 { @apply mt-2 text-2xl font-black; - color: #172033; + color: var(--app-color-on-surface); } .cropper-actions, @@ -300,9 +300,9 @@ .url-input { @apply min-w-0 flex-1 rounded-full border px-4 py-3 text-sm; - border-color: rgba(23, 32, 51, 0.12); + border-color: var(--app-border-subtle); background: rgba(255, 255, 255, 0.92); - color: #172033; + color: var(--app-color-on-surface); } .footer-actions { @@ -315,22 +315,22 @@ } .action-button { - background: #172033; - color: #fffaf2; + background: var(--app-color-on-surface); + color: var(--app-color-on-primary); } .action-button.secondary, .plain-button { background: rgba(255, 255, 255, 0.84); - color: #172033; - border: 1px solid rgba(23, 32, 51, 0.12); + color: var(--app-color-on-surface); + border: 1px solid var(--app-border-subtle); } .cropper-stage { @apply overflow-hidden rounded-[1.5rem] border; height: 28rem; - border-color: rgba(23, 32, 51, 0.08); - background: #fffaf2; + border-color: var(--app-border-subtle); + background: var(--app-color-on-primary); } .empty-state, @@ -339,14 +339,14 @@ } .empty-state { - border-color: rgba(23, 32, 51, 0.08); - color: #526178; + border-color: var(--app-border-subtle); + color: var(--app-text-muted); background: rgba(255, 250, 242, 0.9); } .error-message { border-color: rgba(185, 28, 28, 0.12); - color: #b91c1c; + color: var(--app-danger-muted); background: rgba(254, 226, 226, 0.75); } diff --git a/frontend/src/entry-public-ssr.js b/frontend/src/entry-public-ssr.js index be60f5fe..bbf9ddea 100644 --- a/frontend/src/entry-public-ssr.js +++ b/frontend/src/entry-public-ssr.js @@ -12,7 +12,8 @@ import ProductFeaturePage from '@/static/views/ProductFeaturePage.vue'; import PricingPage from '@/static/views/PricingPage.vue'; import BlogsPage from '@/static/views/BlogsPage.vue'; import GuidesPage from '@/static/views/GuidesPage.vue'; -import './assets/main.css'; +import { createSocializeVuetify } from '@/plugins/vuetify.js'; +import './assets/styles.css'; const publicRoutes = [ { path: '/', component: Landing }, @@ -45,6 +46,7 @@ export async function render(routePath) { render: () => h(RouterView), }); + app.use(createSocializeVuetify()); app.use(createPinia()); app.use(router); app.use(head); diff --git a/frontend/src/features/auth/views/LoginView.vue b/frontend/src/features/auth/views/LoginView.vue index bf1a8efd..e50f9b7c 100644 --- a/frontend/src/features/auth/views/LoginView.vue +++ b/frontend/src/features/auth/views/LoginView.vue @@ -18,16 +18,16 @@ :callback="googleCallback" popup-type="TOKEN" > - + - +
@@ -225,13 +225,13 @@ .login-card { @apply flex min-h-0 w-full flex-1 flex-col justify-center gap-10 bg-white/80 px-5 py-8 sm:flex-none sm:rounded-[1.5rem] sm:border sm:p-8; - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); box-shadow: none; } @media (min-width: 640px) { .login-card { - box-shadow: 0 18px 40px rgba(23, 32, 51, 0.08); + box-shadow: 0 18px 40px var(--app-border-subtle); } } diff --git a/frontend/src/features/campaigns/views/CampaignDetailView.vue b/frontend/src/features/campaigns/views/CampaignDetailView.vue index 5dc90029..b02ccaa3 100644 --- a/frontend/src/features/campaigns/views/CampaignDetailView.vue +++ b/frontend/src/features/campaigns/views/CampaignDetailView.vue @@ -137,7 +137,7 @@ .content-card { @apply rounded-[1.5rem] border; background: rgba(255, 255, 255, 0.9); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .hero { @@ -146,7 +146,7 @@ .breadcrumb-row { @apply flex items-center gap-2 text-sm; - color: #0f766e; + color: var(--app-color-on-tertiary); } .breadcrumb, @@ -157,18 +157,18 @@ .status-row small, .status-row em { @apply text-sm leading-6 not-italic; - color: #526178; + color: var(--app-text-muted); } .breadcrumb { @apply font-bold uppercase tracking-[0.16em]; - color: #0f766e; + color: var(--app-color-on-tertiary); } .hero h1, .section-header strong, .content-card strong { - color: #172033; + color: var(--app-color-on-surface); } .hero h1 { @@ -182,8 +182,8 @@ .meta-chip, .version-chip { @apply rounded-full px-4 py-2 text-xs font-bold uppercase tracking-[0.16em]; - background: rgba(23, 32, 51, 0.08); - color: #172033; + background: var(--app-border-subtle); + color: var(--app-color-on-surface); } .section-header { @@ -196,8 +196,8 @@ .scope-button { @apply inline-flex items-center justify-center rounded-full px-5 py-3 text-sm font-bold no-underline transition; - background: #172033; - color: #fffaf2; + background: var(--app-color-on-surface); + color: var(--app-color-on-primary); } .scope-button:hover { @@ -223,11 +223,11 @@ .page-message { @apply rounded-[1.25rem] border p-4 text-sm font-medium; background: rgba(255, 255, 255, 0.84); - border-color: rgba(23, 32, 51, 0.08); - color: #526178; + border-color: var(--app-border-subtle); + color: var(--app-text-muted); } .page-message.error { - color: #b91c1c; + color: var(--app-danger-muted); } diff --git a/frontend/src/features/campaigns/views/CampaignsView.vue b/frontend/src/features/campaigns/views/CampaignsView.vue index b68ca34f..5ce73cae 100644 --- a/frontend/src/features/campaigns/views/CampaignsView.vue +++ b/frontend/src/features/campaigns/views/CampaignsView.vue @@ -178,14 +178,14 @@
- - +
@@ -250,12 +250,12 @@ .eyebrow { @apply text-xs font-bold uppercase tracking-[0.24em]; - color: #0f766e; + color: var(--app-color-on-tertiary); } .header h1 { @apply mt-2 text-4xl font-black; - color: #172033; + color: var(--app-color-on-surface); } .header p, @@ -264,7 +264,7 @@ .campaign-meta span, .campaign-meta em { @apply text-sm leading-6 not-italic; - color: #526178; + color: var(--app-text-muted); } .primary, @@ -273,20 +273,20 @@ } .primary { - background: #172033; - color: #fffaf2; + background: var(--app-color-on-surface); + color: var(--app-color-on-primary); } .secondary { - background: rgba(23, 32, 51, 0.06); - color: #172033; + background: var(--app-control-hover); + color: var(--app-color-on-surface); } .create-panel, .campaign-row { @apply rounded-[1.5rem] border; background: rgba(255, 255, 255, 0.9); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .create-panel { @@ -299,7 +299,7 @@ .panel-header strong, .campaign-row strong { - color: #172033; + color: var(--app-color-on-surface); } .form-grid { @@ -308,7 +308,7 @@ .field { @apply flex flex-col gap-2 text-sm font-semibold; - color: #172033; + color: var(--app-color-on-surface); } .field-wide { @@ -317,16 +317,16 @@ .field input { @apply rounded-2xl border px-4 py-3 text-sm; - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); background: rgba(255, 255, 255, 0.95); - color: #172033; + color: var(--app-color-on-surface); } .field textarea { @apply min-h-28 rounded-2xl border px-4 py-3 text-sm; - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); background: rgba(255, 255, 255, 0.95); - color: #172033; + color: var(--app-color-on-surface); resize: vertical; } @@ -353,11 +353,11 @@ .page-message { @apply rounded-[1.25rem] border p-4 text-sm font-medium; background: rgba(255, 255, 255, 0.84); - border-color: rgba(23, 32, 51, 0.08); - color: #526178; + border-color: var(--app-border-subtle); + color: var(--app-text-muted); } .page-message.error { - color: #b91c1c; + color: var(--app-danger-muted); } diff --git a/frontend/src/features/channels/views/ChannelsView.vue b/frontend/src/features/channels/views/ChannelsView.vue index 7a59d81c..9e0dbecb 100644 --- a/frontend/src/features/channels/views/ChannelsView.vue +++ b/frontend/src/features/channels/views/ChannelsView.vue @@ -134,7 +134,7 @@
- +
- - +
@@ -241,7 +241,7 @@ - + @@ -261,7 +261,7 @@ .header h1 { @apply text-4xl font-black; - color: #172033; + color: var(--app-color-on-surface); } .header p, @@ -273,7 +273,7 @@ .page-message, .empty-state span { @apply text-sm leading-6 not-italic; - color: #526178; + color: var(--app-text-muted); } .network-tabs { @@ -282,16 +282,16 @@ .network-tab { @apply inline-flex items-center gap-2 rounded-full border px-4 py-3 transition; - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); background: rgba(255, 255, 255, 0.95); - color: #526178; + color: var(--app-text-muted); } .network-tab.active, .network-tab:hover { border-color: rgba(255, 138, 61, 0.28); background: rgba(255, 138, 61, 0.1); - color: #172033; + color: var(--app-color-on-surface); } .channel-grid { @@ -303,7 +303,7 @@ .empty-state { @apply flex flex-col gap-5 rounded-[1.5rem] border p-5; background: rgba(255, 255, 255, 0.92); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .empty-state { @@ -317,13 +317,13 @@ } .primary { - background: #172033; - color: #fffaf2; + background: var(--app-color-on-surface); + color: var(--app-color-on-primary); } .secondary { - background: rgba(23, 32, 51, 0.06); - color: #172033; + background: var(--app-control-hover); + color: var(--app-color-on-surface); } .panel-header { @@ -334,12 +334,12 @@ .field, .channel-header strong, .channel-metrics strong { - color: #172033; + color: var(--app-color-on-surface); } .panel-header span { @apply text-sm font-semibold; - color: #526178; + color: var(--app-text-muted); } .form-grid { @@ -352,7 +352,7 @@ .field input { @apply rounded-2xl border px-4 py-3 text-sm; - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); background: rgba(255, 255, 255, 0.95); } @@ -371,8 +371,8 @@ .channel-metrics { @apply grid grid-cols-3 gap-3 rounded-[1rem] border p-4; - background: #fffaf2; - border-color: rgba(23, 32, 51, 0.08); + background: var(--app-color-on-primary); + border-color: var(--app-border-subtle); } .channel-metrics div { @@ -386,10 +386,10 @@ .page-message { @apply rounded-[1.25rem] border p-4 font-medium; background: rgba(255, 255, 255, 0.84); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .page-message.error { - color: #b91c1c; + color: var(--app-danger-muted); } diff --git a/frontend/src/features/clients/views/ClientDetailView.vue b/frontend/src/features/clients/views/ClientDetailView.vue index e13f7466..6ca9f4ef 100644 --- a/frontend/src/features/clients/views/ClientDetailView.vue +++ b/frontend/src/features/clients/views/ClientDetailView.vue @@ -220,13 +220,13 @@
Client details - +
Use a local file or a remote image URL, then crop and scale it.
- - +
@@ -359,34 +359,34 @@ Use a local file or a remote image URL, then crop and scale it.
- - +
- - +
@@ -489,7 +489,7 @@ .campaign-card { @apply rounded-[1.5rem] border; background: rgba(255, 255, 255, 0.9); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .hero { @@ -500,7 +500,7 @@ .stat-card strong, .campaign-card strong, .contact-card strong { - color: #172033; + color: var(--app-color-on-surface); } .hero-main h1 { @@ -515,12 +515,12 @@ .campaign-card em, .section-header span { @apply text-sm leading-6 not-italic; - color: #526178; + color: var(--app-text-muted); } .breadcrumb { @apply font-bold uppercase tracking-[0.18em]; - color: #0f766e; + color: var(--app-color-on-tertiary); } .hero-meta { @@ -530,7 +530,7 @@ .hero-status { @apply inline-flex items-center rounded-full px-3 py-1 text-xs font-bold uppercase tracking-[0.18em]; background: rgba(15, 118, 110, 0.12); - color: #0f766e; + color: var(--app-color-on-tertiary); } .stats-grid { @@ -552,7 +552,7 @@ .details-section { @apply rounded-[1.5rem] border p-5; background: rgba(255, 255, 255, 0.92); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .scope-actions { @@ -561,8 +561,8 @@ .scope-button { @apply inline-flex items-center justify-center gap-2 rounded-full px-5 py-3 text-sm font-bold no-underline transition; - background: #172033; - color: #fffaf2; + background: var(--app-color-on-surface); + color: var(--app-color-on-primary); } .scope-button:hover { @@ -571,12 +571,12 @@ .scope-button-secondary { background: rgba(255, 255, 255, 0.92); - color: #172033; - border: 1px solid rgba(23, 32, 51, 0.12); + color: var(--app-color-on-surface); + border: 1px solid var(--app-border-subtle); } .scope-button-secondary:hover { - background: rgba(23, 32, 51, 0.06); + background: var(--app-control-hover); } .details-grid { @@ -585,8 +585,8 @@ .detail-row { @apply flex flex-col gap-2 rounded-[1.25rem] border p-4; - background: #fffaf2; - border-color: rgba(23, 32, 51, 0.08); + background: var(--app-color-on-primary); + border-color: var(--app-border-subtle); } .detail-row-wide { @@ -595,7 +595,7 @@ .detail-row small { @apply text-sm leading-6; - color: #526178; + color: var(--app-text-muted); } .identity-row { @@ -608,7 +608,7 @@ .identity-row strong { @apply truncate text-base font-bold; - color: #172033; + color: var(--app-color-on-surface); } .form-grid { @@ -617,7 +617,7 @@ .field { @apply flex flex-col gap-2 text-sm font-semibold; - color: #172033; + color: var(--app-color-on-surface); } .field-wide { @@ -627,9 +627,9 @@ .field input, .field select { @apply rounded-2xl border px-4 py-3 text-sm; - border-color: rgba(23, 32, 51, 0.12); + border-color: var(--app-border-subtle); background: white; - color: #172033; + color: var(--app-color-on-surface); } .image-field { @@ -638,8 +638,8 @@ .image-picker-card { @apply flex flex-col gap-4 rounded-[1.25rem] border p-4 lg:flex-row lg:items-center lg:justify-between; - background: #fffaf2; - border-color: rgba(23, 32, 51, 0.08); + background: var(--app-color-on-primary); + border-color: var(--app-border-subtle); } .image-picker-copy { @@ -647,12 +647,12 @@ } .image-picker-copy strong { - color: #172033; + color: var(--app-color-on-surface); } .image-picker-copy small { @apply text-sm leading-6; - color: #526178; + color: var(--app-text-muted); } .image-picker-actions { @@ -669,7 +669,7 @@ .section-header strong { @apply text-lg font-black; - color: #172033; + color: var(--app-color-on-surface); } .campaign-list { @@ -699,11 +699,11 @@ .page-message { @apply rounded-[1.25rem] border p-4 text-sm font-medium; background: rgba(255, 255, 255, 0.84); - border-color: rgba(23, 32, 51, 0.08); - color: #526178; + border-color: var(--app-border-subtle); + color: var(--app-text-muted); } .page-message.error { - color: #b91c1c; + color: var(--app-danger-muted); } diff --git a/frontend/src/features/clients/views/ClientsView.vue b/frontend/src/features/clients/views/ClientsView.vue index c0cd75e7..fd9102a4 100644 --- a/frontend/src/features/clients/views/ClientsView.vue +++ b/frontend/src/features/clients/views/ClientsView.vue @@ -75,13 +75,13 @@
- +
- - +
@@ -227,17 +227,17 @@ .eyebrow { @apply text-xs font-bold uppercase tracking-[0.24em]; - color: #0f766e; + color: var(--app-color-on-tertiary); } .header h1 { @apply mt-2 text-4xl font-black; - color: #172033; + color: var(--app-color-on-surface); } .header p { @apply mt-2 text-sm leading-6; - color: #526178; + color: var(--app-text-muted); } .header { @@ -261,7 +261,7 @@ .create-button, .primary { - background: #172033; + background: var(--app-color-on-surface); color: white; } @@ -272,14 +272,14 @@ .secondary { background: rgba(255, 255, 255, 0.84); - border: 1px solid rgba(23, 32, 51, 0.12); - color: #172033; + border: 1px solid var(--app-border-subtle); + color: var(--app-color-on-surface); } .create-panel { @apply flex flex-col gap-5 rounded-[1.75rem] border p-5 md:p-6; background: rgba(255, 255, 255, 0.92); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); } .panel-header { @@ -288,12 +288,12 @@ .panel-header strong { @apply text-lg font-black; - color: #172033; + color: var(--app-color-on-surface); } .panel-header span { @apply text-sm font-semibold; - color: #526178; + color: var(--app-text-muted); } .form-grid { @@ -302,7 +302,7 @@ .field { @apply flex flex-col gap-2 text-sm font-semibold; - color: #172033; + color: var(--app-color-on-surface); } .field.field-wide { @@ -311,9 +311,9 @@ .field input { @apply rounded-2xl border px-4 py-3 text-sm; - border-color: rgba(23, 32, 51, 0.12); + border-color: var(--app-border-subtle); background: white; - color: #172033; + color: var(--app-color-on-surface); } .panel-actions { @@ -327,18 +327,18 @@ .page-message { @apply rounded-[1.25rem] border p-4 text-sm font-medium; background: rgba(255, 255, 255, 0.84); - border-color: rgba(23, 32, 51, 0.08); - color: #526178; + border-color: var(--app-border-subtle); + color: var(--app-text-muted); } .page-message.error { - color: #b91c1c; + color: var(--app-danger-muted); } .client-card { @apply flex flex-col gap-3 rounded-[1.5rem] border p-5; background: rgba(255, 255, 255, 0.84); - border-color: rgba(23, 32, 51, 0.08); + border-color: var(--app-border-subtle); text-decoration: none; } @@ -348,7 +348,7 @@ .client-card strong { @apply text-xl font-black; - color: #172033; + color: var(--app-color-on-surface); } .client-card span { @@ -358,7 +358,7 @@ .client-card em { @apply text-sm leading-6 not-italic; - color: #526178; + color: var(--app-text-muted); } .client-card small { diff --git a/frontend/src/features/content/components/ColorPalette.vue b/frontend/src/features/content/components/ColorPalette.vue index ab5afffc..26a1a155 100644 --- a/frontend/src/features/content/components/ColorPalette.vue +++ b/frontend/src/features/content/components/ColorPalette.vue @@ -24,7 +24,7 @@