Palettes variees, logo stamp croque, search/date modernises

- Palettes : Chagrine bleu lavande + ambre + rose ancien (moins aquatique),
  Grave ocre rouge + ardoise (plus lumineux), Zen vert franc + sienne + canard
  (pas de pastels glauques), Peps secondary indigo
- Logo : icone dans stamp carre rotate(-10deg), separe du texte, hover -16deg
- Login : logo stamp rotate -10deg, subtitle epure
- Search : UInput/USelect remplaces par champs custom accent-soft + icone
- Dates : icone clock + opacity 0.7
- Badges : UBadge remplace par pills custom uppercase accent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Yvv
2026-03-01 03:27:11 +01:00
parent c7cb22f313
commit 8dc0dfd452
7 changed files with 452 additions and 182 deletions

View File

@@ -105,27 +105,28 @@ function formatDate(dateStr: string): string {
>
<!-- Search / sort bar -->
<template #search>
<UInput
v-model="searchQuery"
placeholder="Rechercher une decision..."
icon="i-lucide-search"
size="sm"
class="w-full sm:w-64"
/>
<USelect
v-model="sortBy"
:items="sortOptions"
size="sm"
class="w-36"
/>
<UButton
<div class="search-field">
<UIcon name="i-lucide-search" class="search-field__icon" />
<input
v-model="searchQuery"
type="text"
class="search-field__input"
placeholder="Rechercher une decision..."
/>
</div>
<select v-model="sortBy" class="sort-select">
<option v-for="opt in sortOptions" :key="opt.value" :value="opt.value">
{{ opt.label }}
</option>
</select>
<NuxtLink
v-if="auth.isAuthenticated"
to="/decisions/new"
label="Nouvelle"
icon="i-lucide-plus"
color="primary"
size="sm"
/>
class="action-btn"
>
<UIcon name="i-lucide-plus" class="text-xs" />
<span>Nouvelle</span>
</NuxtLink>
</template>
<!-- Main content: decision list -->
@@ -175,14 +176,15 @@ function formatDate(dateStr: string): string {
</div>
<div class="decision-card__meta">
<UBadge variant="subtle" color="primary" size="xs">
<span class="decision-card__type-badge">
{{ typeLabel(decision.decision_type) }}
</UBadge>
</span>
<span class="decision-card__steps">
<UIcon name="i-lucide-layers" class="text-xs" />
{{ decision.steps.length }} etape{{ decision.steps.length !== 1 ? 's' : '' }}
</span>
<span class="decision-card__date">
<UIcon name="i-lucide-clock" class="text-xs" />
{{ formatDate(decision.created_at) }}
</span>
</div>
@@ -305,9 +307,13 @@ function formatDate(dateStr: string): string {
}
.decision-card__date {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.75rem;
color: var(--mood-text-muted);
margin-left: auto;
opacity: 0.7;
}
@media (min-width: 640px) {
@@ -316,6 +322,86 @@ function formatDate(dateStr: string): string {
}
}
.decision-card__type-badge {
font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 3px 10px;
border-radius: 20px;
background: var(--mood-accent-soft);
color: var(--mood-accent);
}
/* --- Modern search / sort / action --- */
.search-field {
flex: 1;
min-width: 10rem;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.625rem 1rem;
background: var(--mood-accent-soft);
border-radius: 12px;
transition: box-shadow 0.15s ease;
}
.search-field:focus-within {
box-shadow: 0 0 0 2.5px var(--mood-accent-soft);
}
.search-field__icon {
color: var(--mood-text-muted);
opacity: 0.5;
font-size: 0.875rem;
flex-shrink: 0;
}
.search-field__input {
flex: 1;
background: none;
font-size: 0.9375rem;
color: var(--mood-text);
min-width: 0;
}
.search-field__input::placeholder {
color: var(--mood-text-muted);
opacity: 0.4;
}
.sort-select {
padding: 0.625rem 1rem;
font-size: 0.875rem;
font-weight: 600;
color: var(--mood-text);
background: var(--mood-accent-soft);
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
min-width: 5.5rem;
}
.action-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.625rem 1.25rem;
font-size: 0.875rem;
font-weight: 700;
color: var(--mood-accent-text);
background: var(--mood-accent);
border-radius: 20px;
cursor: pointer;
text-decoration: none;
transition: transform 0.12s ease, box-shadow 0.12s ease;
white-space: nowrap;
}
.action-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--mood-shadow);
}
.action-btn:active {
transform: translateY(0);
}
.toolbox-section-title {
font-size: 0.8125rem;
font-weight: 700;

View File

@@ -163,27 +163,28 @@ async function createDocument() {
>
<!-- Search / sort bar -->
<template #search>
<UInput
v-model="searchQuery"
placeholder="Rechercher un document..."
icon="i-lucide-search"
size="sm"
class="w-full sm:w-64"
/>
<USelect
v-model="sortBy"
:items="sortOptions"
size="sm"
class="w-36"
/>
<UButton
<div class="search-field">
<UIcon name="i-lucide-search" class="search-field__icon" />
<input
v-model="searchQuery"
type="text"
class="search-field__input"
placeholder="Rechercher un document..."
/>
</div>
<select v-model="sortBy" class="sort-select">
<option v-for="opt in sortOptions" :key="opt.value" :value="opt.value">
{{ opt.label }}
</option>
</select>
<button
v-if="auth.isAuthenticated"
label="Nouveau"
icon="i-lucide-plus"
color="primary"
size="sm"
class="action-btn"
@click="openNewDocModal"
/>
>
<UIcon name="i-lucide-plus" class="text-xs" />
<span>Nouveau</span>
</button>
</template>
<!-- Main content: document list -->
@@ -228,15 +229,16 @@ async function createDocument() {
</div>
<div class="doc-card__meta">
<UBadge variant="subtle" color="primary" size="xs">
<span class="doc-card__type-badge">
{{ typeLabel(doc.doc_type) }}
</UBadge>
</span>
<span class="doc-card__version">v{{ doc.version }}</span>
<span class="doc-card__items">
<UIcon name="i-lucide-list" class="text-xs" />
{{ doc.items_count }} item{{ doc.items_count !== 1 ? 's' : '' }}
</span>
<span class="doc-card__date">
<UIcon name="i-lucide-clock" class="text-xs" />
{{ formatDate(doc.updated_at) }}
</span>
</div>
@@ -433,9 +435,13 @@ async function createDocument() {
}
.doc-card__date {
display: inline-flex;
align-items: center;
gap: 0.25rem;
font-size: 0.75rem;
color: var(--mood-text-muted);
margin-left: auto;
opacity: 0.7;
}
@media (min-width: 640px) {
@@ -473,4 +479,83 @@ async function createDocument() {
font-size: 0.8125rem;
color: var(--mood-text-muted);
}
/* --- Modern search / sort / action --- */
.search-field {
flex: 1;
min-width: 10rem;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.625rem 1rem;
background: var(--mood-accent-soft);
border-radius: 12px;
transition: box-shadow 0.15s ease;
}
.search-field:focus-within {
box-shadow: 0 0 0 2.5px var(--mood-accent-soft);
}
.search-field__icon {
color: var(--mood-text-muted);
opacity: 0.5;
font-size: 0.875rem;
flex-shrink: 0;
}
.search-field__input {
flex: 1;
background: none;
font-size: 0.9375rem;
color: var(--mood-text);
min-width: 0;
}
.search-field__input::placeholder {
color: var(--mood-text-muted);
opacity: 0.4;
}
.sort-select {
padding: 0.625rem 1rem;
font-size: 0.875rem;
font-weight: 600;
color: var(--mood-text);
background: var(--mood-accent-soft);
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
min-width: 5.5rem;
}
.action-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.625rem 1.25rem;
font-size: 0.875rem;
font-weight: 700;
color: var(--mood-accent-text);
background: var(--mood-accent);
border-radius: 20px;
cursor: pointer;
transition: transform 0.12s ease, box-shadow 0.12s ease;
white-space: nowrap;
}
.action-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--mood-shadow);
}
.action-btn:active {
transform: translateY(0);
}
.doc-card__type-badge {
font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 3px 10px;
border-radius: 20px;
background: var(--mood-accent-soft);
color: var(--mood-accent);
}
</style>

View File

@@ -62,8 +62,7 @@ onMounted(() => {
</div>
<h1 class="login-card__title">Connexion</h1>
<p class="login-card__subtitle">
<span class="login-card__g">ğ</span><span class="login-card__paren">(</span>Decision<span class="login-card__paren">)</span>
· Duniter V2 · Ed25519
Duniter V2 · Ed25519
</p>
</div>
@@ -173,26 +172,14 @@ onMounted(() => {
font-size: 1.75rem;
color: var(--mood-accent-text);
background: var(--mood-accent);
border-radius: 16px;
border-radius: 14px;
margin-bottom: 1rem;
transform: rotate(-10deg);
}
.login-card__logo-icon {
transform: scaleX(-1);
}
.login-card__title {
font-size: 1.5rem;
font-weight: 800;
color: var(--mood-text);
margin: 0;
}
@media (min-width: 640px) {
.login-card__title {
font-size: 1.75rem;
}
}
.login-card__subtitle {
font-size: 0.8125rem;
color: var(--mood-text-muted);
@@ -204,13 +191,18 @@ onMounted(() => {
font-size: 0.9375rem;
}
}
.login-card__g {
font-style: italic;
font-weight: 700;
.login-card__title {
font-size: 1.5rem;
font-weight: 800;
color: var(--mood-text);
margin: 0;
}
.login-card__paren {
font-weight: 300;
opacity: 0.5;
@media (min-width: 640px) {
.login-card__title {
font-size: 1.75rem;
}
}
/* Steps */

View File

@@ -140,27 +140,28 @@ async function handleCreate() {
>
<!-- Search / sort bar -->
<template #search>
<UInput
v-model="searchQuery"
placeholder="Rechercher un mandat..."
icon="i-lucide-search"
size="sm"
class="w-full sm:w-64"
/>
<USelect
v-model="sortBy"
:items="sortOptions"
size="sm"
class="w-36"
/>
<UButton
<div class="search-field">
<UIcon name="i-lucide-search" class="search-field__icon" />
<input
v-model="searchQuery"
type="text"
class="search-field__input"
placeholder="Rechercher un mandat..."
/>
</div>
<select v-model="sortBy" class="sort-select">
<option v-for="opt in sortOptions" :key="opt.value" :value="opt.value">
{{ opt.label }}
</option>
</select>
<button
v-if="auth.isAuthenticated"
label="Nouveau"
icon="i-lucide-plus"
color="primary"
size="sm"
class="action-btn"
@click="showCreateModal = true"
/>
>
<UIcon name="i-lucide-plus" class="text-xs" />
<span>Nouveau</span>
</button>
</template>
<!-- Main content: mandates list -->
@@ -248,9 +249,9 @@ async function handleCreate() {
</div>
<div class="mandate-card__meta">
<UBadge variant="subtle" color="primary" size="xs">
<span class="mandate-card__type-badge">
{{ typeLabel(mandate.mandate_type) }}
</UBadge>
</span>
<span class="mandate-card__steps">
<UIcon name="i-lucide-layers" class="text-xs" />
{{ mandate.steps.length }} etape{{ mandate.steps.length !== 1 ? 's' : '' }}
@@ -550,4 +551,83 @@ async function handleCreate() {
font-size: 0.8125rem;
color: var(--mood-text-muted);
}
.mandate-card__type-badge {
font-size: 0.6875rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.04em;
padding: 3px 10px;
border-radius: 20px;
background: var(--mood-accent-soft);
color: var(--mood-accent);
}
/* --- Modern search / sort / action --- */
.search-field {
flex: 1;
min-width: 10rem;
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.625rem 1rem;
background: var(--mood-accent-soft);
border-radius: 12px;
transition: box-shadow 0.15s ease;
}
.search-field:focus-within {
box-shadow: 0 0 0 2.5px var(--mood-accent-soft);
}
.search-field__icon {
color: var(--mood-text-muted);
opacity: 0.5;
font-size: 0.875rem;
flex-shrink: 0;
}
.search-field__input {
flex: 1;
background: none;
font-size: 0.9375rem;
color: var(--mood-text);
min-width: 0;
}
.search-field__input::placeholder {
color: var(--mood-text-muted);
opacity: 0.4;
}
.sort-select {
padding: 0.625rem 1rem;
font-size: 0.875rem;
font-weight: 600;
color: var(--mood-text);
background: var(--mood-accent-soft);
border-radius: 12px;
cursor: pointer;
appearance: none;
-webkit-appearance: none;
min-width: 5.5rem;
}
.action-btn {
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.625rem 1.25rem;
font-size: 0.875rem;
font-weight: 700;
color: var(--mood-accent-text);
background: var(--mood-accent);
border-radius: 20px;
cursor: pointer;
transition: transform 0.12s ease, box-shadow 0.12s ease;
white-space: nowrap;
}
.action-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px var(--mood-shadow);
}
.action-btn:active {
transform: translateY(0);
}
</style>