feat: centralize frontend Vuetify styling
All checks were successful
deploy-socialize / image (push) Successful in 50s
deploy-socialize / deploy (push) Successful in 19s

This commit is contained in:
2026-05-08 13:45:42 -04:00
parent e81c9f42c9
commit 1ca6ab7117
54 changed files with 1461 additions and 1304 deletions

View File

@@ -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.

View File

@@ -0,0 +1,31 @@
# Task: Replace native feature buttons with Vuetify controls
## Goal
Move remaining interactive feature-screen buttons from native `<button>` elements to Vuetify controls so button styling consistently flows through Vuetify.
## Scope
- Replace action buttons with `v-btn`.
- Replace icon-only buttons with `v-btn` using icon-sized styling.
- Preserve specialized non-button native controls only when Vuetify would reduce capability, such as file inputs.
- Keep behavior unchanged while converting one feature area at a time.
## Likely Files
- `frontend/src/components/ImageCropperDialog.vue`
- `frontend/src/features/**/**/*.vue`
- `frontend/src/static/**/*.vue`
## Validation
```bash
cd frontend
npm run build
```
## Done
- [x] Native `<button>` elements under `frontend/src/**/*.vue` were migrated to `v-btn`.
- [x] Public SSR rendering installs the shared Vuetify plugin.
- [x] Frontend build and public prerender pass.

View File

@@ -5,13 +5,14 @@
<div class="shell-sidebar-wrap">
<app-sidebar :is-expanded="isSidebarExpanded" />
<button
<v-btn
class="sidebar-boundary-toggle"
type="button"
variant="text"
:ripple="false"
@click="isSidebarExpanded = !isSidebarExpanded"
>
<v-icon :icon="isSidebarExpanded ? mdiChevronLeft : mdiChevronRight" />
</button>
</v-btn>
</div>
</template>
@@ -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) {

View File

@@ -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);
}
}

View File

@@ -0,0 +1,2 @@
@import "vuetify/styles";
@import "./main.css";

View File

@@ -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 {

View File

@@ -148,13 +148,13 @@
<div class="cropper-eyebrow">Image editor</div>
<h2>{{ title }}</h2>
</div>
<button
<v-btn variant="text" :ripple="false"
class="plain-button"
:disabled="isSaving"
@click="closeDialog"
>
Close
</button>
</v-btn>
</div>
<div class="cropper-actions">
@@ -178,42 +178,42 @@
variant="outlined"
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="action-button secondary"
:disabled="isSaving"
@click="loadImageFromUrl"
>
{{ loadLabel }}
</button>
</v-btn>
</div>
<button
<v-btn variant="text" :ripple="false"
class="action-button secondary"
:disabled="!isReady || isSaving"
@click="zoom(1.15)"
>
Zoom in
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="action-button secondary"
:disabled="!isReady || isSaving"
@click="zoom(0.85)"
>
Zoom out
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="action-button secondary"
:disabled="!isReady || isSaving"
@click="rotate(-90)"
>
Rotate left
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="action-button secondary"
:disabled="!isReady || isSaving"
@click="rotate(90)"
>
Rotate right
</button>
</v-btn>
</div>
<div
@@ -242,14 +242,14 @@
</div>
<div class="footer-actions">
<button
<v-btn variant="text" :ripple="false"
class="action-button secondary"
:disabled="isSaving"
@click="closeDialog"
>
Cancel
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="action-button"
:disabled="!isReady || isSaving"
@click="saveCrop"
@@ -261,7 +261,7 @@
:width="2"
/>
<span>{{ isSaving ? 'Saving...' : confirmLabel }}</span>
</button>
</v-btn>
</div>
</div>
</v-dialog>
@@ -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);
}

View File

@@ -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);

View File

@@ -18,16 +18,16 @@
:callback="googleCallback"
popup-type="TOKEN"
>
<button class="secondary">
<v-btn variant="text" :ripple="false" class="secondary">
<v-icon
:icon="mdiGoogle"
class="mr-2"
/>
{{ t('continueWithGoogle') }}
</button>
</v-btn>
</google-login>
<button
<v-btn variant="text" :ripple="false"
class="secondary"
type="button"
@click="handleFacebookLogin"
@@ -37,7 +37,7 @@
class="mr-2"
/>
{{ t('continueWithFacebook') }}
</button>
</v-btn>
</div>
<div class="my-4 flex items-center">
@@ -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);
}
}

View File

@@ -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);
}
</style>

View File

@@ -178,14 +178,14 @@
</div>
<div class="panel-actions">
<button
<v-btn variant="text" :ripple="false"
class="secondary"
:disabled="campaignsStore.isCreating"
@click="isCreateFormVisible = false"
>
{{ t('common.cancel') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="primary"
:disabled="campaignsStore.isCreating"
@click="submitForm"
@@ -197,7 +197,7 @@
:width="2"
/>
<span>{{ campaignsStore.isCreating ? t('common.creating') : t('campaigns.createTitle') }}</span>
</button>
</v-btn>
</div>
</div>
@@ -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);
}
</style>

View File

@@ -134,7 +134,7 @@
</div>
<div class="network-tabs">
<button
<v-btn variant="text" :ripple="false"
v-for="network in networkOptions"
:key="network.value"
type="button"
@@ -144,7 +144,7 @@
>
<v-icon :icon="network.icon" />
<span>{{ network.value }}</span>
</button>
</v-btn>
</div>
<div
@@ -173,21 +173,21 @@
</div>
<div class="panel-actions">
<button
<v-btn variant="text" :ripple="false"
class="secondary"
type="button"
@click="isCreateFormVisible = false"
>
{{ t('common.cancel') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="primary"
type="button"
:disabled="channelsStore.isCreating"
@click="submitForm"
>
{{ channelsStore.isCreating ? t('common.saving') : t('channels.createTitle') }}
</button>
</v-btn>
</div>
</div>
@@ -241,7 +241,7 @@
</article>
</div>
<button
<v-btn variant="text" :ripple="false"
v-else
type="button"
class="empty-state"
@@ -249,7 +249,7 @@
>
<v-icon :icon="mdiPlus" />
<span>{{ t('channels.emptyAction', { network: activeNetwork }) }}</span>
</button>
</v-btn>
</section>
</template>
@@ -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);
}
</style>

View File

@@ -220,13 +220,13 @@
<div class="section details-section">
<div class="section-header">
<strong>Client details</strong>
<button
<v-btn variant="text" :ripple="false"
v-if="authStore.isManager"
class="scope-button scope-button-secondary"
@click="isEditFormVisible ? (isEditFormVisible = false) : openEditForm()"
>
{{ isEditFormVisible ? 'Close editor' : 'Edit details' }}
</button>
</v-btn>
</div>
<div
@@ -311,20 +311,20 @@
<small>Use a local file or a remote image URL, then crop and scale it.</small>
</div>
<div class="image-picker-actions">
<button
<v-btn variant="text" :ripple="false"
class="scope-button scope-button-secondary"
:disabled="clientsStore.isUpdating"
@click="openPortraitDialog('client')"
>
Change image
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="scope-button scope-button-secondary"
:disabled="clientsStore.isUpdating || !form.portraitUrl"
@click="clearPortrait('client')"
>
Remove
</button>
</v-btn>
</div>
</div>
</div>
@@ -359,34 +359,34 @@
<small>Use a local file or a remote image URL, then crop and scale it.</small>
</div>
<div class="image-picker-actions">
<button
<v-btn variant="text" :ripple="false"
class="scope-button scope-button-secondary"
:disabled="clientsStore.isUpdating"
@click="openPortraitDialog('contact')"
>
Change image
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="scope-button scope-button-secondary"
:disabled="clientsStore.isUpdating || !form.primaryContactPortraitUrl"
@click="clearPortrait('contact')"
>
Remove
</button>
</v-btn>
</div>
</div>
</div>
</div>
<div class="panel-actions">
<button
<v-btn variant="text" :ripple="false"
class="scope-button scope-button-secondary"
:disabled="clientsStore.isUpdating"
@click="isEditFormVisible = false"
>
Cancel
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="scope-button"
:disabled="clientsStore.isUpdating"
@click="submitEditForm"
@@ -398,7 +398,7 @@
:width="2"
/>
<span>{{ clientsStore.isUpdating ? 'Saving...' : 'Save client' }}</span>
</button>
</v-btn>
</div>
</template>
</div>
@@ -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);
}
</style>

View File

@@ -75,13 +75,13 @@
</div>
<div class="action-row">
<button
<v-btn variant="text" :ripple="false"
v-if="authStore.isManager"
class="create-button"
@click="openCreateForm"
>
{{ t('clients.newClient') }}
</button>
</v-btn>
</div>
<div
@@ -151,14 +151,14 @@
</div>
<div class="panel-actions">
<button
<v-btn variant="text" :ripple="false"
class="secondary"
:disabled="clientsStore.isCreating"
@click="isCreateFormVisible = false"
>
{{ t('common.cancel') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="primary"
:disabled="clientsStore.isCreating"
@click="submitForm"
@@ -170,7 +170,7 @@
:width="2"
/>
<span>{{ clientsStore.isCreating ? t('common.creating') : t('clients.createTitle') }}</span>
</button>
</v-btn>
</div>
</div>
@@ -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 {

View File

@@ -24,7 +24,7 @@
<template>
<div class="color-palette">
<button
<v-btn variant="text" :ripple="false"
v-for="color in props.colors"
:key="color"
class="color-option"
@@ -44,10 +44,10 @@
gap: 0.5rem;
width: max-content;
padding: 0.5rem;
border: 1px solid rgba(23, 32, 51, 0.1);
border: 1px solid var(--app-control-active);
border-radius: 0.75rem;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.14);
}
@@ -57,13 +57,13 @@
border: 1px solid rgba(255, 255, 255, 0.9);
border-radius: 9999px;
border-color: rgba(255, 255, 255, 0.9);
box-shadow: 0 0 0 1px rgba(23, 32, 51, 0.12);
box-shadow: 0 0 0 1px var(--app-border-subtle);
transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.color-option:hover,
.color-option.active {
transform: scale(1.08);
box-shadow: 0 0 0 2px #172033;
box-shadow: 0 0 0 2px var(--app-color-on-surface);
}
</style>

View File

@@ -255,7 +255,7 @@
class="approval-step"
:class="`is-${step.status}`"
>
<button
<v-btn variant="text" :ripple="false"
class="step-circle"
type="button"
:disabled="step.kind !== 'approval' || !canRecordDecision(step.approval) || isSubmittingDecision"
@@ -263,7 +263,7 @@
@click="submitDecision(step.approval.id)"
>
{{ index + 1 }}
</button>
</v-btn>
<div class="step-popover">
<div class="popover-heading">
@@ -342,7 +342,7 @@
.popover-heading strong,
.popover-meta strong,
.decision-row strong {
color: #172033;
color: var(--app-color-on-surface);
}
.approval-empty span,
@@ -352,7 +352,7 @@
.decision-row span,
.decision-row small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.approval-stepper,
@@ -378,9 +378,9 @@
.step-circle {
@apply relative z-10 flex h-9 w-9 items-center justify-center rounded-full border text-xs font-black transition;
background: #fffdf8;
background: var(--app-color-surface);
border-color: rgba(23, 32, 51, 0.16);
color: #526178;
color: var(--app-text-muted);
}
button.step-circle:not(:disabled) {
@@ -397,37 +397,37 @@
}
.step-circle.is-muted {
background: rgba(23, 32, 51, 0.04);
background: var(--app-control-subtle);
}
.approval-step.is-approved .step-circle {
background: #0f766e;
border-color: #0f766e;
color: #fffaf2;
background: var(--app-color-on-tertiary);
border-color: var(--app-color-on-tertiary);
color: var(--app-color-on-primary);
}
.approval-step.is-scheduled .step-circle {
background: #b45309;
border-color: #b45309;
color: #fffaf2;
color: var(--app-color-on-primary);
}
.approval-step.is-published .step-circle {
background: #7c3aed;
border-color: #7c3aed;
color: #fffaf2;
color: var(--app-color-on-primary);
}
.approval-step.is-current .step-circle {
background: #172033;
border-color: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
border-color: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.step-popover {
@apply pointer-events-none absolute left-[calc(100%+0.75rem)] top-0 z-20 flex w-[18rem] translate-y-2 flex-col gap-3 rounded-[1rem] border p-4 opacity-0 shadow-xl transition;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.12);
border-color: var(--app-border-subtle);
}
.approval-step:hover .step-popover,
@@ -447,7 +447,7 @@
.decision-row {
@apply flex items-start gap-3 rounded-[0.875rem] border p-3;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.decision-row div {

View File

@@ -114,13 +114,13 @@
<span>Replying to</span>
<strong>{{ replyTarget.authorDisplayName }}</strong>
</div>
<button
<v-btn variant="text" :ripple="false"
type="button"
title="Cancel reply"
@click="emit('cancel-reply')"
>
<v-icon :icon="mdiClose" />
</button>
</v-btn>
</div>
<div class="comment-composer-main">
@@ -148,20 +148,20 @@
class="selected-media-file"
>
<span>{{ form.mediaFile.name }}</span>
<button
<v-btn variant="text" :ripple="false"
type="button"
title="Remove selected media"
@click="clearMediaFile"
>
<v-icon :icon="mdiClose" />
</button>
</v-btn>
</div>
<div
v-if="form.showMentionPicker"
class="mention-picker"
>
<button
<v-btn variant="text" :ripple="false"
v-for="member in members"
:key="member.id"
class="mention-option"
@@ -174,7 +174,7 @@
size="sm"
/>
<span>{{ member.displayName }}</span>
</button>
</v-btn>
<div
v-if="!members.length"
@@ -208,7 +208,7 @@
hide-details
@update:model-value="selectMediaFile"
/>
<button
<v-btn variant="text" :ripple="false"
class="icon-tool-button"
type="button"
title="Mention a member"
@@ -216,8 +216,8 @@
@click="toggleMentionPicker"
>
<v-icon :icon="mdiAt" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="post-button"
type="button"
:disabled="!canSubmit"
@@ -225,7 +225,7 @@
>
<v-icon :icon="mdiSend" />
{{ isPosting ? 'Posting...' : 'Post' }}
</button>
</v-btn>
</div>
</div>
</div>
@@ -235,8 +235,8 @@
@reference "@/assets/main.css";
.comment-composer {
@apply flex flex-col gap-3 rounded-[1.25rem] border p-4;
background: #fffdf8;
border-color: rgba(23, 32, 51, 0.12);
background: var(--app-color-surface);
border-color: var(--app-border-subtle);
}
.comment-composer.reply {
@@ -259,28 +259,28 @@
}
.reply-context span {
color: #526178;
color: var(--app-text-muted);
}
.reply-context strong {
@apply truncate;
color: #172033;
color: var(--app-color-on-surface);
}
.reply-context button {
@apply inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition;
color: #526178;
color: var(--app-text-muted);
}
.reply-context button:hover,
.reply-context button:focus-visible {
background: rgba(15, 118, 110, 0.12);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.comment-textarea {
@apply min-h-24 flex-1 resize-y border-0 bg-transparent text-sm leading-6;
color: #172033;
color: var(--app-color-on-surface);
outline: none;
}
@@ -291,49 +291,49 @@
.selected-media-file {
@apply flex items-center justify-between gap-3 rounded-[1rem] border px-3 py-2 text-sm;
background: rgba(23, 32, 51, 0.03);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.selected-media-file span {
@apply min-w-0 truncate font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.selected-media-file button {
@apply inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition;
color: #526178;
color: var(--app-text-muted);
}
.selected-media-file button:hover,
.selected-media-file button:focus-visible {
background: rgba(185, 28, 28, 0.1);
color: #b91c1c;
color: var(--app-danger-muted);
}
.mention-picker {
@apply grid max-h-52 gap-2 overflow-y-auto rounded-[1rem] border p-2;
background: rgba(23, 32, 51, 0.03);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.mention-option {
@apply flex items-center gap-3 rounded-[0.875rem] px-2 py-2 text-left text-sm font-semibold transition;
color: #172033;
color: var(--app-color-on-surface);
}
.mention-option:hover {
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.empty-note {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.comment-composer-toolbar {
@apply flex items-center justify-end gap-2 border-t pt-3;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.internal-toggle {
@@ -355,20 +355,20 @@
.icon-tool-button {
@apply w-10;
background: rgba(23, 32, 51, 0.06);
color: #526178;
background: var(--app-control-hover);
color: var(--app-text-muted);
}
.icon-tool-button:hover,
.icon-tool-button.active {
background: rgba(15, 118, 110, 0.12);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.post-button {
@apply px-4;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.post-button:disabled {

View File

@@ -85,28 +85,28 @@
</div>
<div class="comment-actions">
<button
<v-btn variant="text" :ripple="false"
class="comment-action-button"
type="button"
title="Add reaction"
>
<v-icon :icon="mdiEmoticonPlusOutline" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="comment-action-button"
type="button"
title="Resolve"
>
<v-icon :icon="mdiCheckCircleOutline" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="comment-action-button"
type="button"
title="Reply"
@click="activeReplyCommentId = thread.comment.id"
>
<v-icon :icon="mdiReplyOutline" />
</button>
</v-btn>
<details class="comment-more-menu">
<summary
class="comment-action-button"
@@ -115,20 +115,20 @@
<v-icon :icon="mdiDotsVertical" />
</summary>
<div class="comment-action-menu">
<button
<v-btn variant="text" :ripple="false"
class="comment-menu-item"
type="button"
>
<v-icon :icon="mdiPencilOutline" />
Edit
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="comment-menu-item danger"
type="button"
>
<v-icon :icon="mdiDeleteOutline" />
Delete
</button>
</v-btn>
</div>
</details>
</div>
@@ -219,22 +219,22 @@
.empty-note {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.comment-row {
@apply relative flex flex-col gap-3 rounded-[1rem] border p-4 transition;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
outline: none;
}
.comment-row:hover,
.comment-row:focus-within,
.comment-row:focus {
background: #fffdf8;
background: var(--app-color-surface);
border-color: rgba(15, 118, 110, 0.24);
box-shadow: 0 16px 34px rgba(23, 32, 51, 0.08);
box-shadow: 0 16px 34px var(--app-border-subtle);
}
.comment-row-header {
@@ -251,7 +251,7 @@
.comment-author strong {
@apply truncate text-sm;
color: #172033;
color: var(--app-color-on-surface);
}
.comment-author small {
@@ -262,7 +262,7 @@
.comment-actions {
@apply absolute right-3 top-3 z-20 flex items-center gap-1 rounded-full border px-1 py-1 opacity-0 shadow-lg transition;
background: rgba(255, 255, 255, 0.92);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
pointer-events: none;
backdrop-filter: blur(10px);
}
@@ -276,13 +276,13 @@
.comment-action-button {
@apply inline-flex h-8 w-8 items-center justify-center rounded-full transition;
color: #526178;
color: var(--app-text-muted);
}
.comment-action-button:hover,
.comment-action-button:focus-visible {
background: rgba(15, 118, 110, 0.12);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.comment-more-menu {
@@ -299,7 +299,7 @@
.comment-more-menu[open] .comment-action-button {
background: rgba(15, 118, 110, 0.12);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.comment-more-menu[open] .comment-action-menu,
@@ -311,38 +311,38 @@
.comment-action-menu {
@apply absolute right-0 top-[calc(100%+0.375rem)] z-20 hidden min-w-36 flex-col gap-1 rounded-[0.875rem] border p-1 shadow-xl;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.comment-menu-item {
@apply flex items-center gap-2 rounded-[0.625rem] px-3 py-2 text-sm font-semibold transition;
color: #172033;
color: var(--app-color-on-surface);
}
.comment-menu-item:hover,
.comment-menu-item:focus-visible {
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.comment-menu-item.danger {
color: #b91c1c;
color: var(--app-danger-muted);
}
.comment-menu-item.danger:hover,
.comment-menu-item.danger:focus-visible {
background: rgba(185, 28, 28, 0.1);
color: #b91c1c;
color: var(--app-danger-muted);
}
.comment-body {
@apply whitespace-pre-line text-sm leading-6;
color: #172033;
color: var(--app-color-on-surface);
}
.comment-attachment {
@apply block w-fit max-w-full overflow-hidden rounded-[0.875rem] border;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
background: #ffffff;
}
@@ -372,7 +372,7 @@
.reply-meta strong {
@apply truncate text-sm;
color: #172033;
color: var(--app-color-on-surface);
}
.reply-meta small {
@@ -382,6 +382,6 @@
.reply-row p {
@apply whitespace-pre-line text-sm leading-6;
color: #172033;
color: var(--app-color-on-surface);
}
</style>

View File

@@ -583,7 +583,7 @@
}
function calendarEventColor(event) {
return calendarEventSource(event)?.color ?? '#0f766e';
return calendarEventSource(event)?.color ?? 'var(--app-color-on-tertiary)';
}
function formatDateTime(value) {
@@ -704,14 +704,14 @@
<template>
<section class="editor-shell">
<button
<v-btn variant="text" :ripple="false"
class="back-button"
type="button"
@click="navigateBackToContent"
>
<v-icon :icon="mdiArrowLeft" />
Back to content
</button>
</v-btn>
<div
v-if="!isCreateMode && detailStore.isLoading"
@@ -749,7 +749,7 @@
<span class="meta-chip">{{ item.currentRevisionLabel }}</span>
</div>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
:disabled="contentItemsStore.isCreating || detailStore.actions.revision"
@click="saveContent"
@@ -757,7 +757,7 @@
{{ isCreateMode
? (contentItemsStore.isCreating ? 'Creating...' : 'Create content')
: (detailStore.actions.revision ? 'Saving...' : 'Save revision') }}
</button>
</v-btn>
</div>
</div>
@@ -815,7 +815,7 @@
<div class="date-context field-wide">
<div class="date-context-days">
<button
<v-btn variant="text" :ripple="false"
v-for="day in dateContextDays"
:key="day.key"
class="date-context-day"
@@ -828,14 +828,14 @@
>
<span>{{ formatContextDay(day.date) }}</span>
<strong>{{ day.events.length }}</strong>
</button>
</v-btn>
</div>
<div
v-if="selectedDateCalendarEvents.length"
class="date-context-panel"
>
<button
<v-btn variant="text" :ripple="false"
v-for="event in selectedDateCalendarEvents"
:key="event.id"
class="calendar-context-pill"
@@ -844,7 +844,7 @@
@click="showCalendarEvent(event)"
>
{{ event.title }}
</button>
</v-btn>
</div>
<div
@@ -910,20 +910,20 @@
<div class="content-section">
<div class="section-title-row">
<strong>Channels and variants</strong>
<button
<v-btn variant="text" :ripple="false"
class="secondary-button"
type="button"
@click="addPlacement()"
>
Add channel
</button>
</v-btn>
</div>
<div
v-if="groupedChannels.length"
class="channel-suggestions"
>
<button
<v-btn variant="text" :ripple="false"
v-for="group in groupedChannels"
:key="group.network"
class="network-pill"
@@ -931,7 +931,7 @@
@click="addPlacement(group.channels[0])"
>
{{ group.network }}
</button>
</v-btn>
</div>
<div
@@ -948,13 +948,13 @@
<strong>{{ placement.channelName || placement.network || 'Channel' }}</strong>
<span>{{ placement.variantLabel || 'Custom variant' }}</span>
</div>
<button
<v-btn variant="text" :ripple="false"
class="link-button"
type="button"
@click="removePlacement(placement.id)"
>
Remove
</button>
</v-btn>
</div>
<div class="form-grid compact-grid">
@@ -1018,13 +1018,13 @@
<div class="media-section">
<div class="section-title-row">
<strong>Media</strong>
<button
<v-btn variant="text" :ripple="false"
class="secondary-button"
type="button"
@click="addMedia(placement)"
>
Add media
</button>
</v-btn>
</div>
<div
@@ -1063,13 +1063,13 @@
/>
</div>
<button
<v-btn variant="text" :ripple="false"
class="link-button"
type="button"
@click="removeMedia(placement, media.id)"
>
Remove media
</button>
</v-btn>
</div>
</div>
@@ -1108,7 +1108,7 @@
<template v-else>
<div class="tab-strip">
<button
<v-btn variant="text" :ripple="false"
v-for="tab in productionTabs"
:key="tab.key"
class="tab-button"
@@ -1118,7 +1118,7 @@
>
{{ tab.label }}
<span>{{ tab.count }}</span>
</button>
</v-btn>
</div>
<template v-if="activeProductionTab === 'comments'">
@@ -1200,13 +1200,13 @@
variant="outlined"
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="primary-button field-wide"
:disabled="detailStore.actions.asset"
@click="linkGoogleDriveAsset"
>
{{ detailStore.actions.asset ? 'Linking...' : 'Link asset' }}
</button>
</v-btn>
</div>
<div class="timeline-list">
@@ -1262,13 +1262,13 @@
variant="outlined"
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="secondary-button"
:disabled="detailStore.actions.assetRevision"
@click="addAssetRevision(asset)"
>
{{ detailStore.actions.assetRevision ? 'Adding...' : 'Add revision' }}
</button>
</v-btn>
</div>
</article>
@@ -1319,13 +1319,13 @@
<span>{{ activeCalendarEvent.source?.displayTitle ?? t('contentItems.calendar.importedEvent') }}</span>
<strong>{{ activeCalendarEvent.title }}</strong>
</div>
<button
<v-btn variant="text" :ripple="false"
class="link-button"
type="button"
@click="closeCalendarEvent"
>
{{ t('close') }}
</button>
</v-btn>
</div>
<p>{{ formatCalendarDate(activeCalendarEvent.startDate) }}</p>
@@ -1333,13 +1333,13 @@
<p v-if="activeCalendarEvent.location">{{ activeCalendarEvent.location }}</p>
<div class="calendar-event-actions">
<button
<v-btn variant="text" :ripple="false"
class="secondary-button"
type="button"
@click="navigateToCalendarDay(activeCalendarEvent)"
>
{{ t('contentItems.dateContext.viewDay') }}
</button>
</v-btn>
</div>
</div>
</div>
@@ -1356,28 +1356,28 @@
.page-message {
@apply rounded-[1.25rem] border p-4 text-sm;
background: rgba(255, 255, 255, 0.9);
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);
}
.editor-header {
@apply flex flex-col gap-4 rounded-[1.75rem] border p-6 lg:flex-row lg:items-start lg:justify-between;
background: rgba(255, 255, 255, 0.92);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.24em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.editor-header h1 {
@apply mt-2 text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.editor-header p,
@@ -1388,7 +1388,7 @@
.placement-header span,
.section-title-row span {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.header-actions,
@@ -1398,8 +1398,8 @@
.meta-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);
}
.back-button,
@@ -1411,23 +1411,23 @@
.back-button {
@apply w-fit border;
background: rgba(255, 255, 255, 0.88);
border-color: rgba(23, 32, 51, 0.12);
color: #172033;
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.back-button:hover {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.primary-button {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.secondary-button {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.editor-grid {
@@ -1437,13 +1437,13 @@
.work-panel {
@apply grid min-w-0 grid-cols-[2.75rem_minmax(0,1fr)] items-start gap-4 rounded-[1.75rem] border p-5;
background: rgba(255, 255, 255, 0.9);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.panel {
@apply flex min-h-0 flex-col gap-5 rounded-[1.75rem] border p-5;
background: rgba(255, 255, 255, 0.9);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.side-panel {
@@ -1464,7 +1464,7 @@
.section-title-row strong,
.placement-header strong,
.timeline-row strong {
color: #172033;
color: var(--app-color-on-surface);
}
.panel-stack,
@@ -1495,16 +1495,16 @@
.field span {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.field input,
.field select,
.field textarea {
@apply rounded-[1rem] border px-4 py-3 text-sm;
background: #fffdf8;
border-color: rgba(23, 32, 51, 0.12);
color: #172033;
background: var(--app-color-surface);
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
outline: none;
}
@@ -1526,8 +1526,8 @@
.date-context-day {
@apply flex min-h-14 flex-col items-start justify-between rounded-[0.875rem] border px-3 py-2 text-left transition;
background: rgba(255, 253, 248, 0.9);
border-color: rgba(23, 32, 51, 0.08);
color: #526178;
border-color: var(--app-border-subtle);
color: var(--app-text-muted);
}
.date-context-day span {
@@ -1536,25 +1536,25 @@
.date-context-day strong {
@apply h-5 min-w-5 rounded-full px-1.5 text-center text-xs leading-5;
background: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.date-context-day.marked {
border-color: rgba(15, 118, 110, 0.32);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.date-context-day.marked strong,
.date-context-day.active strong {
background: #0f766e;
color: #fffaf2;
background: var(--app-color-on-tertiary);
color: var(--app-color-on-primary);
}
.date-context-day.active {
background: #172033;
border-color: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
border-color: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.date-context-panel {
@@ -1565,23 +1565,23 @@
@apply rounded-full border px-3 py-1.5 text-xs font-bold transition;
background: color-mix(in srgb, var(--calendar-color) 12%, white);
border-color: color-mix(in srgb, var(--calendar-color) 34%, white);
color: #172033;
color: var(--app-color-on-surface);
}
.calendar-context-pill:hover {
background: var(--calendar-color);
color: #fffaf2;
color: var(--app-color-on-primary);
}
.date-context-empty {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.hashtags-input-shell {
@apply flex flex-wrap items-center gap-2 rounded-[1rem] border px-4 py-3;
background: #fffdf8;
border-color: rgba(23, 32, 51, 0.12);
background: var(--app-color-surface);
border-color: var(--app-border-subtle);
}
.hashtags-editor {
@@ -1590,7 +1590,7 @@
.hashtags-inline-input {
@apply min-w-[12rem] flex-1 border-0 bg-transparent p-0 text-sm;
color: #172033;
color: var(--app-color-on-surface);
outline: none;
}
@@ -1600,9 +1600,9 @@
.network-pill {
@apply rounded-full border px-4 py-2 text-xs font-bold uppercase tracking-[0.16em];
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-control-subtle);
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.channel-suggestions {
@@ -1612,8 +1612,8 @@
.placement-card,
.media-card {
@apply 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);
}
.identity-row {
@@ -1627,7 +1627,7 @@
.timeline-row {
@apply flex flex-col gap-3 rounded-[1rem] border p-4;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.timeline-row-header {
@@ -1637,7 +1637,7 @@
.timeline-row p,
.asset-revision-row p {
@apply text-sm leading-6;
color: #172033;
color: var(--app-color-on-surface);
}
.timeline-actions {
@@ -1654,14 +1654,14 @@
.tab-button {
@apply flex items-center justify-between gap-2 rounded-[1rem] border px-3 py-2 text-sm font-bold transition;
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-control-subtle);
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.tab-button.active {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.tab-button span {
@@ -1675,25 +1675,25 @@
.asset-card {
@apply flex flex-col gap-4 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);
}
.asset-card .timeline-row-header span,
.asset-revision-row small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.asset-link {
@apply w-fit text-sm font-semibold;
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.revision-pill {
@apply rounded-full px-3 py-1 text-xs font-bold;
background: rgba(15, 118, 110, 0.12);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.asset-revisions {
@@ -1703,12 +1703,12 @@
.asset-revision-row {
@apply rounded-[0.875rem] border px-3 py-2;
background: rgba(255, 255, 255, 0.7);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.asset-revision-row span {
@apply mr-2 text-sm font-bold;
color: #172033;
color: var(--app-color-on-surface);
}
.compact-form {
@@ -1717,7 +1717,7 @@
.link-button {
@apply text-sm font-semibold;
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.calendar-event-popover {
@@ -1726,8 +1726,8 @@
.calendar-event-card {
@apply flex w-full max-w-md flex-col gap-4 rounded-[1.25rem] border p-5 shadow-2xl;
background: #fffdf8;
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-color-surface);
border-color: var(--app-border-subtle);
}
.calendar-event-header {
@@ -1741,12 +1741,12 @@
.calendar-event-header span,
.calendar-event-card p {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.calendar-event-header strong {
@apply text-xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.calendar-event-actions {

View File

@@ -484,6 +484,12 @@
calendarStore.toggleSourceVisibility(sourceId);
}
function setSourceVisibility(sourceId, visible) {
if (sourceIsVisible(sourceId) !== visible) {
calendarStore.toggleSourceVisibility(sourceId);
}
}
function toggleColorPalette(sourceId) {
activeColorSourceId.value = activeColorSourceId.value === sourceId ? '' : sourceId;
}
@@ -866,26 +872,26 @@
>
<div class="calendar-toolbar">
<div class="range-selector">
<button
<v-btn variant="text" :ripple="false"
class="toggle-button"
:class="{ 'toggle-button-active': viewMode === 'month' }"
type="button"
@click="setView('month')"
>
{{ t('dashboard.month') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="toggle-button"
:class="{ 'toggle-button-active': viewMode === 'week' }"
type="button"
@click="setView('week')"
>
{{ t('dashboard.week') }}
</button>
</v-btn>
</div>
<div class="calendar-nav">
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
:title="previousPeriodLabel"
@@ -893,11 +899,11 @@
@click="shiftPeriod(-1)"
>
<v-icon :icon="mdiChevronLeft" />
</button>
</v-btn>
<div class="calendar-period">{{ periodLabel }}</div>
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
:title="nextPeriodLabel"
@@ -905,20 +911,20 @@
@click="shiftPeriod(1)"
>
<v-icon :icon="mdiChevronRight" />
</button>
</v-btn>
</div>
<button
<v-btn variant="text" :ripple="false"
v-if="!isTodayVisible"
class="text-button"
type="button"
@click="jumpToToday"
>
{{ t('dashboard.today') }}
</button>
</v-btn>
<div class="calendar-selector">
<button
<v-btn variant="text" :ripple="false"
class="calendar-selector-button"
type="button"
@click="isCalendarSelectorOpen = !isCalendarSelectorOpen"
@@ -926,7 +932,7 @@
<span>{{ t('contentItems.calendar.calendars') }}</span>
<strong>{{ visibleCalendarSourceCount }}/{{ availableCalendarSources.length }}</strong>
<v-icon :icon="mdiChevronDown" />
</button>
</v-btn>
<div
v-if="isCalendarSelectorOpen"
@@ -938,7 +944,7 @@
class="calendar-selector-row"
>
<span class="source-color-control">
<button
<v-btn variant="text" :ripple="false"
class="source-swatch-button"
type="button"
:disabled="source.isReadOnly"
@@ -949,7 +955,7 @@
class="source-swatch"
:style="{ background: source.color }"
/>
</button>
</v-btn>
<ColorPalette
v-if="activeColorSourceId === source.id"
@@ -960,19 +966,23 @@
@update:model-value="color => updateSourceColor(source, color)"
/>
</span>
<button
<v-btn variant="text" :ripple="false"
class="calendar-selector-title"
type="button"
@click="toggleSource(source.id)"
>
{{ source.displayTitle }}
</button>
<button
</v-btn>
<v-switch
class="visibility-switch"
:class="{ active: sourceIsVisible(source.id) }"
type="button"
:model-value="sourceIsVisible(source.id)"
:aria-label="source.displayTitle"
@click="toggleSource(source.id)"
color="primary"
density="compact"
hide-details
inset
@click.stop
@update:model-value="visible => setSourceVisibility(source.id, visible)"
/>
</div>
@@ -983,14 +993,14 @@
{{ t('contentItems.calendar.noCalendars') }}
</div>
<button
<v-btn variant="text" :ripple="false"
class="calendar-selector-add"
type="button"
@click="openAddCalendar"
>
<v-icon :icon="mdiCalendarPlus" />
<span>{{ t('contentItems.calendar.addCalendar') }}</span>
</button>
</v-btn>
</div>
</div>
</div>
@@ -1031,7 +1041,7 @@
v-for="entry in viewMode === 'month' ? day.entries.slice(0, 3) : day.entries"
:key="`${entry.type}-${entry.id}`"
>
<button
<v-btn variant="text" :ripple="false"
v-if="entry.type === 'imported-calendar'"
class="calendar-entry calendar-context-entry"
:class="entry.tone"
@@ -1041,7 +1051,7 @@
@click="createFromImportedEvent(entry)"
>
<span class="calendar-event-chip">{{ entry.title }}</span>
</button>
</v-btn>
<router-link
v-else-if="entry.type === 'content'"
@@ -1136,7 +1146,7 @@
v-for="entry in upcomingEntries"
:key="`${entry.type}-${entry.id}`"
>
<button
<v-btn variant="text" :ripple="false"
v-if="entry.type === 'imported-calendar'"
class="item-card calendar-upcoming-card"
:style="entryStyle(entry)"
@@ -1150,7 +1160,7 @@
<em>{{ entry.timeLabel }}</em>
<small>{{ formatEntryDate(entry.scheduledAt) }}</small>
</div>
</button>
</v-btn>
<router-link
v-else-if="entry.type === 'content'"
@@ -1274,32 +1284,32 @@
<div class="calendar-dialog">
<div class="dialog-header">
<strong>{{ t('contentItems.calendar.addCalendar') }}</strong>
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
@click="isAddCalendarOpen = false"
>
<v-icon :icon="mdiClose" />
</button>
</v-btn>
</div>
<div class="add-mode-toggle">
<button
<v-btn variant="text" :ripple="false"
class="toggle-button"
:class="{ 'toggle-button-active': activeAddMode === 'catalog' }"
type="button"
@click="activeAddMode = 'catalog'"
>
{{ t('contentItems.calendar.catalog') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="toggle-button"
:class="{ 'toggle-button-active': activeAddMode === 'custom' }"
type="button"
@click="activeAddMode = 'custom'"
>
{{ t('contentItems.calendar.customIcs') }}
</button>
</v-btn>
</div>
<v-radio-group
@@ -1344,18 +1354,18 @@
hide-details
:placeholder="t('contentItems.calendar.category')"
/>
<button
<v-btn variant="text" :ripple="false"
class="text-button"
type="button"
@click="searchCatalog"
>
<v-icon :icon="mdiMagnify" />
<span>{{ t('contentItems.calendar.search') }}</span>
</button>
</v-btn>
</div>
<div class="catalog-results">
<button
<v-btn variant="text" :ripple="false"
v-for="entry in calendarStore.catalogEntries"
:key="entry.id"
class="catalog-entry"
@@ -1374,7 +1384,7 @@
? t('contentItems.calendar.alreadyAdded')
: `${entry.providerName} · ${entry.category}` }}
</span>
</button>
</v-btn>
</div>
</div>
@@ -1413,13 +1423,13 @@
hide-details
:placeholder="t('contentItems.calendar.category')"
/>
<button
<v-btn variant="text" :ripple="false"
class="text-button"
type="submit"
>
<v-icon :icon="mdiPlus" />
<span>{{ t('contentItems.calendar.addCalendar') }}</span>
</button>
</v-btn>
</div>
</v-form>
@@ -1444,13 +1454,13 @@
.status-row em,
.status-row small {
@apply text-sm leading-6 not-italic;
color: #526178;
color: var(--app-text-muted);
}
.range-selector {
@apply inline-flex w-fit rounded-full border p-1;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.calendar-selector {
@@ -1460,26 +1470,26 @@
.calendar-selector-button {
@apply inline-flex min-h-11 w-full items-center justify-between gap-2 rounded-full border px-4 py-2 text-sm font-bold transition sm:w-auto;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
}
.calendar-selector-button strong {
@apply rounded-full px-2 py-0.5 text-xs;
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.calendar-selector-menu {
@apply absolute right-0 top-[calc(100%+0.5rem)] z-30 flex w-full min-w-72 flex-col gap-1 rounded-[1rem] border p-2 shadow-xl sm:w-80;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.calendar-selector-row,
.calendar-selector-add {
@apply flex min-h-11 w-full items-center gap-3 rounded-[0.75rem] px-3 text-left text-sm font-semibold transition;
color: #172033;
color: var(--app-color-on-surface);
}
.calendar-selector-row:hover,
@@ -1500,7 +1510,7 @@
}
.source-swatch-button:not(:disabled):hover {
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
}
.source-swatch-button:disabled {
@@ -1513,32 +1523,17 @@
.calendar-selector-empty {
@apply px-3 py-2 text-sm;
color: #526178;
color: var(--app-text-muted);
}
.calendar-selector-add {
@apply border-t;
border-color: rgba(23, 32, 51, 0.08);
color: #0f766e;
border-color: var(--app-border-subtle);
color: var(--app-color-on-tertiary);
}
.visibility-switch {
@apply relative h-6 w-10 shrink-0 rounded-full transition;
background: rgba(148, 163, 184, 0.35);
}
.visibility-switch::after {
@apply absolute left-1 top-1 h-4 w-4 rounded-full bg-white transition;
content: '';
box-shadow: 0 1px 4px rgba(23, 32, 51, 0.2);
}
.visibility-switch.active {
background: #0f766e;
}
.visibility-switch.active::after {
transform: translateX(1rem);
@apply shrink-0;
}
.toggle-button,
@@ -1546,8 +1541,8 @@
.text-button {
@apply inline-flex items-center justify-center rounded-full border px-3 py-2 text-sm font-semibold transition;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
}
.toggle-button {
@@ -1555,7 +1550,7 @@
}
.toggle-button-active {
background: #172033;
background: var(--app-color-on-surface);
color: #ffffff;
}
@@ -1573,16 +1568,16 @@
.item-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);
}
.page-message {
@apply p-5 text-sm;
color: #526178;
color: var(--app-text-muted);
}
.page-message.error {
color: #b91c1c;
color: var(--app-danger-muted);
}
.calendar-card {
@@ -1604,7 +1599,7 @@
.calendar-period {
@apply min-w-0 px-2 text-base font-bold md:text-lg;
color: #172033;
color: var(--app-color-on-surface);
}
.source-swatch {
@@ -1622,12 +1617,12 @@
.weekday-label {
@apply px-2 text-xs font-bold uppercase tracking-[0.16em];
color: #526178;
color: var(--app-text-muted);
}
.calendar-day {
@apply min-h-[8rem] overflow-visible rounded-[1rem] border p-2.5;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.calendar-day-week {
@@ -1645,7 +1640,7 @@
.day-number {
@apply mb-2 text-sm font-bold;
color: #172033;
color: var(--app-color-on-surface);
}
.day-entries,
@@ -1674,12 +1669,12 @@
.calendar-entry strong,
.item-card strong {
@apply text-sm font-bold;
color: #172033;
color: var(--app-color-on-surface);
}
.calendar-entry span {
@apply text-xs leading-5;
color: #526178;
color: var(--app-text-muted);
}
.content-calendar-entry,
@@ -1707,13 +1702,13 @@
}
.campaign-chip {
background: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.hashtag-chip {
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.content-preview {
@@ -1734,7 +1729,7 @@
.content-preview span {
@apply text-xs leading-5;
-webkit-line-clamp: 2;
color: #526178;
color: var(--app-text-muted);
}
.content-meta-row {
@@ -1747,7 +1742,7 @@
.planned-time {
@apply gap-1 text-[0.7rem] font-bold uppercase;
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.planned-time i,
@@ -1757,12 +1752,12 @@
.channel-icons {
@apply justify-end gap-1;
color: #526178;
color: var(--app-text-muted);
}
.entry-time {
@apply text-[0.7rem] font-bold uppercase tracking-[0.12em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.calendar-event-chip {
@@ -1773,7 +1768,7 @@
.entry-more,
.day-empty {
@apply px-1 text-xs font-semibold;
color: #526178;
color: var(--app-text-muted);
}
.calendar-entry.production {
@@ -1825,7 +1820,7 @@
.calendar-dialog {
@apply flex flex-col gap-4 rounded-[1.5rem] border bg-white p-5;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.dialog-header,
@@ -1842,13 +1837,13 @@
.dialog-header strong {
@apply text-lg font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.scope-option {
@apply inline-flex items-center gap-2 rounded-full border px-3 py-2 text-sm font-semibold;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
}
.catalog-panel,
@@ -1860,8 +1855,8 @@
.catalog-search input,
.custom-calendar-form input {
@apply min-h-11 rounded-[0.75rem] border px-3 text-sm;
border-color: rgba(23, 32, 51, 0.12);
color: #172033;
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.catalog-search input[type='search'],
@@ -1876,7 +1871,7 @@
.catalog-entry {
@apply grid min-h-14 grid-cols-[auto_minmax(0,1fr)] items-center gap-x-3 rounded-[0.75rem] border px-3 py-2 text-left transition;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: #ffffff;
}
@@ -1895,17 +1890,17 @@
.catalog-entry strong {
@apply text-sm font-bold;
color: #172033;
color: var(--app-color-on-surface);
}
.catalog-entry span:last-child {
@apply col-start-2 text-xs;
color: #526178;
color: var(--app-text-muted);
}
.dialog-error {
@apply text-sm font-semibold;
color: #b91c1c;
color: var(--app-danger-muted);
}
.item-grid {
@@ -1918,8 +1913,8 @@
.version-chip {
@apply w-fit 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);
}
.version-chip.calendar-event-chip {
@@ -1933,39 +1928,39 @@
.content-table-shell {
@apply overflow-x-auto rounded-[1.5rem] border;
background: rgba(255, 255, 255, 0.94);
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-surface-glass);
border-color: var(--app-border-subtle);
}
.content-table {
@apply w-full min-w-[52rem] border-collapse text-left text-sm;
color: #526178;
color: var(--app-text-muted);
}
.content-table th {
@apply px-5 py-4 text-xs font-black uppercase tracking-[0.14em];
background: #f8fafc;
color: #172033;
color: var(--app-color-on-surface);
}
.content-table td {
@apply border-t px-5 py-4 align-middle;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.content-table-title {
@apply font-bold no-underline;
color: #172033;
color: var(--app-color-on-surface);
}
.content-table-title:hover {
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.table-status {
@apply inline-flex rounded-full px-3 py-1 text-xs font-bold;
background: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
@media (max-width: 960px) {

View File

@@ -109,7 +109,7 @@
.panel,
.status-panel {
@apply rounded-[1.75rem] border;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.9);
}
@@ -117,17 +117,17 @@
@apply p-6 md:p-8;
background:
radial-gradient(circle at top left, rgba(14, 165, 164, 0.18), transparent 45%),
linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(240, 249, 255, 0.92));
linear-gradient(135deg, var(--app-surface-raised), rgba(240, 249, 255, 0.92));
}
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.24em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.hero-copy h1 {
@apply mt-3 text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.hero-copy p,
@@ -138,7 +138,7 @@
.status-copy p,
.status-label span {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.hero-card {
@@ -158,13 +158,13 @@
.media-type-item {
@apply w-fit rounded-full px-3 py-2;
background: rgba(15, 118, 110, 0.08);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.hero-card strong,
.panel-header strong,
.status-copy strong {
color: #172033;
color: var(--app-color-on-surface);
}
.hero-card strong {
@@ -196,16 +196,16 @@
.media-type-item,
.workflow-item {
@apply rounded-[1.1rem] border px-4 py-3;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(248, 250, 252, 0.9);
}
.workflow-icon {
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.status-panel {
background: linear-gradient(135deg, rgba(255, 247, 237, 0.95), rgba(255, 255, 255, 0.98));
background: linear-gradient(135deg, rgba(255, 247, 237, 0.95), var(--app-surface-raised));
}
.status-copy {
@@ -214,7 +214,7 @@
.status-label {
@apply text-xs font-bold uppercase tracking-[0.2em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.status-copy strong {

View File

@@ -14,7 +14,7 @@
class="feedback-entry"
data-feedback-ui="true"
>
<button
<v-btn variant="text" :ripple="false"
class="feedback-entry-button"
type="button"
:title="t('feedback.open')"
@@ -22,7 +22,7 @@
>
<v-icon :icon="mdiMessageAlertOutline" />
<span>{{ t('feedback.button') }}</span>
</button>
</v-btn>
<FeedbackSubmissionDialog v-model="isDialogOpen" />
</div>

View File

@@ -136,7 +136,7 @@
await nextTick();
const target = document.querySelector('.shell-container') ?? document.body;
const canvas = await html2canvas(target, {
backgroundColor: '#fffaf2',
backgroundColor: 'var(--app-color-on-primary)',
height: window.innerHeight,
ignoreElements: element => element.dataset?.feedbackUi === 'true',
scale: Math.min(window.devicePixelRatio || 1, 2),
@@ -484,14 +484,14 @@
<p>{{ t('feedback.eyebrow') }}</p>
<h2>{{ t('feedback.title') }}</h2>
</div>
<button
<v-btn variant="text" :ripple="false"
class="feedback-icon-button"
type="button"
:title="t('close')"
@click="requestClose"
>
<v-icon :icon="mdiClose" />
</button>
</v-btn>
</header>
<div class="feedback-dialog-body">
@@ -549,7 +549,7 @@
class="feedback-editor"
>
<div class="feedback-toolstrip">
<button
<v-btn variant="text" :ripple="false"
v-for="tool in annotationTools"
:key="tool.value"
class="feedback-tool-button"
@@ -559,24 +559,24 @@
@click="selectedTool = tool.value"
>
<v-icon :icon="tool.icon" />
</button>
</v-btn>
<span class="feedback-tool-divider"></span>
<button
<v-btn variant="text" :ripple="false"
class="feedback-tool-button"
type="button"
:title="t('feedback.tools.undo')"
@click="undoAnnotation"
>
<v-icon :icon="mdiUndoVariant" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="feedback-tool-button"
type="button"
:title="t('feedback.tools.clear')"
@click="clearAnnotations"
>
<v-icon :icon="mdiRedoVariant" />
</button>
</v-btn>
</div>
<canvas
@@ -623,26 +623,26 @@
@reference "@/assets/main.css";
.feedback-dialog {
@apply overflow-hidden rounded-lg border;
background: #fffaf2;
border-color: rgba(23, 32, 51, 0.12);
color: #172033;
background: var(--app-color-on-primary);
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.feedback-dialog-header,
.feedback-dialog-footer {
@apply flex items-center justify-between gap-4 px-5 py-4;
border-bottom: 1px solid rgba(23, 32, 51, 0.08);
border-bottom: 1px solid var(--app-border-subtle);
}
.feedback-dialog-footer {
@apply justify-end;
border-bottom: 0;
border-top: 1px solid rgba(23, 32, 51, 0.08);
border-top: 1px solid var(--app-border-subtle);
}
.feedback-dialog-header p {
@apply text-xs font-black uppercase;
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.feedback-dialog-header h2 {
@@ -652,15 +652,15 @@
.feedback-icon-button,
.feedback-tool-button {
@apply flex h-10 w-10 items-center justify-center rounded-full transition-colors;
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.feedback-icon-button:hover,
.feedback-tool-button:hover,
.feedback-tool-button-active {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.feedback-dialog-body {
@@ -694,7 +694,7 @@
@apply block w-full rounded-md border;
max-height: 58vh;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.12);
border-color: var(--app-border-subtle);
cursor: crosshair;
object-fit: contain;
}
@@ -703,7 +703,7 @@
@apply flex min-h-[18rem] flex-col items-center justify-center gap-3 rounded-md border border-dashed text-sm;
background: rgba(23, 32, 51, 0.03);
border-color: rgba(23, 32, 51, 0.16);
color: #526178;
color: var(--app-text-muted);
}
.feedback-empty-preview i {

View File

@@ -184,14 +184,14 @@
<template>
<section class="feedback-detail-page">
<button
<v-btn variant="text" :ripple="false"
class="back-button"
type="button"
@click="router.push({ name: 'developer-feedback' })"
>
<v-icon :icon="mdiArrowLeft" />
{{ t('feedback.review.detail.back') }}
</button>
</v-btn>
<div
v-if="feedbackStore.isDetailLoading"
@@ -242,7 +242,7 @@
<section class="panel">
<div class="panel-header">
<strong>{{ t('feedback.review.detail.screenshot') }}</strong>
<button
<v-btn variant="text" :ripple="false"
v-if="report.screenshot"
class="small-button"
type="button"
@@ -250,8 +250,8 @@
>
<v-icon :icon="mdiDownloadOutline" />
{{ t('feedback.review.detail.download') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
v-if="report.screenshot"
class="small-button"
type="button"
@@ -259,7 +259,7 @@
>
<v-icon :icon="mdiOpenInNew" />
{{ t('feedback.review.detail.openOriginal') }}
</button>
</v-btn>
</div>
<div
@@ -329,13 +329,13 @@
variant="outlined"
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="submit"
:disabled="!canSubmitComment"
>
{{ feedbackStore.isCommenting ? t('feedback.review.detail.commenting') : t('feedback.review.detail.addComment') }}
</button>
</v-btn>
</v-form>
</section>
</main>
@@ -384,14 +384,14 @@
</template>
</v-combobox>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="button"
:disabled="feedbackStore.isSaving"
@click="saveReviewChanges"
>
{{ feedbackStore.isSaving ? t('common.saving') : t('save') }}
</button>
</v-btn>
</section>
<section class="panel">
@@ -459,20 +459,20 @@
.back-button,
.small-button {
border-color: rgba(23, 32, 51, 0.12);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.88);
color: #172033;
color: var(--app-color-on-surface);
}
.back-button:hover,
.small-button:hover {
background: #172033;
background: var(--app-color-on-surface);
color: white;
}
.primary-button {
border-color: #0f766e;
background: #0f766e;
border-color: var(--app-color-on-tertiary);
background: var(--app-color-on-tertiary);
color: white;
}
@@ -482,18 +482,18 @@
.detail-header {
@apply rounded-lg border p-5;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.88);
}
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.detail-header h1 {
@apply mt-2 line-clamp-3 text-2xl font-black md:text-3xl;
color: #172033;
color: var(--app-color-on-surface);
}
.header-meta,
@@ -505,7 +505,7 @@
.file-meta span {
@apply rounded-md px-2.5 py-1 text-xs font-bold;
background: rgba(15, 118, 110, 0.08);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.detail-grid {
@@ -519,7 +519,7 @@
.panel {
@apply rounded-lg border p-5;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.9);
}
@@ -529,7 +529,7 @@
.panel-header strong {
@apply text-base font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.description {
@@ -545,7 +545,7 @@
.screenshot-frame {
@apply overflow-hidden rounded-lg border;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
background: #0f172a;
}
@@ -556,14 +556,14 @@
.empty-block,
.page-message {
@apply rounded-lg border p-4 text-sm font-semibold;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(248, 250, 252, 0.9);
color: #526178;
color: var(--app-text-muted);
}
.page-message-error {
border-color: rgba(220, 38, 38, 0.24);
color: #b91c1c;
color: var(--app-danger-muted);
}
.timeline {
@@ -572,7 +572,7 @@
.timeline-item {
@apply rounded-lg border p-4;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(248, 250, 252, 0.78);
}
@@ -586,7 +586,7 @@
.timeline-item strong {
@apply text-sm font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.timeline-item span,
@@ -619,6 +619,6 @@
.info-list dd {
@apply mt-1 break-words text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
</style>

View File

@@ -70,14 +70,14 @@
<p>{{ t('feedback.review.description') }}</p>
</div>
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
:title="t('feedback.review.refresh')"
@click="feedbackStore.loadReports"
>
<v-icon :icon="mdiRefresh" />
</button>
</v-btn>
</header>
<section class="metric-grid">
@@ -186,14 +186,14 @@
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="filter-reset"
type="button"
:title="t('feedback.review.filters.clear')"
@click="feedbackStore.resetFilters"
>
<v-icon :icon="mdiFilterOffOutline" />
</button>
</v-btn>
</section>
<div
@@ -214,7 +214,7 @@
v-else
class="report-table"
>
<button
<v-btn variant="text" :ripple="false"
v-for="report in feedbackStore.filteredReports"
:key="report.id"
class="report-row"
@@ -263,7 +263,7 @@
/>
</small>
</span>
</button>
</v-btn>
<div
v-if="!feedbackStore.filteredReports.length"
@@ -287,30 +287,30 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.review-header h1 {
@apply mt-2 text-3xl font-black md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.review-header p {
@apply mt-2 max-w-3xl text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.icon-button,
.filter-reset {
@apply inline-flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-lg border transition-colors;
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);
}
.icon-button:hover,
.filter-reset:hover {
background: #172033;
background: var(--app-color-on-surface);
color: white;
}
@@ -320,7 +320,7 @@
.metric {
@apply rounded-lg border p-4;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.86);
}
@@ -331,12 +331,12 @@
.metric strong {
@apply mt-2 block text-3xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.filter-panel {
@apply grid gap-3 rounded-lg border p-4 lg:grid-cols-[minmax(15rem,1.5fr)_repeat(4,minmax(9rem,1fr))_repeat(2,minmax(8rem,0.8fr))_minmax(10rem,1fr)_auto];
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.9);
}
@@ -345,7 +345,7 @@
@apply flex h-10 items-center gap-2 rounded-lg border px-3 text-sm;
border-color: rgba(23, 32, 51, 0.16);
background: white;
color: #172033;
color: var(--app-color-on-surface);
}
.filter-search input {
@@ -362,7 +362,7 @@
.report-row {
@apply grid gap-4 rounded-lg border p-4 text-left transition-colors lg:grid-cols-[minmax(0,1.55fr)_minmax(12rem,0.8fr)_minmax(12rem,0.8fr)_minmax(12rem,0.7fr)] lg:items-center;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.86);
}
@@ -383,13 +383,13 @@
.report-title strong {
@apply text-sm font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.report-title em {
@apply rounded-md px-2 py-1 text-xs font-bold not-italic;
background: rgba(15, 118, 110, 0.08);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.status-dot {
@@ -402,7 +402,7 @@
}
.status-planned {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
.status-resolved {
@@ -416,7 +416,7 @@
.report-description {
@apply line-clamp-2 text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.report-tags {
@@ -425,7 +425,7 @@
.report-tags span {
@apply inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-semibold;
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
color: #44516a;
}
@@ -433,7 +433,7 @@
.report-context,
.report-activity strong {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.report-secondary small,
@@ -449,13 +449,13 @@
.page-message {
@apply rounded-lg border p-4 text-sm font-semibold;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.86);
color: #526178;
color: var(--app-text-muted);
}
.page-message-error {
border-color: rgba(220, 38, 38, 0.24);
color: #b91c1c;
color: var(--app-danger-muted);
}
</style>

View File

@@ -100,14 +100,14 @@
<template>
<section class="feedback-detail-page">
<button
<v-btn variant="text" :ripple="false"
class="back-button"
type="button"
@click="router.push({ name: 'my-feedback' })"
>
<v-icon :icon="mdiArrowLeft" />
{{ t('feedback.mine.detail.back') }}
</button>
</v-btn>
<div
v-if="feedbackStore.isDetailLoading"
@@ -134,7 +134,7 @@
</div>
</div>
<button
<v-btn variant="text" :ripple="false"
v-if="canCancel"
class="cancel-button"
type="button"
@@ -143,7 +143,7 @@
>
<v-icon :icon="mdiCancel" />
{{ feedbackStore.isCancelling ? t('common.saving') : t('feedback.mine.detail.cancel') }}
</button>
</v-btn>
</header>
<div class="detail-grid">
@@ -230,14 +230,14 @@
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="button"
:disabled="!canSubmitComment"
@click="submitComment"
>
{{ feedbackStore.isCommenting ? t('feedback.review.detail.commenting') : t('feedback.review.detail.addComment') }}
</button>
</v-btn>
</section>
</aside>
</div>
@@ -258,19 +258,19 @@
}
.back-button {
color: #0f766e;
color: var(--app-color-on-tertiary);
background: rgba(15, 118, 110, 0.08);
}
.cancel-button {
border: 1px solid rgba(220, 38, 38, 0.24);
color: #b91c1c;
color: var(--app-danger-muted);
background: white;
}
.primary-button {
@apply mt-3 justify-center;
background: #172033;
background: var(--app-color-on-surface);
color: white;
}
@@ -285,12 +285,12 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.detail-header h1 {
@apply mt-2 max-w-4xl text-2xl font-black leading-tight md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.header-meta {
@@ -300,7 +300,7 @@
.header-meta span {
@apply rounded-md px-2 py-1;
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
}
.detail-grid {
@@ -315,7 +315,7 @@
.panel,
.page-message {
@apply rounded-lg border p-4;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.9);
}
@@ -325,18 +325,18 @@
.panel-header strong {
@apply text-sm font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.description {
@apply whitespace-pre-wrap text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.path-link {
@apply mt-3 inline-flex max-w-full items-center gap-2 truncate rounded-md px-2 py-1 text-sm font-semibold;
background: rgba(15, 118, 110, 0.08);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.tag-row {
@@ -345,7 +345,7 @@
.tag-row span {
@apply inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-semibold;
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
color: #44516a;
}
@@ -360,7 +360,7 @@
.timeline li {
@apply rounded-lg border p-3;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(248, 250, 252, 0.75);
}
@@ -372,7 +372,7 @@
.timeline strong {
@apply text-sm font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.timeline span,
@@ -385,11 +385,11 @@
.timeline p {
@apply my-2 whitespace-pre-wrap text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.page-message-error {
border-color: rgba(220, 38, 38, 0.24);
color: #b91c1c;
color: var(--app-danger-muted);
}
</style>

View File

@@ -43,14 +43,14 @@
<p>{{ t('feedback.mine.description') }}</p>
</div>
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
:title="t('feedback.mine.refresh')"
@click="feedbackStore.loadReports"
>
<v-icon :icon="mdiRefresh" />
</button>
</v-btn>
</header>
<section class="metric-grid">
@@ -98,14 +98,14 @@
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
:title="t('feedback.review.filters.clear')"
@click="feedbackStore.resetFilters"
>
<v-icon :icon="mdiFilterOffOutline" />
</button>
</v-btn>
</section>
<div
@@ -126,7 +126,7 @@
v-else
class="report-list"
>
<button
<v-btn variant="text" :ripple="false"
v-for="report in feedbackStore.filteredReports"
:key="report.id"
class="report-row"
@@ -160,7 +160,7 @@
<span>{{ t('feedback.review.lastActivity') }}</span>
<strong>{{ formatDate(report.lastActivityAt) }}</strong>
</span>
</button>
</v-btn>
<div
v-if="!feedbackStore.filteredReports.length"
@@ -184,17 +184,17 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.page-header h1 {
@apply mt-2 text-3xl font-black md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.page-header p {
@apply mt-2 max-w-3xl text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.metric-grid {
@@ -206,7 +206,7 @@
.report-row,
.page-message {
@apply rounded-lg border;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.9);
}
@@ -221,7 +221,7 @@
.metric strong {
@apply mt-2 block text-3xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.filter-panel {
@@ -230,13 +230,13 @@
.icon-button {
@apply inline-flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-lg border transition-colors;
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);
}
.icon-button:hover {
background: #172033;
background: var(--app-color-on-surface);
color: white;
}
@@ -256,7 +256,7 @@
.unread-dot {
@apply h-2.5 w-2.5 rounded-full;
background: #0f766e;
background: var(--app-color-on-tertiary);
}
.report-main,
@@ -271,18 +271,18 @@
.report-title strong,
.report-activity strong {
@apply text-sm font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.report-title em {
@apply rounded-md px-2 py-1 text-xs font-bold not-italic;
background: rgba(15, 118, 110, 0.08);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.report-description {
@apply line-clamp-2 text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.report-tags {
@@ -291,7 +291,7 @@
.report-tags span {
@apply inline-flex items-center gap-1 rounded-md px-2 py-1 text-xs font-semibold;
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
color: #44516a;
}
@@ -302,11 +302,11 @@
.page-message {
@apply p-4 text-sm font-semibold;
color: #526178;
color: var(--app-text-muted);
}
.page-message-error {
border-color: rgba(220, 38, 38, 0.24);
color: #b91c1c;
color: var(--app-danger-muted);
}
</style>

View File

@@ -245,7 +245,7 @@
.hero,
.panel {
@apply rounded-lg border;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.92);
}
@@ -255,18 +255,18 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.hero h1 {
@apply mt-2 text-3xl font-black md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.hero p,
.panel-header span {
@apply mt-2 text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.onboarding-grid {
@@ -283,12 +283,12 @@
.panel-header .v-icon {
@apply mt-1;
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.panel-header strong {
@apply block text-xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.form-stack {
@@ -297,13 +297,13 @@
.page-message {
@apply rounded-lg border p-3 text-sm font-semibold;
border-color: rgba(23, 32, 51, 0.08);
background: rgba(23, 32, 51, 0.04);
color: #526178;
border-color: var(--app-border-subtle);
background: var(--app-control-subtle);
color: var(--app-text-muted);
}
.page-message.error {
border-color: rgba(220, 38, 38, 0.24);
color: #b91c1c;
color: var(--app-danger-muted);
}
</style>

View File

@@ -253,7 +253,7 @@
<div class="eyebrow">{{ t('organizationSettings.eyebrow') }}</div>
<p>{{ t('organizationSettings.description') }}</p>
<div class="organization-title-line">
<button
<v-btn variant="text" :ripple="false"
v-if="organization"
class="organization-logo-button"
type="button"
@@ -267,7 +267,7 @@
:src="organization.logoUrl"
size="lg"
/>
</button>
</v-btn>
<v-form
v-if="organization && isEditingName"
class="title-edit-form"
@@ -282,7 +282,7 @@
maxlength="256"
variant="outlined"
/>
<button
<v-btn variant="text" :ripple="false"
class="icon-action"
type="submit"
:disabled="organizationStore.isSaving"
@@ -290,8 +290,8 @@
:title="t('organizationSettings.saveName')"
>
<v-icon :icon="mdiCheck" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="icon-action secondary"
type="button"
:disabled="organizationStore.isSaving"
@@ -300,14 +300,14 @@
@click="cancelEditingName"
>
<v-icon :icon="mdiClose" />
</button>
</v-btn>
</v-form>
<div
v-else
class="title-row"
>
<h1>{{ organization?.name ?? t('organizationSettings.title') }}</h1>
<button
<v-btn variant="text" :ripple="false"
v-if="organization && canManageSettings"
class="icon-action secondary"
type="button"
@@ -316,7 +316,7 @@
@click="startEditingName"
>
<v-icon :icon="mdiPencilOutline" />
</button>
</v-btn>
</div>
</div>
<div class="hero-status">
@@ -358,7 +358,7 @@
class="settings-tabs"
aria-label="Organization settings sections"
>
<button
<v-btn variant="text" :ripple="false"
v-for="section in visibleSections"
:key="section.key"
class="settings-tab"
@@ -368,7 +368,7 @@
>
<v-icon :icon="section.icon" />
<span>{{ t(`organizationSettings.sections.${section.key}.title`) }}</span>
</button>
</v-btn>
</nav>
<div
@@ -419,13 +419,13 @@
hide-details
/>
<div class="form-actions">
<button
<v-btn variant="text" :ripple="false"
class="primary-action"
type="submit"
:disabled="organizationStore.isAddingMember"
>
{{ organizationStore.isAddingMember ? t('organizationSettings.addingMember') : t('organizationSettings.addMember') }}
</button>
</v-btn>
</div>
</v-form>
<div
@@ -561,7 +561,7 @@
.settings-hero h1,
.title-edit-form input {
@apply min-w-0 text-3xl font-black md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.settings-hero p,
@@ -570,7 +570,7 @@
.placeholder-panel span,
.empty-state {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.organization-title-line {
@@ -579,11 +579,11 @@
.organization-logo-button {
@apply inline-flex size-14 flex-shrink-0 items-center justify-center rounded-[0.75rem] border bg-white transition-colors md:size-16;
border-color: rgba(23, 32, 51, 0.12);
border-color: var(--app-border-subtle);
}
.organization-logo-button:hover:not(:disabled) {
border-color: #0f766e;
border-color: var(--app-color-on-tertiary);
box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
}
@@ -601,24 +601,24 @@
}
.title-edit-form input:focus {
border-color: #0f766e;
border-color: var(--app-color-on-tertiary);
box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
}
.icon-action {
@apply inline-flex size-9 flex-shrink-0 items-center justify-center rounded-[0.5rem] transition-colors;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.icon-action.secondary {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.icon-action:hover:not(:disabled) {
background: #0f766e;
color: #fffaf2;
background: var(--app-color-on-tertiary);
color: var(--app-color-on-primary);
}
.icon-action:disabled {
@@ -635,22 +635,22 @@
.settings-tabs {
@apply flex flex-wrap gap-2 border-b pb-3;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.settings-tab {
@apply inline-flex h-10 items-center gap-2 rounded-[0.75rem] px-3 text-sm font-semibold transition-colors;
color: #526178;
color: var(--app-text-muted);
}
.settings-tab:hover {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.settings-tab-active {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.settings-tab :deep(.v-icon) {
@@ -667,13 +667,13 @@
.section-heading h2 {
@apply text-2xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.content-card {
@apply flex flex-col gap-4 rounded-[0.75rem] border p-5;
background: rgba(255, 255, 255, 0.94);
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-surface-glass);
border-color: var(--app-border-subtle);
}
.table-list {
@@ -682,7 +682,7 @@
.table-row {
@apply flex items-center justify-between gap-4 rounded-[0.75rem] px-4 py-3;
background: rgba(23, 32, 51, 0.04);
background: var(--app-control-subtle);
}
.table-row {
@@ -694,7 +694,7 @@
}
.table-row-button:hover {
background: rgba(23, 32, 51, 0.08);
background: var(--app-border-subtle);
}
.table-row div {
@@ -704,7 +704,7 @@
.table-row strong,
.placeholder-panel strong {
@apply font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.table-row small {
@@ -715,18 +715,18 @@
.placeholder-panel,
.empty-state {
@apply rounded-[0.75rem] px-4 py-4;
background: rgba(23, 32, 51, 0.04);
background: var(--app-control-subtle);
}
.settings-form {
@apply flex flex-col gap-4 rounded-[0.75rem] p-4;
background: rgba(23, 32, 51, 0.04);
background: var(--app-control-subtle);
}
.usage-plan span,
.usage-row-heading span {
@apply text-sm;
color: #526178;
color: var(--app-text-muted);
}
.field-error {
@@ -734,7 +734,7 @@
}
.field-success {
color: #0f766e !important;
color: var(--app-color-on-tertiary) !important;
}
.invite-form {
@@ -743,7 +743,7 @@
.settings-form label {
@apply flex min-w-0 flex-col gap-2 text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.settings-form input,
@@ -751,12 +751,12 @@
@apply h-11 w-full rounded-[0.5rem] border px-3 text-sm outline-none transition-colors;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.14);
color: #172033;
color: var(--app-color-on-surface);
}
.settings-form input:focus,
.settings-form select:focus {
border-color: #0f766e;
border-color: var(--app-color-on-tertiary);
box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
}
@@ -766,12 +766,12 @@
.primary-action {
@apply inline-flex h-11 items-center justify-center rounded-[0.5rem] px-4 text-sm font-bold transition-colors;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.primary-action:hover:not(:disabled) {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
.primary-action:disabled {
@@ -789,7 +789,7 @@
.settings-alert.success {
background: rgba(15, 118, 110, 0.12);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.placeholder-panel {
@@ -802,13 +802,13 @@
.tier-form {
@apply grid gap-3 rounded-[0.75rem] p-4 md:grid-cols-[minmax(0,1fr)_auto] md:items-end;
background: rgba(23, 32, 51, 0.04);
background: var(--app-control-subtle);
}
.usage-plan,
.usage-row {
@apply rounded-[0.75rem] p-4;
background: rgba(23, 32, 51, 0.04);
background: var(--app-control-subtle);
}
.usage-plan {
@@ -825,12 +825,12 @@
.usage-meter {
@apply h-2 overflow-hidden rounded-full;
background: rgba(23, 32, 51, 0.1);
background: var(--app-control-active);
}
.usage-meter span {
@apply block h-full rounded-full;
background: #0f766e;
background: var(--app-color-on-tertiary);
}
</style>

View File

@@ -315,27 +315,26 @@
</header>
<section class="release-shell">
<nav
<v-tabs
:model-value="activeTab"
class="release-tabs"
aria-label="Release communications sections"
density="compact"
@update:model-value="setTab"
>
<button
<v-tab
class="release-tab"
:class="{ 'release-tab-active': activeTab === 'git-log' }"
type="button"
@click="setTab('git-log')"
value="git-log"
>
{{ t('releaseCommunications.commits.gitLogTab') }}
</button>
<button
</v-tab>
<v-tab
class="release-tab"
:class="{ 'release-tab-active': activeTab === 'release-notes' }"
type="button"
@click="setTab('release-notes')"
value="release-notes"
>
{{ t('releaseCommunications.commits.releaseNotesTab') }}
</button>
</nav>
</v-tab>
</v-tabs>
<section class="release-content">
<template v-if="activeTab === 'git-log'">
@@ -570,17 +569,17 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.page-header h1 {
@apply mt-2 text-3xl font-black md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.page-header p {
@apply mt-2 max-w-3xl text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.release-shell {
@@ -596,36 +595,14 @@
}
.release-tabs {
display: flex;
flex-wrap: wrap;
gap: 8px;
border-bottom: 1px solid rgba(23, 32, 51, 0.1);
padding-bottom: 12px;
border-bottom: 1px solid var(--app-control-active);
}
.release-tab {
display: inline-flex;
height: 40px;
align-items: center;
gap: 8px;
border: 0;
border-radius: 0.75rem;
background: transparent;
padding: 0 12px;
color: #526178;
min-width: 0;
color: var(--app-text-muted);
font-size: 0.875rem;
font-weight: 600;
transition: background 0.15s ease, color 0.15s ease;
}
.release-tab:hover {
background: rgba(23, 32, 51, 0.06);
color: #172033;
}
.release-tab-active {
background: #172033;
color: #fffaf2;
}
.updates-panel,
@@ -665,7 +642,7 @@
.localized-fields h3,
.selected-commits-list h3 {
margin: 0;
color: #172033;
color: var(--app-color-on-surface);
font-size: 1rem;
font-weight: 800;
}
@@ -711,33 +688,6 @@
gap: 8px;
}
.release-note-field :deep(.v-field__input) {
min-height: 40px;
align-items: center;
padding-top: 0;
padding-bottom: 0;
}
.release-note-field :deep(input) {
height: 40px;
line-height: 40px;
}
.release-note-field :deep(input::placeholder),
.release-note-textarea :deep(textarea::placeholder) {
line-height: inherit;
}
.release-note-textarea :deep(.v-field__input) {
align-items: flex-start;
padding-top: 10px;
padding-bottom: 10px;
}
.release-note-textarea :deep(textarea) {
line-height: 1.45;
}
.update-row {
display: grid;
width: 100%;
@@ -746,15 +696,22 @@
border-bottom: 1px solid #e2e8f0;
background: transparent;
padding: 10px 0;
color: inherit;
cursor: pointer;
font: inherit;
text-align: left;
}
.update-row:hover {
background: var(--app-control-hover);
}
.update-row:last-child {
border-bottom: 0;
}
.update-row strong {
color: #172033;
color: var(--app-color-on-surface);
font-size: 1rem;
font-weight: 800;
line-height: 1.3;
@@ -853,7 +810,7 @@
.commit-subject {
display: grid;
gap: 4px;
color: #172033;
color: var(--app-color-on-surface);
font-size: 0.92rem;
line-height: 1.35;
}
@@ -891,7 +848,7 @@
.dialog-header h2 {
margin: 0;
color: #172033;
color: var(--app-color-on-surface);
font-size: 1.35rem;
font-weight: 900;
}

View File

@@ -114,17 +114,17 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.22em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.page-header h1 {
@apply mt-2 text-3xl font-black md:text-4xl;
color: #172033;
color: var(--app-color-on-surface);
}
.page-header p {
@apply mt-2 max-w-3xl text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.updates-list {
@@ -155,7 +155,7 @@
margin: 0;
font-size: 1.1rem;
font-weight: 800;
color: #172033;
color: var(--app-color-on-surface);
}
.release-description {

View File

@@ -50,17 +50,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-3 max-w-2xl text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.queue-list {
@@ -70,26 +70,26 @@
.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);
}
.queue-row {
@apply flex flex-col justify-between gap-4 rounded-[1.5rem] border p-5 lg:flex-row lg:items-center;
background: rgba(255, 255, 255, 0.84);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.queue-row strong {
@apply block text-xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.queue-row span,
.queue-meta span,
.queue-meta small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.queue-meta {

View File

@@ -48,12 +48,12 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.24em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.page-header h1 {
@apply mt-2 text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.page-header p,
@@ -61,13 +61,13 @@
.placeholder-block span,
.placeholder-block small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.panel {
@apply flex flex-col gap-5 rounded-[1.75rem] border p-5;
background: rgba(255, 255, 255, 0.9);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.panel-heading {
@@ -76,7 +76,7 @@
.panel-heading strong,
.placeholder-block strong {
color: #172033;
color: var(--app-color-on-surface);
}
.panel-heading strong {
@@ -85,8 +85,8 @@
.placeholder-block {
@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);
}
.placeholder-block strong {

View File

@@ -56,7 +56,7 @@
.settings-nav {
@apply flex h-fit flex-col gap-2 rounded-[1.75rem] border p-4;
background: rgba(255, 255, 255, 0.9);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.settings-nav-header {
@@ -65,27 +65,27 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.24em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.settings-nav-header h1 {
@apply mt-2 text-2xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.settings-link {
@apply rounded-[1rem] px-4 py-3 text-sm font-semibold no-underline transition;
color: #526178;
color: var(--app-text-muted);
}
.settings-link:hover {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.settings-link.router-link-active {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.settings-content {

View File

@@ -188,13 +188,13 @@
</div>
</div>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="button"
@click="isPortraitDialogOpen = true"
>
{{ t('userSettings.updatePortrait') }}
</button>
</v-btn>
</div>
<div class="panel">
@@ -271,13 +271,13 @@
</div>
<div class="form-actions">
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="submit"
:disabled="!canSave"
>
{{ userProfileStore.isUpdating ? t('common.saving') : t('userSettings.saveDetails') }}
</button>
</v-btn>
</div>
</v-form>
</div>
@@ -318,7 +318,7 @@
</div>
<div class="calendar-feed-actions">
<button
<v-btn variant="text" :ripple="false"
v-if="!userProfileStore.calendarExportFeed?.isEnabled"
class="primary-button"
type="button"
@@ -326,33 +326,33 @@
@click="enableCalendarFeed"
>
{{ t('userSettings.calendarFeed.enable') }}
</button>
</v-btn>
<template v-else>
<button
<v-btn variant="text" :ripple="false"
class="secondary-button"
type="button"
:disabled="!calendarFeedUrl"
@click="copyCalendarFeedUrl"
>
{{ t('userSettings.calendarFeed.copy') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="secondary-button"
type="button"
:disabled="userProfileStore.isUpdatingCalendarFeed"
@click="regenerateCalendarFeed"
>
{{ t('userSettings.calendarFeed.regenerate') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="danger-button"
type="button"
:disabled="userProfileStore.isUpdatingCalendarFeed"
@click="revokeCalendarFeed"
>
{{ t('userSettings.calendarFeed.revoke') }}
</button>
</v-btn>
</template>
</div>
</div>
@@ -377,12 +377,12 @@
.eyebrow {
@apply text-xs font-bold uppercase tracking-[0.24em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.page-header h1 {
@apply mt-2 text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.page-header p,
@@ -390,13 +390,13 @@
.hero-identity span,
.hero-identity small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.panel {
@apply flex flex-col gap-5 rounded-[1.75rem] border p-5;
background: rgba(255, 255, 255, 0.9);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.hero-panel {
@@ -409,7 +409,7 @@
.hero-identity strong,
.panel-heading strong {
color: #172033;
color: var(--app-color-on-surface);
}
.hero-identity strong {
@@ -438,14 +438,14 @@
.field span {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.field input {
@apply rounded-[1rem] border px-4 py-3 text-sm;
background: #fffaf2;
border-color: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-color-on-primary);
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.field input:disabled {
@@ -460,19 +460,19 @@
@apply rounded-[1rem] border px-4 py-3 text-sm font-semibold;
background: rgba(15, 118, 110, 0.08);
border-color: rgba(15, 118, 110, 0.18);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.page-message.error {
background: rgba(185, 28, 28, 0.08);
border-color: rgba(185, 28, 28, 0.16);
color: #b91c1c;
color: var(--app-danger-muted);
}
.primary-button {
@apply inline-flex items-center justify-center gap-2 rounded-full px-5 py-3 text-sm font-bold transition;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.secondary-button,
@@ -481,13 +481,13 @@
}
.secondary-button {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.danger-button {
background: rgba(185, 28, 28, 0.08);
color: #b91c1c;
color: var(--app-danger-muted);
}
.primary-button:disabled,
@@ -499,20 +499,20 @@
.calendar-feed-box {
@apply flex flex-col gap-2 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);
}
.calendar-feed-box span,
.calendar-feed-empty {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.calendar-feed-box code {
@apply overflow-x-auto rounded-[0.75rem] px-3 py-2 text-sm;
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.calendar-feed-actions {

View File

@@ -148,7 +148,7 @@
<span>{{ labels.description }}</span>
</div>
<button
<v-btn variant="text" :ripple="false"
type="button"
class="secondary-button"
:disabled="disabled"
@@ -156,7 +156,7 @@
>
<v-icon :icon="mdiPlus" />
<span>{{ labels.addStep }}</span>
</button>
</v-btn>
</div>
<div
@@ -182,30 +182,30 @@
</div>
<div class="approval-step-actions">
<button
<v-btn variant="text" :ripple="false"
type="button"
:aria-label="labels.moveUp"
:disabled="disabled || index === 0"
@click="moveStep(index, -1)"
>
<v-icon :icon="mdiArrowUp" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
type="button"
:aria-label="labels.moveDown"
:disabled="disabled || index === modelValue.length - 1"
@click="moveStep(index, 1)"
>
<v-icon :icon="mdiArrowDown" />
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
type="button"
:aria-label="labels.removeStep"
:disabled="disabled"
@click="removeStep(index)"
>
<v-icon :icon="mdiDeleteOutline" />
</button>
</v-btn>
</div>
</div>
@@ -321,8 +321,8 @@
.approval-editor-header {
@apply flex flex-col gap-3 rounded-[1rem] border px-4 py-4 sm:flex-row sm:items-center sm:justify-between;
background: #fffaf2;
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-color-on-primary);
border-color: var(--app-border-subtle);
}
.approval-editor-header div,
@@ -332,14 +332,14 @@
.approval-editor-header strong,
.approval-step-heading strong {
color: #172033;
color: var(--app-color-on-surface);
}
.approval-editor-header span,
.approval-empty,
.approval-step-heading small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.approval-step-list {
@@ -349,8 +349,8 @@
.approval-empty,
.approval-step-card {
@apply rounded-[1rem] border px-4 py-4;
background: #fffaf2;
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-color-on-primary);
border-color: var(--app-border-subtle);
}
.approval-step-card {
@@ -367,8 +367,8 @@
.approval-step-actions button {
@apply inline-flex h-9 w-9 items-center justify-center rounded-full;
background: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.approval-step-actions button:disabled {
@@ -382,8 +382,8 @@
.secondary-button {
@apply inline-flex items-center justify-center gap-2 rounded-full px-4 py-2 text-sm font-semibold;
background: rgba(23, 32, 51, 0.08);
color: #172033;
background: var(--app-border-subtle);
color: var(--app-color-on-surface);
}
.secondary-button:disabled {
@@ -397,25 +397,25 @@
.field span {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.field input,
.field select {
@apply rounded-[1rem] border px-4 py-3 text-sm;
background: #fffdf8;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
background: var(--app-color-surface);
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
outline: none;
}
.field-error {
@apply text-sm leading-6;
color: #b91c1c;
color: var(--app-danger-muted);
}
.field-help {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
</style>

View File

@@ -274,51 +274,51 @@
>
<div class="calendar-toolbar">
<div class="calendar-nav">
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
@click="shiftPeriod(-1)"
>
<v-icon :icon="mdiChevronLeft" />
</button>
</v-btn>
<div class="calendar-period">{{ periodLabel }}</div>
<button
<v-btn variant="text" :ripple="false"
class="icon-button"
type="button"
@click="shiftPeriod(1)"
>
<v-icon :icon="mdiChevronRight" />
</button>
</v-btn>
</div>
<div class="calendar-controls">
<button
<v-btn variant="text" :ripple="false"
class="text-button"
type="button"
@click="jumpToToday"
>
{{ t('today') }}
</button>
</v-btn>
<div class="view-toggle">
<button
<v-btn variant="text" :ripple="false"
class="toggle-button"
:class="{ 'toggle-button-active': viewMode === 'month' }"
type="button"
@click="setView('month')"
>
{{ t('dashboard.month') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="toggle-button"
:class="{ 'toggle-button-active': viewMode === 'week' }"
type="button"
@click="setView('week')"
>
{{ t('dashboard.week') }}
</button>
</v-btn>
</div>
</div>
</div>
@@ -396,19 +396,19 @@
.page-message {
@apply rounded-[1.25rem] border p-4 text-sm font-medium;
background: rgba(255, 255, 255, 0.88);
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);
}
.calendar-card {
@apply rounded-[1.75rem] border p-4 md:p-5;
background: rgba(255, 255, 255, 0.94);
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
background: var(--app-surface-glass);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.calendar-toolbar {
@@ -426,7 +426,7 @@
.calendar-period {
@apply min-w-0 px-2 text-base font-bold md:text-lg;
color: #172033;
color: var(--app-color-on-surface);
}
.icon-button,
@@ -434,8 +434,8 @@
.toggle-button {
@apply inline-flex items-center justify-center rounded-full border px-3 py-2 text-sm font-semibold transition;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
}
.icon-button {
@@ -451,7 +451,7 @@
.view-toggle {
@apply inline-flex rounded-full border p-1;
background: #f8fafc;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.toggle-button {
@@ -459,7 +459,7 @@
}
.toggle-button-active {
background: #172033;
background: var(--app-color-on-surface);
color: #ffffff;
}
@@ -474,13 +474,13 @@
.weekday-label {
@apply px-2 text-xs font-bold uppercase tracking-[0.16em];
color: #526178;
color: var(--app-text-muted);
}
.calendar-day {
@apply min-h-[8.5rem] rounded-[1.25rem] border p-3;
background: linear-gradient(180deg, rgba(255, 253, 248, 0.8) 0%, rgba(255, 255, 255, 0.96) 100%);
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.calendar-day-week {
@@ -498,7 +498,7 @@
.day-number {
@apply mb-3 text-sm font-bold;
color: #172033;
color: var(--app-color-on-surface);
}
.day-entries {
@@ -515,23 +515,23 @@
.calendar-entry strong {
@apply text-sm font-bold;
color: #172033;
color: var(--app-color-on-surface);
}
.calendar-entry span {
@apply text-xs leading-5;
color: #526178;
color: var(--app-text-muted);
}
.entry-time {
@apply text-[0.7rem] font-bold uppercase tracking-[0.12em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.entry-more,
.day-empty {
@apply px-1 text-xs font-semibold;
color: #526178;
color: var(--app-text-muted);
}
.calendar-entry.production {

View File

@@ -224,7 +224,7 @@
<div class="panel-kicker">{{ t('overview.workspacesKicker') }}</div>
<div class="panel-title">{{ t('overview.workspaceRollup') }}</div>
<div class="workspace-stack">
<button
<v-btn variant="text" :ripple="false"
v-for="workspace in workspaceStats"
:key="workspace.id"
class="workspace-row"
@@ -240,7 +240,7 @@
<small>{{ workspace.upcomingCount }} {{ t('overview.labels.upcoming') }}</small>
<small>{{ workspace.blockingCount }} {{ t('overview.labels.blocked') }}</small>
</div>
</button>
</v-btn>
</div>
</article>
@@ -324,7 +324,7 @@
.page-header h1 {
@apply mt-2 text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.page-header p,
@@ -333,13 +333,13 @@
.workspace-row span,
.empty-state {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.eyebrow,
.panel-kicker {
@apply text-xs font-bold uppercase tracking-[0.24em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.stats-grid {
@@ -354,8 +354,8 @@
.panel {
@apply rounded-[1.75rem] border p-5;
background: rgba(255, 255, 255, 0.92);
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.panel {
@@ -365,7 +365,7 @@
.panel-title,
.workspace-row strong,
.list-row strong {
color: #172033;
color: var(--app-color-on-surface);
}
.panel-title {
@@ -374,7 +374,7 @@
.stat-card strong {
@apply mt-3 block text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.workspace-stack {
@@ -384,8 +384,8 @@
.workspace-row,
.list-row {
@apply flex items-start justify-between gap-4 rounded-[1.1rem] border p-4 text-left no-underline;
background: #fffaf2;
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-color-on-primary);
border-color: var(--app-border-subtle);
}
.workspace-row.alert,
@@ -401,17 +401,17 @@
.workspace-meta small,
.list-row em {
@apply text-sm font-semibold not-italic;
color: #172033;
color: var(--app-color-on-surface);
}
.page-message,
.empty-state {
@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);
border-color: var(--app-border-subtle);
}
.page-message.error {
color: #b91c1c;
color: var(--app-danger-muted);
}
</style>

View File

@@ -113,21 +113,21 @@
/>
<div class="panel-actions field-wide">
<button
<v-btn variant="text" :ripple="false"
class="secondary"
type="button"
:disabled="workspaceStore.isCreating"
@click="cancel"
>
{{ t('common.cancel') }}
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
class="primary"
type="submit"
:disabled="workspaceStore.isCreating"
>
{{ workspaceStore.isCreating ? t('common.creating') : t('workspaceCreate.createAction') }}
</button>
</v-btn>
</div>
</v-form>
</article>
@@ -143,7 +143,7 @@
.hero-copy,
.create-card {
@apply rounded-[1.75rem] border;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
background: rgba(255, 255, 255, 0.92);
}
@@ -151,7 +151,7 @@
@apply p-6 md:p-8;
background:
radial-gradient(circle at top left, rgba(255, 138, 61, 0.16), transparent 38%),
linear-gradient(135deg, rgba(255, 255, 255, 0.98), rgba(255, 247, 237, 0.92));
linear-gradient(135deg, var(--app-surface-raised), rgba(255, 247, 237, 0.92));
}
.eyebrow {
@@ -161,14 +161,14 @@
.hero-copy h1 {
@apply mt-3 text-4xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.hero-copy p,
.card-header span,
.field small {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.create-card {
@@ -176,7 +176,7 @@
}
.card-header strong {
color: #172033;
color: var(--app-color-on-surface);
}
.card-header {
@@ -201,15 +201,15 @@
.field span {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.field input,
.field select {
@apply rounded-[1rem] border px-4 py-3 text-sm;
background: #fffdf8;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
background: var(--app-color-surface);
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
outline: none;
}
@@ -223,12 +223,12 @@
}
.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);
}
</style>

View File

@@ -417,7 +417,7 @@
class="tab-strip"
aria-label="Workspace settings sections"
>
<button
<v-btn variant="text" :ripple="false"
v-for="tab in settingsTabs"
:key="tab.key"
type="button"
@@ -427,7 +427,7 @@
>
<v-icon :icon="tab.icon" />
<span>{{ tab.label }}</span>
</button>
</v-btn>
</nav>
<div class="tab-content">
@@ -486,14 +486,14 @@
{{ logoStatus }}
</small>
</div>
<button
<v-btn variant="text" :ripple="false"
class="secondary-button"
type="button"
:disabled="workspaceStore.isUploadingLogo"
@click="isLogoDialogOpen = true"
>
{{ workspaceStore.isUploadingLogo ? t('common.saving') : t('workspaceSettings.logo.changeAction') }}
</button>
</v-btn>
</div>
<v-text-field
@@ -512,13 +512,13 @@
/>
</label>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="submit"
:disabled="workspaceStore.isUpdating || !isSettingsDirty"
>
{{ workspaceStore.isUpdating ? t('common.saving') : t('workspaceSettings.general.saveAction') }}
</button>
</v-btn>
</v-form>
</article>
@@ -558,12 +558,12 @@
hide-details
/>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="submit"
>
{{ workspaceStore.isInviting ? t('common.creating') : t('workspaceSettings.sendInvite') }}
</button>
</v-btn>
</v-form>
</article>
@@ -733,14 +733,14 @@
</span>
</div>
<button
<v-btn variant="text" :ripple="false"
class="primary-button"
type="button"
:disabled="workspaceStore.isUpdating || !isSettingsDirty"
@click="submitWorkspaceSettings"
>
{{ workspaceStore.isUpdating ? t('common.saving') : t('workspaceSettings.approvals.saveAction') }}
</button>
</v-btn>
</div>
</article>
@@ -857,8 +857,8 @@
.settings-card {
@apply flex flex-col gap-5 rounded-[0.75rem] border p-5;
background: rgba(255, 255, 255, 0.94);
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-surface-glass);
border-color: var(--app-border-subtle);
}
.section-copy {
@@ -867,22 +867,22 @@
.tab-strip {
@apply flex flex-wrap gap-2 border-b pb-3;
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.tab-button {
@apply inline-flex h-10 items-center gap-2 rounded-[0.75rem] px-3 text-sm font-semibold transition-colors;
color: #526178;
color: var(--app-text-muted);
}
.tab-button:hover {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.tab-button-active {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.tab-button :deep(.v-icon) {
@@ -895,7 +895,7 @@
.tab-heading h2 {
@apply text-2xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.section-kicker {
@@ -910,7 +910,7 @@
.connector-status,
.workflow-rule strong,
.workflow-step-copy strong {
color: #172033;
color: var(--app-color-on-surface);
}
.section-copy h1 {
@@ -927,13 +927,13 @@
.workflow-rule span,
.workflow-step-copy span {
@apply text-sm leading-6;
color: #526178;
color: var(--app-text-muted);
}
.logo-picker-card {
@apply flex flex-col gap-4 rounded-[0.75rem] border p-4 sm:flex-row sm:items-center;
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-control-subtle);
border-color: var(--app-border-subtle);
}
.logo-picker-copy {
@@ -941,7 +941,7 @@
}
.logo-picker-copy strong {
color: #172033;
color: var(--app-color-on-surface);
}
.logo-picker-copy small,
@@ -951,11 +951,11 @@
}
.field-error {
color: #b91c1c;
color: var(--app-danger-muted);
}
.field-success {
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.form-stack {
@@ -968,43 +968,43 @@
.field span {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.field input,
.field select {
@apply h-11 rounded-[0.5rem] border px-3 text-sm outline-none transition-colors;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.1);
color: #172033;
border-color: var(--app-control-active);
color: var(--app-color-on-surface);
}
.field input:focus,
.field select:focus {
border-color: #0f766e;
border-color: var(--app-color-on-tertiary);
box-shadow: 0 0 0 3px rgba(15, 118, 110, 0.12);
}
.primary-button {
@apply inline-flex h-11 items-center justify-center rounded-[0.5rem] px-4 text-sm font-bold transition-colors;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.secondary-button {
@apply inline-flex h-11 items-center justify-center rounded-[0.5rem] border px-4 text-sm font-bold transition-colors;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.14);
color: #172033;
color: var(--app-color-on-surface);
}
.primary-button:hover:not(:disabled) {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
.secondary-button:hover:not(:disabled) {
border-color: #0f766e;
color: #0f766e;
border-color: var(--app-color-on-tertiary);
color: var(--app-color-on-tertiary);
}
.primary-button:disabled,
@@ -1027,8 +1027,8 @@
.workflow-toggle,
.workflow-step {
@apply rounded-[0.75rem] border px-4 py-4;
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-control-subtle);
border-color: var(--app-border-subtle);
}
.invite-row {
@@ -1064,7 +1064,7 @@
.workflow-step-icon {
@apply inline-flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-[0.75rem];
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.connector-status {
@@ -1074,11 +1074,11 @@
.connector-link {
@apply inline-flex h-11 w-fit items-center gap-3 rounded-[0.5rem] px-4 text-sm font-bold no-underline transition;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.connector-link:hover {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
</style>

View File

@@ -216,21 +216,25 @@
<div class="side-menu-items side-menu-right">
<template v-if="!authStore.isAuthenticated">
<router-link to="/login">
<button class="menu-item-action">
<v-btn
to="/login"
class="menu-item-action"
variant="text"
:ripple="false"
>
<v-icon :icon="mdiLogin" />
<span class="label">{{ t('nav.signIn') }}</span>
</button>
</router-link>
</v-btn>
</template>
<div
v-if="contentViewActions.length"
class="view-selector"
>
<button
<v-btn
class="menu-item-action view-selector-button"
type="button"
variant="text"
:ripple="false"
@click="isContentViewMenuOpen = !isContentViewMenuOpen"
>
<v-icon :icon="activeContentViewAction.icon" />
@@ -239,28 +243,25 @@
class="selector-chevron"
:icon="mdiChevronDown"
/>
</button>
</v-btn>
<div
v-if="isContentViewMenuOpen"
class="view-selector-menu"
>
<router-link
<v-btn
v-for="action in contentViewActions"
:key="action.key"
:to="action.route"
class="menu-action-link"
@click="isContentViewMenuOpen = false"
>
<button
class="view-selector-option"
class="view-selector-option menu-action-link"
:class="{ 'view-selector-option-active': action.active }"
type="button"
variant="text"
:ripple="false"
@click="isContentViewMenuOpen = false"
>
<v-icon :icon="action.icon" />
<span>{{ action.label }}</span>
</button>
</router-link>
</v-btn>
</div>
</div>
@@ -268,19 +269,21 @@
v-for="action in appBarActions"
:key="action.key"
>
<button
<v-btn
v-if="action.disabled"
class="menu-item-action"
type="button"
variant="text"
:ripple="false"
disabled
>
<v-icon :icon="action.icon" />
<span class="label">{{ action.label }}</span>
</button>
<button
</v-btn>
<v-btn
v-else-if="action.handler"
class="menu-item-action"
type="button"
variant="text"
:ripple="false"
:disabled="action.loading"
@click="action.handler"
>
@@ -295,17 +298,17 @@
:icon="action.icon"
/>
<span class="label">{{ action.label }}</span>
</button>
<router-link
</v-btn>
<v-btn
v-else
:to="action.route"
class="menu-action-link"
class="menu-item-action menu-action-link"
variant="text"
:ripple="false"
>
<button class="menu-item-action">
<v-icon :icon="action.icon" />
<span class="label">{{ action.label }}</span>
</button>
</router-link>
</v-btn>
</template>
</div>
</div>
@@ -318,7 +321,7 @@
@apply sticky top-0 z-20 flex flex-col gap-4 px-5 py-4 md:flex-row md:items-center md:justify-between;
background: rgba(255, 250, 242, 0.82);
backdrop-filter: blur(18px);
border-bottom: 1px solid rgba(23, 32, 51, 0.08);
border-bottom: 1px solid var(--app-border-subtle);
isolation: isolate;
}
@@ -353,8 +356,8 @@
.view-selector-menu {
@apply absolute right-0 top-[calc(100%+0.5rem)] z-30 flex min-w-52 flex-col gap-1 rounded-[1rem] border p-2 shadow-xl;
background: #ffffff;
border-color: rgba(23, 32, 51, 0.1);
background: var(--app-surface-raised);
border-color: var(--app-border-subtle);
}
.label {
@@ -362,15 +365,16 @@
}
.menu-item-action {
@apply flex h-11 items-center gap-3 rounded-full px-4 transition-colors;
@apply flex h-11 items-center justify-start gap-3 rounded-full px-4 normal-case transition-colors;
background: rgba(255, 255, 255, 0.8);
color: #172033;
border: 1px solid rgba(23, 32, 51, 0.06);
color: var(--app-color-on-surface);
border: 1px solid var(--app-border-muted);
letter-spacing: 0;
}
.menu-item-action:hover {
background: #172033;
color: #fffaf2;
background: var(--app-color-primary);
color: var(--app-color-on-primary);
}
.menu-item-action:disabled {
@@ -380,21 +384,27 @@
.menu-item-action:disabled:hover {
background: rgba(255, 255, 255, 0.8);
color: #172033;
color: var(--app-color-on-surface);
}
.view-selector-option {
@apply flex min-h-11 w-full items-center gap-3 rounded-[0.75rem] px-3 text-left text-sm font-semibold transition;
color: #172033;
@apply flex h-auto min-h-11 w-full items-center justify-start gap-3 rounded-[0.75rem] px-3 text-left text-sm font-semibold normal-case transition;
color: var(--app-color-on-surface);
letter-spacing: 0;
}
.view-selector-option:hover,
.view-selector-option-active {
background: #172033;
color: #fffaf2;
background: var(--app-color-primary);
color: var(--app-color-on-primary);
}
.menu-item-action i {
.menu-item-action :deep(.v-btn__content),
.view-selector-option :deep(.v-btn__content) {
@apply flex min-w-0 items-center justify-start gap-3;
}
.menu-item-action :deep(.v-icon) {
@apply text-xl;
}

View File

@@ -356,15 +356,17 @@
class="sidebar-search-group"
>
<strong>Campaigns</strong>
<button
<v-btn
v-for="result in campaignResults"
:key="`campaign-${result.id}`"
class="sidebar-search-result"
variant="text"
:ripple="false"
@click="openSearchResult(result)"
>
<span>{{ result.label }}</span>
<small>{{ result.description }}</small>
</button>
</v-btn>
</div>
<div
@@ -372,15 +374,17 @@
class="sidebar-search-group"
>
<strong>Content items</strong>
<button
<v-btn
v-for="result in contentResults"
:key="`content-${result.id}`"
class="sidebar-search-result"
variant="text"
:ripple="false"
@click="openSearchResult(result)"
>
<span>{{ result.label }}</span>
<small>{{ result.description }}</small>
</button>
</v-btn>
</div>
<div
@@ -396,9 +400,10 @@
ref="notificationsRef"
class="sidebar-notifications-wrap"
>
<button
class="sidebar-link sidebar-utility-link"
type="button"
<v-btn
class="sidebar-link sidebar-control sidebar-utility-link"
variant="text"
:ripple="false"
@click.stop="toggleNotifications"
>
<span class="sidebar-link-main">
@@ -418,7 +423,7 @@
{{ t('notifications.title') }}
</span>
</span>
</button>
</v-btn>
<div
v-if="isExpanded && isNotificationsOpen"
@@ -443,17 +448,19 @@
{{ notificationsStore.error }}
</div>
<button
<v-btn
v-for="notification in notificationsStore.recentItems"
:key="notification.id"
class="sidebar-notification-row"
:class="{ 'sidebar-notification-row-unread': !notification.readAt }"
variant="text"
:ripple="false"
@click="openNotification(notification)"
>
<strong>{{ formatNotificationTitle(notification) }}</strong>
<span>{{ notification.message }}</span>
<small>{{ formatNotificationDate(notification.createdAt) }}</small>
</button>
</v-btn>
<div
v-if="!notificationsStore.isLoading && !notificationsStore.recentItems.length"
@@ -466,12 +473,14 @@
</div>
<div class="sidebar-section sidebar-primary-links">
<router-link
<v-btn
v-for="link in visiblePrimaryLinks"
:key="link.to"
:to="link.to"
class="sidebar-link"
active-class="sidebar-link-active"
class="sidebar-link sidebar-control"
active-class="sidebar-link-active sidebar-control-active"
variant="text"
:ripple="false"
:title="!isExpanded ? t(link.labelKey) : null"
>
<span class="sidebar-link-icon-wrap">
@@ -495,15 +504,17 @@
>
{{ t(link.labelKey) }}
</span>
</router-link>
</v-btn>
</div>
<div class="sidebar-section">
<div class="sidebar-section-header">
<router-link
<v-btn
to="/app/content"
class="sidebar-link sidebar-link-section"
active-class="sidebar-link-active"
class="sidebar-link sidebar-control sidebar-link-section"
active-class="sidebar-link-active sidebar-control-active"
variant="text"
:ripple="false"
:title="!isExpanded ? t('nav.content') : null"
>
<span class="sidebar-link-main">
@@ -515,25 +526,29 @@
{{ t('nav.content') }}
</span>
</span>
</router-link>
</v-btn>
<router-link
<v-btn
v-if="isExpanded"
:to="{ name: 'content-item-create' }"
class="sidebar-section-action"
class="sidebar-section-action sidebar-icon-button"
variant="text"
:ripple="false"
:title="t('contentItems.newItem')"
>
<v-icon :icon="mdiPlus" />
</router-link>
</v-btn>
</div>
</div>
<div class="sidebar-section">
<div class="sidebar-section-header">
<router-link
<v-btn
to="/app/campaigns"
class="sidebar-link sidebar-link-section"
active-class="sidebar-link-active"
class="sidebar-link sidebar-control sidebar-link-section"
active-class="sidebar-link-active sidebar-control-active"
variant="text"
:ripple="false"
:title="!isExpanded ? t('nav.campaigns') : null"
@click="toggleSection('campaigns')"
>
@@ -552,16 +567,18 @@
:class="{ 'sidebar-chevron-open': openSections.campaigns }"
/>
</span>
</router-link>
</v-btn>
<router-link
<v-btn
v-if="isExpanded"
to="/app/campaigns?create=true"
class="sidebar-section-action"
class="sidebar-section-action sidebar-icon-button"
variant="text"
:ripple="false"
:title="t('campaigns.createTitle')"
>
<v-icon :icon="mdiPlus" />
</router-link>
</v-btn>
</div>
<div
@@ -597,10 +614,12 @@
<div class="sidebar-section">
<div class="sidebar-section-header">
<router-link
<v-btn
to="/app/channels"
class="sidebar-link sidebar-link-section"
active-class="sidebar-link-active"
class="sidebar-link sidebar-control sidebar-link-section"
active-class="sidebar-link-active sidebar-control-active"
variant="text"
:ripple="false"
:title="!isExpanded ? t('nav.channels') : null"
@click="toggleSection('channels')"
>
@@ -619,16 +638,18 @@
:class="{ 'sidebar-chevron-open': openSections.channels }"
/>
</span>
</router-link>
</v-btn>
<router-link
<v-btn
v-if="isExpanded"
to="/app/channels?create=true"
class="sidebar-section-action"
class="sidebar-section-action sidebar-icon-button"
variant="text"
:ripple="false"
:title="t('channels.createTitle')"
>
<v-icon :icon="mdiPlus" />
</router-link>
</v-btn>
</div>
<div
@@ -668,12 +689,14 @@
v-if="authStore.isAuthenticated && visibleBottomLinks.length"
class="sidebar-section sidebar-bottom-links"
>
<router-link
<v-btn
v-for="link in visibleBottomLinks"
:key="link.to"
:to="link.to"
class="sidebar-link"
active-class="sidebar-link-active"
class="sidebar-link sidebar-control"
active-class="sidebar-link-active sidebar-control-active"
variant="text"
:ripple="false"
:title="!isExpanded ? t(link.labelKey) : null"
>
<span class="sidebar-link-icon-wrap">
@@ -691,7 +714,7 @@
>
{{ t(link.labelKey) }}
</span>
</router-link>
</v-btn>
</div>
<SidebarUserMenu
@@ -705,7 +728,7 @@
@reference "@/assets/main.css";
.app-sidebar {
@apply flex h-full w-[19rem] flex-shrink-0 flex-col px-4 pt-4 transition-[width,padding] duration-200;
border-right: 1px solid rgba(23, 32, 51, 0.08);
border-right: 1px solid var(--app-border-subtle);
}
.app-sidebar-scroll {
@@ -714,7 +737,7 @@
.brand-block {
@apply flex items-center gap-3 pb-4;
border-bottom: 1px solid rgba(23, 32, 51, 0.08);
border-bottom: 1px solid var(--app-border-subtle);
}
.brand-link {
@@ -744,7 +767,7 @@
.brand-name {
@apply min-w-0 text-lg font-black uppercase tracking-[0.18em];
color: rgb(var(--v-theme-primary));
color: var(--app-color-primary);
line-height: 2.75rem;
}
@@ -777,25 +800,25 @@
.sidebar-search {
@apply flex h-11 items-center gap-3 rounded-[1.1rem] border px-4 transition-colors;
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.06);
color: #526178;
background: var(--app-control-subtle);
border-color: var(--app-border-muted);
color: var(--app-text-muted);
}
.sidebar-search-open,
.sidebar-search:focus-within {
background: rgba(255, 255, 255, 0.96);
border-color: rgba(23, 32, 51, 0.1);
background: var(--app-color-control-focus);
border-color: var(--app-border-subtle);
}
.sidebar-search-icon {
@apply h-5 w-5 flex-shrink-0 text-xl;
color: #526178;
color: var(--app-text-muted);
}
.sidebar-search-input {
@apply min-w-0 flex-1 border-0 bg-transparent p-0 text-sm;
color: #172033;
color: var(--app-color-on-surface);
outline: none;
}
@@ -804,14 +827,14 @@
}
.sidebar-search-input::placeholder {
color: #7a8799;
color: var(--app-text-subtle);
}
.sidebar-floating-panel {
@apply absolute left-0 right-0 top-[calc(100%+0.6rem)] z-40 flex flex-col gap-3 rounded-[1.25rem] border p-3;
background: rgba(255, 255, 255, 0.98);
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.12);
background: var(--app-surface-raised);
border-color: var(--app-border-subtle);
box-shadow: var(--app-shadow-popover);
}
.sidebar-search-panel-collapsed {
@@ -828,22 +851,27 @@
.sidebar-search-group strong {
@apply px-2 text-xs font-black uppercase tracking-[0.18em];
color: #5d6b82;
color: var(--app-text-muted);
}
.sidebar-search-result {
@apply flex flex-col gap-1 rounded-[0.95rem] px-3 py-3 text-left transition-colors;
color: #172033;
@apply flex h-auto min-h-0 flex-col items-stretch gap-1 rounded-[0.95rem] px-3 py-3 text-left normal-case transition-colors;
color: var(--app-color-on-surface);
letter-spacing: 0;
}
.sidebar-search-result:hover {
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
}
.sidebar-search-result :deep(.v-btn__content) {
@apply flex min-w-0 flex-col items-start gap-1 whitespace-normal;
}
.sidebar-search-result small,
.sidebar-search-empty {
@apply text-xs leading-5;
color: #526178;
color: var(--app-text-muted);
}
.sidebar-search-empty {
@@ -865,7 +893,7 @@
.sidebar-notification-badge {
@apply absolute -right-2 -top-2 flex h-5 min-w-[1.25rem] items-center justify-center rounded-full px-1 text-[10px] font-black;
background: #ef4444;
color: #fffaf2;
color: var(--app-color-on-primary);
}
.sidebar-notifications-panel {
@@ -878,7 +906,7 @@
.sidebar-notifications-header strong {
@apply text-sm font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.sidebar-notifications-header span,
@@ -886,7 +914,7 @@
.sidebar-notification-row span,
.sidebar-notification-row small {
@apply text-xs leading-5;
color: #526178;
color: var(--app-text-muted);
}
.sidebar-notifications-empty {
@@ -894,20 +922,25 @@
}
.sidebar-notification-row {
@apply flex flex-col gap-1 rounded-[0.9rem] px-3 py-3 text-left transition-colors;
@apply flex h-auto min-h-0 flex-col items-stretch gap-1 rounded-[0.9rem] px-3 py-3 text-left normal-case transition-colors;
letter-spacing: 0;
}
.sidebar-notification-row:hover {
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
}
.sidebar-notification-row :deep(.v-btn__content) {
@apply flex min-w-0 flex-col items-start gap-1 whitespace-normal;
}
.sidebar-notification-row-unread {
background: rgba(15, 118, 110, 0.08);
background: color-mix(in srgb, var(--app-color-highlight) 14%, transparent);
}
.sidebar-notification-row strong {
@apply text-sm font-semibold;
color: #172033;
color: var(--app-color-on-surface);
}
.sidebar-section {
@@ -923,18 +956,21 @@
}
.sidebar-link {
@apply flex min-w-0 items-center gap-3 rounded-[1.1rem] px-4 py-3 text-sm font-semibold no-underline transition-colors;
@apply flex h-auto min-h-11 min-w-0 items-center gap-3 rounded-[1.1rem] px-4 py-3 text-sm font-semibold no-underline normal-case transition-colors;
color: #44516a;
background: transparent;
letter-spacing: 0;
justify-content: flex-start;
}
.sidebar-link:hover {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.sidebar-link-active {
background: linear-gradient(135deg, rgba(255, 138, 61, 0.14), rgba(239, 68, 68, 0.1));
color: #172033;
color: var(--app-color-on-surface);
box-shadow: inset 0 0 0 1px rgba(255, 138, 61, 0.2);
}
@@ -951,13 +987,14 @@
}
.sidebar-section-action {
@apply ml-auto flex h-11 w-11 flex-shrink-0 items-center justify-center rounded-[1rem] transition-colors no-underline;
color: #526178;
@apply ml-auto flex h-11 min-w-0 w-11 flex-shrink-0 items-center justify-center rounded-[1rem] normal-case transition-colors no-underline;
color: var(--app-text-muted);
letter-spacing: 0;
}
.sidebar-section-action:hover {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.sidebar-chevron {
@@ -974,19 +1011,28 @@
@apply h-5 w-5 flex-shrink-0 text-xl;
}
.sidebar-link :deep(.v-btn__content),
.sidebar-section-action :deep(.v-btn__content) {
@apply flex min-w-0 items-center justify-start gap-3;
}
.sidebar-section-action :deep(.v-btn__content) {
@apply justify-center;
}
.sidebar-sublist {
@apply flex flex-col gap-1 pl-4;
}
.sidebar-sublink {
@apply flex flex-col rounded-[1rem] px-4 py-3 text-sm no-underline transition-colors;
color: #526178;
color: var(--app-text-muted);
}
.sidebar-sublink:hover,
.sidebar-sublink-active {
background: rgba(23, 32, 51, 0.05);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.sidebar-sublink strong {
@@ -996,7 +1042,7 @@
.sidebar-sublink small,
.sidebar-empty {
@apply text-xs;
color: #7a8799;
color: var(--app-text-subtle);
}
.app-sidebar-collapsed {
@@ -1020,7 +1066,7 @@
}
.app-sidebar-collapsed .sidebar-search:hover {
background: rgba(23, 32, 51, 0.07);
background: var(--app-control-active);
}
.app-sidebar-collapsed .sidebar-search-panel-input {

View File

@@ -90,9 +90,10 @@
class="sidebar-workspace sidebar-workspace-bottom"
:class="{ 'sidebar-workspace-collapsed': !isExpanded }"
>
<button
<v-btn
class="sidebar-workspace-trigger"
type="button"
variant="text"
:ripple="false"
:title="!isExpanded ? userProfileStore.alias : null"
@click.stop="toggleUserMenu"
>
@@ -113,46 +114,50 @@
class="sidebar-workspace-icon"
:class="{ 'sidebar-workspace-icon-open': isUserMenuOpen }"
/>
</button>
</v-btn>
<div
v-if="isUserMenuOpen"
class="sidebar-workspace-menu"
class="sidebar-workspace-menu sidebar-menu-surface"
>
<button
class="sidebar-workspace-option"
type="button"
<v-btn
class="sidebar-workspace-option sidebar-menu-option"
variant="text"
:ripple="false"
@click="openMyFeedback"
>
<v-icon :icon="mdiBugOutline" />
<span>{{ t('nav.myFeedback') }}</span>
</button>
<div class="sidebar-workspace-separator" />
<button
class="sidebar-workspace-option"
type="button"
</v-btn>
<div class="sidebar-workspace-separator sidebar-menu-separator" />
<v-btn
class="sidebar-workspace-option sidebar-menu-option"
variant="text"
:ripple="false"
@click="openProfile"
>
<v-icon :icon="mdiAccountCircleOutline" />
<span>{{ t('nav.profile') }}</span>
</button>
<button
class="sidebar-workspace-option"
type="button"
</v-btn>
<v-btn
class="sidebar-workspace-option sidebar-menu-option"
variant="text"
:ripple="false"
@click="toggleLanguage"
>
<v-icon :icon="mdiTranslate" />
<span>{{ t('nav.language') }}</span>
</button>
<div class="sidebar-workspace-separator" />
<button
class="sidebar-workspace-option sidebar-workspace-option-danger"
type="button"
</v-btn>
<div class="sidebar-workspace-separator sidebar-menu-separator" />
<v-btn
class="sidebar-workspace-option sidebar-menu-option sidebar-workspace-option-danger sidebar-menu-option-danger"
variant="text"
:ripple="false"
@click="handleLogout"
>
<v-icon :icon="mdiLogout" />
<span>{{ t('nav.signOut') }}</span>
</button>
</v-btn>
</div>
</div>
</template>
@@ -165,26 +170,31 @@
.sidebar-workspace-bottom {
@apply py-4;
border-top: 1px solid rgba(23, 32, 51, 0.08);
border-top: 1px solid var(--app-border-subtle);
}
.sidebar-workspace-trigger {
@apply flex w-full items-center gap-3 rounded-[1.1rem] px-4 py-3 text-left transition-colors;
background: rgba(23, 32, 51, 0.04);
color: #172033;
@apply flex h-auto min-h-11 w-full items-center justify-start gap-3 rounded-[1.1rem] px-4 py-3 text-left text-sm font-semibold normal-case transition-colors;
background: transparent;
color: var(--app-color-on-surface);
letter-spacing: 0;
}
.sidebar-workspace-trigger:hover {
background: rgba(23, 32, 51, 0.07);
background: var(--app-control-hover);
}
.sidebar-workspace-trigger :deep(.v-btn__content) {
@apply flex min-w-0 flex-1 items-center justify-start gap-3;
}
.sidebar-workspace-label {
@apply flex-1 truncate text-sm font-semibold;
@apply flex-1 truncate;
}
.sidebar-workspace-icon {
@apply text-base transition-transform;
color: #5d6b82;
color: var(--app-text-muted);
}
.sidebar-workspace-icon-open {
@@ -192,12 +202,9 @@
}
.sidebar-workspace-menu {
@apply absolute bottom-[calc(100%+0.5rem)] left-0 right-0 z-30 flex flex-col gap-1 rounded-[1.25rem] border p-2;
@apply absolute bottom-[calc(100%+0.5rem)] left-0 right-0;
isolation: isolate;
background: #fffdf8;
background-clip: padding-box;
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.12);
}
.sidebar-workspace-collapsed {
@@ -208,35 +215,25 @@
@apply h-11 w-11 justify-center rounded-[1rem] p-0;
}
.sidebar-workspace-collapsed .sidebar-workspace-trigger :deep(.v-btn__content) {
@apply flex-none justify-center;
}
.sidebar-workspace-collapsed .sidebar-workspace-menu {
@apply left-[calc(100%+0.75rem)] right-auto w-56;
bottom: 1rem;
}
.sidebar-workspace-option {
@apply flex items-center gap-3 rounded-[0.95rem] px-4 py-3 text-left text-sm font-semibold transition-colors;
color: #172033;
@apply h-auto min-h-11 normal-case;
letter-spacing: 0;
}
.sidebar-workspace-option .v-icon {
.sidebar-workspace-option :deep(.v-btn__content) {
@apply flex min-w-0 items-center justify-start gap-3;
}
.sidebar-workspace-option :deep(.v-icon) {
@apply text-base;
color: #5d6b82;
}
.sidebar-workspace-option:hover {
background: rgba(23, 32, 51, 0.05);
}
.sidebar-workspace-separator {
@apply my-1;
border-top: 1px solid rgba(23, 32, 51, 0.08);
}
.sidebar-workspace-option-danger {
color: #b91c1c;
}
.sidebar-workspace-option-danger .v-icon {
color: #b91c1c;
}
</style>

View File

@@ -161,9 +161,11 @@
ref="workspaceMenuRef"
class="user-menu-wrap"
>
<button
<v-btn
class="menu-item-action workspace-trigger"
:class="{ 'workspace-trigger-static': !canOpenWorkspaceMenu }"
variant="text"
:ripple="false"
@click.stop="toggleWorkspaceMenu"
>
<AppAvatar
@@ -178,17 +180,18 @@
class="user-trigger-icon"
:class="{ 'user-trigger-icon-open': isWorkspaceMenuOpen }"
/>
</button>
</v-btn>
<div
v-if="isWorkspaceMenuOpen"
class="user-menu"
>
<button
<v-btn
v-if="canSelectAllWorkspaces"
class="user-menu-item all-workspaces-item"
:class="{ 'user-menu-item-active': workspaceStore.isAllWorkspacesSelected }"
type="button"
variant="text"
:ripple="false"
@click="chooseAllWorkspaces"
>
<AppAvatar
@@ -199,7 +202,7 @@
<span>{{ t('workspaceSelector.allWorkspaces') }}</span>
<small>{{ t('workspaceSelector.allWorkspacesDescription') }}</small>
</span>
</button>
</v-btn>
<div
v-for="workspace in visibleWorkspaces"
@@ -210,9 +213,10 @@
'workspace-menu-row-muted': workspaceStore.isAllWorkspacesSelected && !workspaceStore.isWorkspaceVisible(workspace.id),
}"
>
<button
<v-btn
class="user-menu-item workspace-menu-select"
type="button"
variant="text"
:ripple="false"
@click="chooseWorkspace(workspace.id)"
>
<AppAvatar
@@ -224,47 +228,51 @@
<span>{{ workspace.name }}</span>
<small>{{ workspace.timeZone }}</small>
</span>
</button>
</v-btn>
<button
<v-btn
v-if="canSelectAllWorkspaces"
class="workspace-visibility-button"
type="button"
variant="text"
:ripple="false"
:aria-label="workspaceStore.isWorkspaceVisible(workspace.id) ? t('workspaceSelector.hideWorkspace') : t('workspaceSelector.showWorkspace')"
@click.stop="toggleWorkspaceVisibility(workspace.id)"
>
<v-icon :icon="workspaceStore.isWorkspaceVisible(workspace.id) ? mdiEyeOutline : mdiEyeOffOutline" />
</button>
</v-btn>
<button
<v-btn
v-if="canManageWorkspaces"
class="workspace-settings-button"
type="button"
variant="text"
:ripple="false"
:aria-label="t('workspaceSelector.workspaceSettings')"
@click="openWorkspaceSettings(workspace.id)"
>
<v-icon :icon="mdiCogOutline" />
</button>
</v-btn>
</div>
<button
<v-btn
v-if="canManageWorkspaces"
class="user-menu-item user-menu-item-create"
type="button"
variant="text"
:ripple="false"
@click="openCreateWorkspace"
>
<span>{{ t('workspaceSelector.createAction') }}</span>
<v-icon :icon="mdiPlus" />
</button>
</v-btn>
<div
v-if="activeOrganization"
class="organization-switcher"
>
<div class="organization-current-row">
<button
<v-btn
class="user-menu-item organization-current"
type="button"
variant="text"
:ripple="false"
@click="openOrganizationSettings(activeOrganization.id)"
>
<AppAvatar
@@ -280,29 +288,31 @@
:icon="mdiCogOutline"
class="organization-action-icon"
/>
</button>
</v-btn>
</div>
<button
<v-btn
v-if="canSwitchOrganizations"
class="organization-swap-button"
type="button"
variant="text"
:ripple="false"
:aria-expanded="isOrganizationListOpen"
@click="toggleOrganizationList"
>
<span>Change organization</span>
<v-icon :icon="mdiSwapHorizontal" />
</button>
</v-btn>
<div
v-if="isOrganizationListOpen"
class="organization-options"
>
<button
<v-btn
v-for="organization in switchableOrganizations"
:key="organization.id"
class="user-menu-item organization-option"
type="button"
variant="text"
:ripple="false"
@click="chooseOrganization(organization.id)"
>
<AppAvatar
@@ -314,7 +324,7 @@
<span>{{ organization.name }}</span>
<small>{{ t('workspaceSelector.organizationLabel') }}</small>
</span>
</button>
</v-btn>
</div>
</div>
</div>
@@ -328,15 +338,20 @@
}
.menu-item-action {
@apply flex h-11 items-center gap-3 rounded-full px-4 transition-colors;
@apply flex h-11 items-center justify-start gap-3 rounded-full px-4 normal-case transition-colors;
background: rgba(255, 255, 255, 0.8);
color: #172033;
border: 1px solid rgba(23, 32, 51, 0.06);
color: var(--app-color-on-surface);
border: 1px solid var(--app-border-muted);
letter-spacing: 0;
}
.menu-item-action:hover {
background: #172033;
color: #fffaf2;
background: var(--app-color-primary);
color: var(--app-color-on-primary);
}
.menu-item-action :deep(.v-btn__content) {
@apply flex min-w-0 items-center justify-start gap-3;
}
.user-menu-wrap {
@@ -369,21 +384,22 @@
width: max(100%, 17rem);
max-width: min(24rem, calc(100vw - 2rem));
isolation: isolate;
background: #fffdf8;
background: var(--app-surface-raised);
background-clip: padding-box;
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.12);
border-color: var(--app-border-subtle);
box-shadow: var(--app-shadow-popover);
z-index: 40;
}
.user-menu-item {
@apply flex items-center gap-3 rounded-[0.9rem] px-3 py-3 text-left text-sm font-semibold transition-colors;
color: #172033;
@apply flex h-auto min-h-11 items-center justify-start gap-3 rounded-[0.9rem] px-3 py-3 text-left text-sm font-semibold normal-case transition-colors;
color: var(--app-color-on-surface);
letter-spacing: 0;
}
.user-menu-item:hover,
.workspace-menu-row:hover {
background: rgba(23, 32, 51, 0.06);
background: var(--app-control-hover);
}
.user-menu-item-active {
@@ -393,7 +409,7 @@
.workspace-menu-row {
@apply flex min-w-0 items-center rounded-[0.9rem] transition-colors;
color: #172033;
color: var(--app-color-on-surface);
}
.workspace-menu-row-muted {
@@ -402,8 +418,8 @@
.all-workspaces-item {
@apply mb-1 border;
border-color: rgba(23, 32, 51, 0.08);
background: rgba(23, 32, 51, 0.03);
border-color: var(--app-border-subtle);
background: var(--app-control-subtle);
}
.workspace-menu-select {
@@ -415,19 +431,21 @@
}
.workspace-settings-button {
@apply mr-2 flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-colors;
color: #526178;
@apply mr-2 flex h-8 min-w-0 w-8 flex-shrink-0 items-center justify-center rounded-full normal-case transition-colors;
color: var(--app-text-muted);
letter-spacing: 0;
}
.workspace-visibility-button {
@apply flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-colors;
color: #526178;
@apply flex h-8 min-w-0 w-8 flex-shrink-0 items-center justify-center rounded-full normal-case transition-colors;
color: var(--app-text-muted);
letter-spacing: 0;
}
.workspace-visibility-button:hover,
.workspace-settings-button:hover {
background: rgba(23, 32, 51, 0.1);
color: #172033;
background: var(--app-control-active);
color: var(--app-color-on-surface);
}
.workspace-visibility-button :deep(.v-icon),
@@ -446,17 +464,17 @@
.user-menu-item-copy small {
@apply text-xs font-medium;
color: #526178;
color: var(--app-text-muted);
}
.user-menu-item-create {
@apply justify-between border border-dashed;
border-color: rgba(23, 32, 51, 0.12);
border-color: var(--app-border-subtle);
}
.organization-switcher {
@apply mt-2 flex flex-col gap-1 border-t pt-2;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.organization-current-row {
@@ -465,31 +483,46 @@
.organization-current {
@apply w-full min-w-0 border;
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.08);
background: var(--app-control-subtle);
border-color: var(--app-border-subtle);
}
.organization-current:hover {
background: rgba(23, 32, 51, 0.07);
background: var(--app-control-active);
}
.organization-action-icon {
@apply flex-shrink-0 text-base;
color: #526178;
color: var(--app-text-muted);
}
.organization-swap-button {
@apply flex w-full items-center justify-between gap-3 rounded-[0.9rem] border px-3 py-2.5 text-sm font-semibold transition-colors;
background: rgba(23, 32, 51, 0.04);
border-color: rgba(23, 32, 51, 0.08);
color: #172033;
@apply flex h-auto min-h-11 w-full items-center justify-between gap-3 rounded-[0.9rem] border px-3 py-2.5 text-sm font-semibold normal-case transition-colors;
background: var(--app-control-subtle);
border-color: var(--app-border-subtle);
color: var(--app-color-on-surface);
letter-spacing: 0;
}
.organization-swap-button:hover {
background: rgba(23, 32, 51, 0.08);
background: var(--app-control-active);
}
.organization-options {
@apply flex flex-col gap-1;
}
.user-menu-item :deep(.v-btn__content),
.organization-swap-button :deep(.v-btn__content) {
@apply flex min-w-0 items-center justify-start gap-3;
}
.organization-swap-button :deep(.v-btn__content) {
@apply w-full justify-between;
}
.workspace-visibility-button :deep(.v-btn__content),
.workspace-settings-button :deep(.v-btn__content) {
@apply justify-center;
}
</style>

View File

@@ -2,12 +2,7 @@ import { createApp } from 'vue';
import App from './App.vue';
import router from '@/router/router.js';
import { createPinia } from 'pinia';
import './assets/main.css';
import 'vuetify/styles';
import { createVuetify } from 'vuetify';
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';
import './assets/styles.css';
import vueGoogleOauth from 'vue3-google-login';
import { useAuthStore } from '@/features/auth/stores/authStore.js';
import { useUserProfileStore } from '@/features/user-profile/stores/userProfileStore.js';
@@ -24,23 +19,9 @@ import { useChannelsStore } from '@/features/channels/stores/channelsStore.js';
import { i18n } from '@/plugins/i18n.js';
import config from '@/config.js';
import { createHead } from '@vueuse/head';
import { socializeTheme } from '@/plugins/theme.js';
import { createSocializeVuetify } from '@/plugins/vuetify.js';
const vuetify = createVuetify({
components,
directives,
icons: {
defaultSet: 'mdi',
aliases,
sets: { mdi },
},
theme: {
defaultTheme: 'socializeLight',
themes: {
socializeLight: socializeTheme,
},
},
});
const vuetify = createSocializeVuetify();
const pinia = createPinia();
const head = createHead();

View File

@@ -0,0 +1,47 @@
import { createVuetify } from 'vuetify';
import { aliases, mdi } from 'vuetify/iconsets/mdi-svg';
import * as components from 'vuetify/components';
import * as directives from 'vuetify/directives';
import { socializeTheme } from '@/plugins/theme.js';
export function createSocializeVuetify() {
return createVuetify({
components,
directives,
defaults: {
VBtn: {
rounded: 'lg',
style: 'letter-spacing: 0; text-transform: none;',
},
VCard: {
rounded: 'lg',
},
VTextField: {
color: 'primary',
density: 'comfortable',
variant: 'outlined',
},
VTextarea: {
color: 'primary',
density: 'comfortable',
variant: 'outlined',
},
VSelect: {
color: 'primary',
density: 'comfortable',
variant: 'outlined',
},
},
icons: {
defaultSet: 'mdi',
aliases,
sets: { mdi },
},
theme: {
defaultTheme: 'socializeLight',
themes: {
socializeLight: socializeTheme,
},
},
});
}

View File

@@ -31,13 +31,13 @@
@focusin="openProductMenu"
@focusout="scheduleProductMenuClose"
>
<button
<v-btn variant="text" :ripple="false"
type="button"
:aria-expanded="isProductMenuOpen"
aria-haspopup="true"
>
{{ t('public.nav.product') }}
</button>
</v-btn>
<div
class="site-product-panel"
:class="{ open: isProductMenuOpen }"
@@ -73,14 +73,14 @@
@focusin="openResourcesMenu"
@focusout="scheduleResourcesMenuClose"
>
<button
<v-btn variant="text" :ripple="false"
type="button"
:aria-expanded="isResourcesMenuOpen"
aria-haspopup="true"
@click="toggleResourcesMenu"
>
{{ t('public.nav.resources') }}
</button>
</v-btn>
<div
class="site-nav-menu"
:class="{ open: isResourcesMenuOpen }"
@@ -105,20 +105,20 @@
class="site-language-toggle"
:aria-label="t('public.nav.language')"
>
<button
<v-btn variant="text" :ripple="false"
type="button"
:class="{ active: currentLocale === 'en' }"
@click="setLocale('en')"
>
En
</button>
<button
</v-btn>
<v-btn variant="text" :ripple="false"
type="button"
:class="{ active: currentLocale === 'fr' }"
@click="setLocale('fr')"
>
Fr
</button>
</v-btn>
</div>
<router-link
@@ -267,7 +267,7 @@
@apply sticky top-0 z-30 w-full;
background: rgba(255, 250, 242, 0.9);
backdrop-filter: blur(18px);
border-bottom: 1px solid rgba(23, 32, 51, 0.08);
border-bottom: 1px solid var(--app-border-subtle);
}
.site-menu-inner {
@@ -317,8 +317,8 @@
.site-nav a:hover,
.site-nav-group:hover > button {
background: rgba(23, 32, 51, 0.06);
color: #172033;
background: var(--app-control-hover);
color: var(--app-color-on-surface);
}
.site-nav-group {
@@ -332,9 +332,9 @@
.site-nav-menu {
@apply invisible absolute left-0 top-[calc(100%+0.5rem)] flex min-w-36 flex-col gap-1 rounded-[1rem] border p-2 opacity-0 transition-opacity;
background: rgba(255, 255, 255, 0.98);
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.12);
background: var(--app-surface-raised);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-border-subtle);
}
.site-nav-group:hover .site-nav-menu,
@@ -349,8 +349,8 @@
.site-product-panel {
@apply invisible absolute left-1/2 top-full grid w-[min(56rem,calc(100vw-2rem))] -translate-x-1/2 grid-cols-3 gap-2 rounded-[1.25rem] border p-3 opacity-0 transition-opacity;
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);
box-shadow: 0 24px 60px rgba(23, 32, 51, 0.14);
}
@@ -371,7 +371,7 @@
.site-product-icon {
@apply flex h-10 w-10 items-center justify-center rounded-[0.75rem];
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.site-product-icon svg {
@@ -381,7 +381,7 @@
.site-product-link strong {
@apply block text-sm font-black leading-5;
color: #172033;
color: var(--app-color-on-surface);
}
.site-product-link small {
@@ -392,7 +392,7 @@
.site-language-toggle {
@apply flex items-center rounded-full border p-1;
background: rgba(255, 255, 255, 0.64);
border-color: rgba(23, 32, 51, 0.1);
border-color: var(--app-control-active);
}
.site-language-toggle button {
@@ -401,22 +401,22 @@
}
.site-language-toggle button:hover {
color: #172033;
color: var(--app-color-on-surface);
}
.site-language-toggle button.active {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.site-login {
@apply flex h-10 min-w-[7.75rem] items-center justify-center rounded-full px-4 text-sm font-bold no-underline transition-colors;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.site-login:hover {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
@media (max-width: 420px) {

View File

@@ -40,8 +40,8 @@
.public-page-panel {
@apply rounded-[2rem] p-6 md:p-10;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.eyebrow {
@@ -51,7 +51,7 @@
h1 {
@apply mt-4 max-w-4xl text-4xl font-black leading-tight md:text-6xl;
color: #172033;
color: var(--app-color-on-surface);
}
p {

View File

@@ -40,8 +40,8 @@
.public-page-panel {
@apply rounded-[2rem] p-6 md:p-10;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.eyebrow {
@@ -51,7 +51,7 @@
h1 {
@apply mt-4 max-w-4xl text-4xl font-black leading-tight md:text-6xl;
color: #172033;
color: var(--app-color-on-surface);
}
p {

View File

@@ -71,7 +71,7 @@
</div>
<div class="hero-actions">
<router-link to="/register">
<button class="primary">{{ t('public.landing.hero.primaryAction') }}</button>
<v-btn variant="text" :ripple="false" class="primary">{{ t('public.landing.hero.primaryAction') }}</v-btn>
</router-link>
</div>
<span class="cta-note">{{ t('public.landing.hero.ctaNote') }}</span>
@@ -145,7 +145,7 @@
<p>{{ t('public.landing.finalCta.description') }}</p>
</div>
<router-link to="/register">
<button class="primary">{{ t('public.landing.hero.primaryAction') }}</button>
<v-btn variant="text" :ripple="false" class="primary">{{ t('public.landing.hero.primaryAction') }}</v-btn>
</router-link>
</section>
@@ -165,8 +165,8 @@
.hero-card {
@apply grid gap-8 overflow-hidden rounded-[2rem] p-6 md:grid-cols-[1fr_0.88fr] md:p-10;
background: linear-gradient(145deg, #172033 0%, #25324b 65%, #314766 100%);
color: #fffaf2;
background: linear-gradient(145deg, var(--app-color-on-surface) 0%, #25324b 65%, #314766 100%);
color: var(--app-color-on-primary);
box-shadow: 0 30px 80px rgba(23, 32, 51, 0.18);
}
@@ -231,13 +231,13 @@
.preview-bar {
@apply flex items-center justify-between gap-3 rounded-[1rem] bg-white/90 px-4 py-3;
color: #172033;
color: var(--app-color-on-surface);
}
.preview-bar span,
.approval-card span {
@apply text-xs font-black uppercase tracking-[0.18em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.preview-bar strong {
@@ -252,7 +252,7 @@
.preview-row {
@apply flex items-center justify-between gap-4 rounded-[1rem] bg-white/90 p-4;
color: #172033;
color: var(--app-color-on-surface);
}
.preview-row strong {
@@ -267,12 +267,12 @@
.preview-row em {
@apply rounded-full px-3 py-1 text-xs font-black not-italic;
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.approval-card {
@apply rounded-[1rem] bg-white/95 p-5;
color: #172033;
color: var(--app-color-on-surface);
}
.approval-card strong {
@@ -286,34 +286,34 @@
.pillar-card {
@apply rounded-[1.5rem] p-6;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.pillar-card p {
@apply mt-3 text-lg font-semibold leading-7;
color: #172033;
color: var(--app-color-on-surface);
}
.focus-card {
@apply grid gap-6 rounded-[1.75rem] p-6 md:grid-cols-[1fr_1.1fr] md:p-8;
background: linear-gradient(135deg, rgba(255, 138, 61, 0.12), rgba(52, 211, 153, 0.1));
border: 1px solid rgba(23, 32, 51, 0.08);
border: 1px solid var(--app-border-subtle);
}
.focus-card h2 {
@apply mt-3 text-2xl font-black leading-tight md:text-3xl;
color: #172033;
color: var(--app-color-on-surface);
}
.inline-cta {
@apply mt-5 inline-flex h-11 items-center rounded-full px-5 text-sm font-black no-underline transition-colors;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.inline-cta:hover {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
.focus-metrics {
@@ -322,12 +322,12 @@
.focus-metrics div {
@apply rounded-[1.25rem] bg-white/70 p-5;
border: 1px solid rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-control-hover);
}
.focus-metrics strong {
@apply block text-sm font-black uppercase tracking-[0.18em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.focus-metrics span {
@@ -337,8 +337,8 @@
.final-cta {
@apply flex flex-col gap-6 rounded-[2rem] p-6 md:flex-row md:items-center md:justify-between md:p-10;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
box-shadow: 0 30px 80px rgba(23, 32, 51, 0.18);
}

View File

@@ -108,8 +108,8 @@
.public-page-panel {
@apply rounded-[2rem] p-6 md:p-10;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.eyebrow {
@@ -119,7 +119,7 @@
h1 {
@apply mt-4 max-w-4xl text-4xl font-black leading-tight md:text-6xl;
color: #172033;
color: var(--app-color-on-surface);
}
p {
@@ -133,13 +133,13 @@
.pricing-tier {
@apply relative flex min-h-[42rem] flex-col gap-6 rounded-[1.5rem] border bg-white/85 p-5;
border-color: rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.pricing-tier.featured {
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
border-color: rgba(255, 178, 107, 0.44);
box-shadow: 0 28px 70px rgba(23, 32, 51, 0.2);
}
@@ -147,16 +147,16 @@
.tier-badge {
@apply mb-4 inline-flex w-fit rounded-full px-3 py-1 text-xs font-black uppercase tracking-[0.16em];
background: #ffb26b;
color: #172033;
color: var(--app-color-on-surface);
}
.tier-top h2 {
@apply text-2xl font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.featured .tier-top h2 {
color: #fffaf2;
color: var(--app-color-on-primary);
}
.tier-top p {
@@ -176,11 +176,11 @@
.tier-price strong {
@apply text-4xl font-black leading-none;
color: #172033;
color: var(--app-color-on-surface);
}
.featured .tier-price strong {
color: #fffaf2;
color: var(--app-color-on-primary);
}
.tier-price span {
@@ -190,21 +190,21 @@
.tier-action {
@apply flex h-11 items-center justify-center rounded-full px-5 text-sm font-black no-underline transition-colors;
background: #172033;
color: #fffaf2;
background: var(--app-color-on-surface);
color: var(--app-color-on-primary);
}
.tier-action:hover {
background: #0f766e;
background: var(--app-color-on-tertiary);
}
.featured .tier-action {
background: #ffb26b;
color: #172033;
color: var(--app-color-on-surface);
}
.featured .tier-action:hover {
background: #fffaf2;
background: var(--app-color-on-primary);
}
.tier-section {
@@ -213,7 +213,7 @@
.tier-section h3 {
@apply text-xs font-black uppercase tracking-[0.18em];
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.featured .tier-section h3 {
@@ -226,13 +226,13 @@
.tier-section li {
@apply text-sm leading-6;
color: #172033;
color: var(--app-color-on-surface);
}
.tier-section li::before {
content: "✓";
@apply mr-2 font-black;
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.featured .tier-section li::before {
@@ -241,7 +241,7 @@
.limits {
@apply mt-auto border-t pt-5;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
}
.featured .limits {

View File

@@ -99,15 +99,15 @@
.feature-hero {
@apply rounded-[2rem] p-6 md:p-10;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.feature-icon,
.related-icon {
@apply flex h-12 w-12 items-center justify-center rounded-[0.9rem];
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.feature-icon svg,
@@ -123,7 +123,7 @@
h1 {
@apply mt-4 max-w-4xl text-4xl font-black leading-tight md:text-6xl;
color: #172033;
color: var(--app-color-on-surface);
}
p {
@@ -137,13 +137,13 @@
.related-card {
@apply rounded-[1.25rem] border bg-white/80 p-5;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.05);
}
.feature-detail-panel {
@apply rounded-[1.5rem] border bg-white/80 p-5 md:p-7;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.05);
}
@@ -162,13 +162,13 @@
.feature-detail-panel li span {
@apply flex h-8 w-8 items-center justify-center rounded-full text-sm font-black;
background: #0f766e;
color: #fffaf2;
background: var(--app-color-on-tertiary);
color: var(--app-color-on-primary);
}
.feature-detail-panel li strong {
@apply pt-1 text-base font-semibold leading-7;
color: #172033;
color: var(--app-color-on-surface);
}
.related-features {
@@ -177,7 +177,7 @@
.related-features h2 {
@apply mt-3 max-w-3xl text-2xl font-black leading-tight md:text-3xl;
color: #172033;
color: var(--app-color-on-surface);
}
.related-card {
@@ -191,7 +191,7 @@
.related-card strong {
@apply text-base font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.related-card span:last-child {

View File

@@ -68,8 +68,8 @@
.public-page-panel {
@apply rounded-[2rem] p-6 md:p-10;
background: rgba(255, 255, 255, 0.84);
border: 1px solid rgba(23, 32, 51, 0.08);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.06);
border: 1px solid var(--app-border-subtle);
box-shadow: 0 18px 40px var(--app-control-hover);
}
.eyebrow {
@@ -79,7 +79,7 @@
h1 {
@apply mt-4 max-w-4xl text-4xl font-black leading-tight md:text-6xl;
color: #172033;
color: var(--app-color-on-surface);
}
p {
@@ -93,7 +93,7 @@
.product-features h2 {
@apply mt-3 max-w-3xl text-2xl font-black leading-tight md:text-3xl;
color: #172033;
color: var(--app-color-on-surface);
}
.feature-grid {
@@ -102,7 +102,7 @@
.feature-card {
@apply flex min-h-48 flex-col gap-3 rounded-[1.25rem] border bg-white/80 p-5 no-underline transition-colors;
border-color: rgba(23, 32, 51, 0.08);
border-color: var(--app-border-subtle);
box-shadow: 0 18px 40px rgba(23, 32, 51, 0.05);
}
@@ -114,7 +114,7 @@
.feature-icon {
@apply flex h-11 w-11 items-center justify-center rounded-[0.85rem];
background: rgba(15, 118, 110, 0.1);
color: #0f766e;
color: var(--app-color-on-tertiary);
}
.feature-icon svg {
@@ -124,7 +124,7 @@
.feature-card strong {
@apply text-base font-black;
color: #172033;
color: var(--app-color-on-surface);
}
.feature-card span:last-child {

View File

@@ -64,6 +64,9 @@ export default defineConfig(({ isSsrBuild }) => ({
}
}
},
ssr: {
noExternal: ['vuetify'],
},
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))