cinqcinqdev-seo 0.1.29 → 0.1.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,52 +44,52 @@ const { data: stats } = await useAsyncData("admin-dashboard-stats", async () =>
44
44
 
45
45
  <!-- Header -->
46
46
  <div class="mb-8">
47
- <h1 class="text-2xl font-black text-gray-900">Tableau de bord</h1>
48
- <p class="text-sm text-gray-400 mt-1">Gérez votre contenu et vos pages.</p>
47
+ <h1 class="text-2xl font-black text-mgray">Tableau de bord</h1>
48
+ <p class="text-sm text-mgray-400 mt-1">Gérez votre contenu et vos pages.</p>
49
49
  </div>
50
50
 
51
51
  <!-- Stats row -->
52
52
  <div class="grid grid-cols-4 gap-4 mb-10">
53
- <div class="bg-white rounded-2xl p-5 border border-gray-100 shadow-sm">
54
- <p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2">Total pages</p>
55
- <p class="text-3xl font-black text-gray-900">{{ stats?.total ?? 0 }}</p>
53
+ <div class="bg-background rounded-2xl p-5 border border-mgray-100 shadow-sm">
54
+ <p class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2">Total pages</p>
55
+ <p class="text-3xl font-black text-mgray">{{ stats?.total ?? 0 }}</p>
56
56
  </div>
57
- <div class="bg-white rounded-2xl p-5 border border-gray-100 shadow-sm">
58
- <p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2">Publiées</p>
57
+ <div class="bg-background rounded-2xl p-5 border border-mgray-100 shadow-sm">
58
+ <p class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2">Publiées</p>
59
59
  <p class="text-3xl font-black text-green-600">{{ stats?.published ?? 0 }}</p>
60
60
  </div>
61
- <div class="bg-white rounded-2xl p-5 border border-gray-100 shadow-sm">
62
- <p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2">Brouillons</p>
61
+ <div class="bg-background rounded-2xl p-5 border border-mgray-100 shadow-sm">
62
+ <p class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2">Brouillons</p>
63
63
  <p class="text-3xl font-black text-amber-500">{{ stats?.drafts ?? 0 }}</p>
64
64
  </div>
65
- <div class="bg-white rounded-2xl p-5 border border-gray-100 shadow-sm">
66
- <p class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2">Templates</p>
67
- <p class="text-3xl font-black text-[#3d35ff]">{{ stats?.templates ?? 0 }}</p>
65
+ <div class="bg-background rounded-2xl p-5 border border-mgray-100 shadow-sm">
66
+ <p class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2">Templates</p>
67
+ <p class="text-3xl font-black text-primary">{{ stats?.templates ?? 0 }}</p>
68
68
  </div>
69
69
  </div>
70
70
 
71
71
  <!-- Page types grid -->
72
72
  <div class="mb-3 flex items-center justify-between">
73
- <h2 class="text-[11px] font-black uppercase tracking-widest text-gray-400">Types de pages</h2>
73
+ <h2 class="text-[11px] font-black uppercase tracking-widest text-mgray-400">Types de pages</h2>
74
74
  </div>
75
75
  <div class="grid grid-cols-2 md:grid-cols-3 gap-4">
76
76
  <NuxtLink
77
77
  v-for="type in pageTypes"
78
78
  :key="type.id"
79
79
  :to="`${basePath}/pages/${type.id}`"
80
- class="group bg-white rounded-2xl p-6 border border-gray-100 shadow-sm hover:border-[#3d35ff]/30 hover:shadow-md transition-all"
80
+ class="group bg-background rounded-2xl p-6 border border-mgray-100 shadow-sm hover:border-primary-300 hover:shadow-md transition-all"
81
81
  >
82
82
  <div class="flex items-start justify-between mb-4">
83
- <div class="w-9 h-9 rounded-xl bg-gray-50 group-hover:bg-[#3d35ff]/10 flex items-center justify-center transition-colors">
84
- <svg class="text-gray-400 group-hover:text-[#3d35ff] transition-colors" style="width:18px;height:18px" fill="none" stroke="currentColor" viewBox="0 0 24 24" v-html="type.svgPath || defaultIcons[type.id] || defaultIcons.blog_article"></svg>
83
+ <div class="w-9 h-9 rounded-xl bg-mgray-50 group-hover:bg-primary-100 flex items-center justify-center transition-colors">
84
+ <svg class="text-mgray-400 group-hover:text-primary transition-colors" style="width:18px;height:18px" fill="none" stroke="currentColor" viewBox="0 0 24 24" v-html="type.svgPath || defaultIcons[type.id] || defaultIcons.blog_article"></svg>
85
85
  </div>
86
- <span class="text-[10px] font-black px-2 py-1 rounded-full bg-gray-50 text-gray-400">
86
+ <span class="text-[10px] font-black px-2 py-1 rounded-full bg-mgray-50 text-mgray-400">
87
87
  {{ stats?.byType?.[type.id] ?? 0 }}
88
88
  </span>
89
89
  </div>
90
- <h3 class="font-black text-gray-900 text-sm group-hover:text-[#3d35ff] transition-colors">{{ type.label }}</h3>
91
- <p class="text-[11px] text-gray-400 mt-1">{{ type.desc }}</p>
92
- <div class="mt-4 flex items-center gap-1 text-[10px] font-bold text-[#3d35ff] opacity-0 group-hover:opacity-100 transition-opacity">
90
+ <h3 class="font-black text-mgray text-sm group-hover:text-primary transition-colors">{{ type.label }}</h3>
91
+ <p class="text-[11px] text-mgray-400 mt-1">{{ type.desc }}</p>
92
+ <div class="mt-4 flex items-center gap-1 text-[10px] font-bold text-primary opacity-0 group-hover:opacity-100 transition-opacity">
93
93
  Gérer <span>→</span>
94
94
  </div>
95
95
  </NuxtLink>
@@ -107,45 +107,45 @@ useHead({ title: computed(() => `${typeLabel.value} \u2014 Admin`) });
107
107
  <!-- Header -->
108
108
  <div class="mb-8 flex items-center justify-between">
109
109
  <div>
110
- <div class="flex items-center gap-2 text-[11px] text-gray-400 mb-2">
111
- <NuxtLink :to="basePath" class="hover:text-gray-600 transition-colors">Tableau de bord</NuxtLink>
110
+ <div class="flex items-center gap-2 text-[11px] text-mgray-400 mb-2">
111
+ <NuxtLink :to="basePath" class="hover:text-mgray-600 transition-colors">Tableau de bord</NuxtLink>
112
112
  <span>/</span>
113
- <span class="text-gray-600 font-medium">{{ typeLabel }}</span>
113
+ <span class="text-mgray-600 font-medium">{{ typeLabel }}</span>
114
114
  </div>
115
- <h1 class="text-2xl font-black text-gray-900">{{ typeLabel }}</h1>
116
- <p class="text-sm text-gray-400 mt-1">{{ pages?.length ?? 0 }} page{{ (pages?.length ?? 0) > 1 ? "s" : "" }}</p>
115
+ <h1 class="text-2xl font-black text-mgray">{{ typeLabel }}</h1>
116
+ <p class="text-sm text-mgray-400 mt-1">{{ pages?.length ?? 0 }} page{{ (pages?.length ?? 0) > 1 ? "s" : "" }}</p>
117
117
  </div>
118
118
  <button @click="isCreating = true"
119
- class="bg-[#3d35ff] text-white px-5 py-2.5 rounded-xl text-sm font-bold hover:bg-[#2f28cc] transition shadow-lg shadow-[#3d35ff]/20 active:scale-95">
119
+ class="bg-primary text-white px-5 py-2.5 rounded-xl text-sm font-bold hover:brightness-90 transition shadow-lg shadow-primary-200 active:scale-95">
120
120
  + Nouvelle page
121
121
  </button>
122
122
  </div>
123
123
 
124
124
  <!-- Table -->
125
- <div class="bg-white border border-gray-100 rounded-2xl shadow-sm overflow-hidden">
125
+ <div class="bg-background border border-mgray-100 rounded-2xl shadow-sm overflow-hidden">
126
126
  <div v-if="!pages?.length" class="py-24 text-center">
127
- <svg class="w-10 h-10 mx-auto text-gray-200 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
128
- <p class="text-sm font-semibold text-gray-500">Aucune page dans cette catégorie</p>
129
- <p class="text-xs text-gray-400 mt-1">Créez votre première page pour commencer</p>
130
- <button @click="isCreating = true" class="mt-5 px-5 py-2 bg-[#3d35ff] text-white rounded-xl text-xs font-bold hover:bg-[#2f28cc] transition">
127
+ <svg class="w-10 h-10 mx-auto text-mgray-200 mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
128
+ <p class="text-sm font-semibold text-mgray-500">Aucune page dans cette catégorie</p>
129
+ <p class="text-xs text-mgray-400 mt-1">Créez votre première page pour commencer</p>
130
+ <button @click="isCreating = true" class="mt-5 px-5 py-2 bg-primary text-white rounded-xl text-xs font-bold hover:brightness-90 transition">
131
131
  + Créer
132
132
  </button>
133
133
  </div>
134
134
 
135
135
  <table v-else class="w-full text-left">
136
136
  <thead>
137
- <tr class="border-b border-gray-100">
138
- <th class="px-6 py-3.5 text-[10px] font-black text-gray-400 uppercase tracking-widest">Page</th>
139
- <th class="px-6 py-3.5 text-[10px] font-black text-gray-400 uppercase tracking-widest">SEO</th>
140
- <th class="px-6 py-3.5 text-[10px] font-black text-gray-400 uppercase tracking-widest">Statut</th>
141
- <th class="px-6 py-3.5 text-[10px] font-black text-gray-400 uppercase tracking-widest text-right">Actions</th>
137
+ <tr class="border-b border-mgray-100">
138
+ <th class="px-6 py-3.5 text-[10px] font-black text-mgray-400 uppercase tracking-widest">Page</th>
139
+ <th class="px-6 py-3.5 text-[10px] font-black text-mgray-400 uppercase tracking-widest">SEO</th>
140
+ <th class="px-6 py-3.5 text-[10px] font-black text-mgray-400 uppercase tracking-widest">Statut</th>
141
+ <th class="px-6 py-3.5 text-[10px] font-black text-mgray-400 uppercase tracking-widest text-right">Actions</th>
142
142
  </tr>
143
143
  </thead>
144
144
  <tbody class="divide-y divide-gray-50">
145
- <tr v-for="page in pages" :key="page.id" class="group hover:bg-gray-50/60 transition-colors">
145
+ <tr v-for="page in pages" :key="page.id" class="group hover:bg-mgray-50/60 transition-colors">
146
146
  <td class="px-6 py-4">
147
- <div class="font-bold text-gray-900 text-sm">{{ page.title }}</div>
148
- <div class="text-[11px] text-[#3d35ff] font-mono mt-0.5 opacity-70">/{{ page.slug }}</div>
147
+ <div class="font-bold text-mgray text-sm">{{ page.title }}</div>
148
+ <div class="text-[11px] text-primary font-mono mt-0.5 opacity-70">/{{ page.slug }}</div>
149
149
  </td>
150
150
  <td class="px-6 py-4">
151
151
  <span v-if="page.seo_config?.meta_title" class="inline-flex items-center gap-1.5 text-[11px] font-semibold text-green-600">
@@ -158,24 +158,24 @@ useHead({ title: computed(() => `${typeLabel.value} \u2014 Admin`) });
158
158
  <td class="px-6 py-4">
159
159
  <span :class="[
160
160
  'inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[10px] font-black uppercase tracking-wider',
161
- page.status === 'published' ? 'bg-green-50 text-green-700' : 'bg-gray-100 text-gray-500'
161
+ page.status === 'published' ? 'bg-green-50 text-green-700' : 'bg-mgray-100 text-mgray-500'
162
162
  ]">
163
- <span :class="['w-1.5 h-1.5 rounded-full', page.status === 'published' ? 'bg-green-500' : 'bg-gray-400']"></span>
163
+ <span :class="['w-1.5 h-1.5 rounded-full', page.status === 'published' ? 'bg-green-500' : 'bg-mgray-400']"></span>
164
164
  {{ page.status === "published" ? "Publi\xE9" : "Brouillon" }}
165
165
  </span>
166
166
  </td>
167
167
  <td class="px-6 py-4">
168
168
  <div class="flex items-center justify-end gap-1">
169
169
  <NuxtLink :to="`${basePath}/editor/${page.id}`"
170
- class="px-3 py-1.5 rounded-lg text-[11px] font-bold bg-gray-100 text-gray-600 hover:bg-[#3d35ff] hover:text-white transition-all">
170
+ class="px-3 py-1.5 rounded-lg text-[11px] font-bold bg-mgray-100 text-mgray-600 hover:bg-primary hover:text-white transition-all">
171
171
  Éditer
172
172
  </NuxtLink>
173
173
  <button @click="openTemplateModal(page)"
174
- class="p-1.5 rounded-lg text-gray-300 hover:text-[#3d35ff] hover:bg-[#3d35ff]/5 transition-all" title="Sauvegarder comme template">
174
+ class="p-1.5 rounded-lg text-mgray-300 hover:text-primary hover:bg-primary-50 transition-all" title="Sauvegarder comme template">
175
175
  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
176
176
  </button>
177
177
  <button @click="confirmDelete(page.id, page.title)"
178
- class="p-1.5 rounded-lg text-gray-300 hover:text-red-500 hover:bg-red-50 transition-all" title="Supprimer">
178
+ class="p-1.5 rounded-lg text-mgray-300 hover:text-red-500 hover:bg-red-50 transition-all" title="Supprimer">
179
179
  <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>
180
180
  </button>
181
181
  </div>
@@ -188,59 +188,59 @@ useHead({ title: computed(() => `${typeLabel.value} \u2014 Admin`) });
188
188
  <!-- ── Create modal ───────────────────────────────────── -->
189
189
  <Teleport to="body">
190
190
  <div v-if="isCreating" class="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-50">
191
- <div class="bg-white rounded-2xl max-w-md w-full shadow-2xl overflow-hidden">
192
- <div class="px-7 pt-7 pb-5 border-b border-gray-100 flex items-start justify-between">
191
+ <div class="bg-background rounded-2xl max-w-md w-full shadow-2xl overflow-hidden">
192
+ <div class="px-7 pt-7 pb-5 border-b border-mgray-100 flex items-start justify-between">
193
193
  <div>
194
- <h3 class="text-lg font-black text-gray-900">Nouvelle page</h3>
195
- <p class="text-xs text-gray-400 mt-0.5">{{ typeLabel }}</p>
194
+ <h3 class="text-lg font-black text-mgray">Nouvelle page</h3>
195
+ <p class="text-xs text-mgray-400 mt-0.5">{{ typeLabel }}</p>
196
196
  </div>
197
- <button @click="isCreating = false" class="text-gray-300 hover:text-gray-500 transition-colors mt-0.5">
197
+ <button @click="isCreating = false" class="text-mgray-300 hover:text-mgray-500 transition-colors mt-0.5">
198
198
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
199
199
  </button>
200
200
  </div>
201
201
 
202
202
  <div class="px-7 py-6 space-y-5">
203
203
  <div>
204
- <label class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2 block">Titre</label>
204
+ <label class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2 block">Titre</label>
205
205
  <input v-model="newPageTitle" type="text" placeholder="Ex: Création site web"
206
- class="w-full border border-gray-200 p-3 rounded-xl text-sm focus:ring-2 focus:ring-[#3d35ff] outline-none transition" autofocus />
206
+ class="w-full border border-mgray-200 p-3 rounded-xl text-sm text-mgray focus:ring-2 focus:ring-primary outline-none transition" autofocus />
207
207
  </div>
208
208
  <div>
209
- <label class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2 block">Départ</label>
209
+ <label class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2 block">Départ</label>
210
210
  <div class="grid grid-cols-2 gap-2">
211
211
  <button @click="createMode = 'blank'"
212
212
  :class="[
213
213
  'py-3 rounded-xl border-2 text-xs font-black uppercase tracking-wide transition',
214
- createMode === 'blank' ? 'border-[#3d35ff] bg-[#3d35ff]/5 text-[#3d35ff]' : 'border-gray-100 text-gray-400 hover:border-gray-300'
214
+ createMode === 'blank' ? 'border-primary bg-primary-50 text-primary' : 'border-mgray-100 text-mgray-400 hover:border-mgray-300'
215
215
  ]">
216
216
  Page vierge
217
217
  </button>
218
218
  <button @click="createMode = 'template'"
219
219
  :class="[
220
220
  'py-3 rounded-xl border-2 text-xs font-black uppercase tracking-wide transition',
221
- createMode === 'template' ? 'border-[#3d35ff] bg-[#3d35ff]/5 text-[#3d35ff]' : 'border-gray-100 text-gray-400 hover:border-gray-300'
221
+ createMode === 'template' ? 'border-primary bg-primary-50 text-primary' : 'border-mgray-100 text-mgray-400 hover:border-mgray-300'
222
222
  ]">
223
223
  Template
224
224
  </button>
225
225
  </div>
226
226
  </div>
227
227
  <div v-if="createMode === 'template'">
228
- <label class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2 block">Template</label>
229
- <select v-model="selectedTemplateId" class="w-full border border-gray-200 p-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-[#3d35ff] transition bg-white">
228
+ <label class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2 block">Template</label>
229
+ <select v-model="selectedTemplateId" class="w-full border border-mgray-200 p-3 rounded-xl text-sm text-mgray outline-none focus:ring-2 focus:ring-primary transition bg-background">
230
230
  <option value="">— Choisir —</option>
231
231
  <option v-for="tpl in templates" :key="tpl.id" :value="tpl.id">{{ tpl.name }}</option>
232
232
  </select>
233
- <p v-if="!templates.length" class="text-[11px] text-gray-400 mt-1.5">Aucun template disponible.</p>
233
+ <p v-if="!templates.length" class="text-[11px] text-mgray-400 mt-1.5">Aucun template disponible.</p>
234
234
  </div>
235
235
  </div>
236
236
 
237
237
  <div class="px-7 pb-7 flex gap-3">
238
- <button @click="isCreating = false" class="flex-1 px-4 py-2.5 border border-gray-200 rounded-xl text-sm font-semibold hover:bg-gray-50 transition">
238
+ <button @click="isCreating = false" class="flex-1 px-4 py-2.5 border border-mgray-200 rounded-xl text-sm font-semibold text-mgray hover:bg-mgray-50 transition">
239
239
  Annuler
240
240
  </button>
241
241
  <button @click="handleCreate"
242
242
  :disabled="!newPageTitle || createMode === 'template' && !selectedTemplateId"
243
- class="flex-1 px-4 py-2.5 bg-[#3d35ff] text-white rounded-xl text-sm font-bold hover:bg-[#2f28cc] transition disabled:opacity-40 disabled:cursor-not-allowed shadow-lg shadow-[#3d35ff]/20">
243
+ class="flex-1 px-4 py-2.5 bg-primary text-white rounded-xl text-sm font-bold hover:brightness-90 transition disabled:opacity-40 disabled:cursor-not-allowed shadow-lg shadow-primary-200">
244
244
  Créer →
245
245
  </button>
246
246
  </div>
@@ -251,18 +251,18 @@ useHead({ title: computed(() => `${typeLabel.value} \u2014 Admin`) });
251
251
  <!-- ── Delete confirmation modal ─────────────────────── -->
252
252
  <Teleport to="body">
253
253
  <div v-if="deleteModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-50">
254
- <div class="bg-white rounded-2xl max-w-sm w-full shadow-2xl overflow-hidden">
254
+ <div class="bg-background rounded-2xl max-w-sm w-full shadow-2xl overflow-hidden">
255
255
  <div class="p-7">
256
256
  <div class="w-11 h-11 bg-red-50 rounded-xl flex items-center justify-center mb-4">
257
257
  <svg class="w-5 h-5 text-red-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg>
258
258
  </div>
259
- <h3 class="text-base font-black text-gray-900 mb-1">Supprimer cette page ?</h3>
260
- <p class="text-sm text-gray-500">
261
- <span class="font-semibold text-gray-700">« {{ deleteModal.title }} »</span> sera définitivement supprimée. Cette action est irréversible.
259
+ <h3 class="text-base font-black text-mgray mb-1">Supprimer cette page ?</h3>
260
+ <p class="text-sm text-mgray-500">
261
+ <span class="font-semibold text-mgray-700">« {{ deleteModal.title }} »</span> sera définitivement supprimée. Cette action est irréversible.
262
262
  </p>
263
263
  </div>
264
264
  <div class="px-7 pb-7 flex gap-3">
265
- <button @click="deleteModal = null" class="flex-1 px-4 py-2.5 border border-gray-200 rounded-xl text-sm font-semibold hover:bg-gray-50 transition">
265
+ <button @click="deleteModal = null" class="flex-1 px-4 py-2.5 border border-mgray-200 rounded-xl text-sm font-semibold text-mgray hover:bg-mgray-50 transition">
266
266
  Annuler
267
267
  </button>
268
268
  <button @click="handleDelete" :disabled="isDeleting"
@@ -277,27 +277,27 @@ useHead({ title: computed(() => `${typeLabel.value} \u2014 Admin`) });
277
277
  <!-- ── Save as template modal ─────────────────────────── -->
278
278
  <Teleport to="body">
279
279
  <div v-if="templateModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center p-4 z-50">
280
- <div class="bg-white rounded-2xl max-w-sm w-full shadow-2xl overflow-hidden">
281
- <div class="px-7 pt-7 pb-5 border-b border-gray-100 flex items-start justify-between">
280
+ <div class="bg-background rounded-2xl max-w-sm w-full shadow-2xl overflow-hidden">
281
+ <div class="px-7 pt-7 pb-5 border-b border-mgray-100 flex items-start justify-between">
282
282
  <div>
283
- <h3 class="text-base font-black text-gray-900">Sauvegarder comme template</h3>
284
- <p class="text-xs text-gray-400 mt-0.5">Ce template sera disponible lors de la création de pages.</p>
283
+ <h3 class="text-base font-black text-mgray">Sauvegarder comme template</h3>
284
+ <p class="text-xs text-mgray-400 mt-0.5">Ce template sera disponible lors de la création de pages.</p>
285
285
  </div>
286
- <button @click="templateModal = null" class="text-gray-300 hover:text-gray-500 transition-colors mt-0.5">
286
+ <button @click="templateModal = null" class="text-mgray-300 hover:text-mgray-500 transition-colors mt-0.5">
287
287
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
288
288
  </button>
289
289
  </div>
290
290
  <div class="px-7 py-6">
291
- <label class="text-[10px] font-black uppercase tracking-widest text-gray-400 mb-2 block">Nom du template</label>
291
+ <label class="text-[10px] font-black uppercase tracking-widest text-mgray-400 mb-2 block">Nom du template</label>
292
292
  <input v-model="templateName" type="text" placeholder="Ex: Landing page service"
293
- class="w-full border border-gray-200 p-3 rounded-xl text-sm focus:ring-2 focus:ring-[#3d35ff] outline-none transition" autofocus />
293
+ class="w-full border border-mgray-200 p-3 rounded-xl text-sm text-mgray focus:ring-2 focus:ring-primary outline-none transition" autofocus />
294
294
  </div>
295
295
  <div class="px-7 pb-7 flex gap-3">
296
- <button @click="templateModal = null" class="flex-1 px-4 py-2.5 border border-gray-200 rounded-xl text-sm font-semibold hover:bg-gray-50 transition">
296
+ <button @click="templateModal = null" class="flex-1 px-4 py-2.5 border border-mgray-200 rounded-xl text-sm font-semibold text-mgray hover:bg-mgray-50 transition">
297
297
  Annuler
298
298
  </button>
299
299
  <button @click="handleTurnIntoTemplate" :disabled="!templateName.trim() || isSavingTemplate"
300
- class="flex-1 px-4 py-2.5 bg-[#3d35ff] text-white rounded-xl text-sm font-bold hover:bg-[#2f28cc] transition disabled:opacity-40 shadow-lg shadow-[#3d35ff]/20">
300
+ class="flex-1 px-4 py-2.5 bg-primary text-white rounded-xl text-sm font-bold hover:brightness-90 transition disabled:opacity-40 shadow-lg shadow-primary-200">
301
301
  {{ isSavingTemplate ? "Enregistrement..." : "Enregistrer" }}
302
302
  </button>
303
303
  </div>
@@ -310,7 +310,7 @@ useHead({ title: computed(() => `${typeLabel.value} \u2014 Admin`) });
310
310
  <Transition enter-from-class="opacity-0 translate-y-2" leave-to-class="opacity-0 translate-y-2" enter-active-class="transition duration-200" leave-active-class="transition duration-200">
311
311
  <div v-if="toast" :class="[
312
312
  'fixed bottom-6 right-6 z-[100] flex items-center gap-3 px-4 py-3 rounded-xl shadow-xl text-sm font-semibold',
313
- toast.type === 'success' ? 'bg-gray-900 text-white' : 'bg-red-500 text-white'
313
+ toast.type === 'success' ? 'bg-mgray-900 text-white' : 'bg-red-500 text-white'
314
314
  ]">
315
315
  <svg v-if="toast.type === 'success'" class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7"/></svg>
316
316
  <svg v-else class="w-4 h-4 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M6 18L18 6M6 6l12 12"/></svg>
@@ -58,9 +58,9 @@ const statusClass = {
58
58
  <div v-else-if="persona">
59
59
  <!-- Hero -->
60
60
  <div class="bg-gradient-to-br from-blue-600 to-blue-800 rounded-3xl p-8 text-white mb-8 relative overflow-hidden">
61
- <div class="absolute top-0 right-0 w-64 h-64 bg-white/10 rounded-full blur-3xl -mr-16 -mt-16"></div>
61
+ <div class="absolute top-0 right-0 w-64 h-64 bg-background/10 rounded-full blur-3xl -mr-16 -mt-16"></div>
62
62
  <div class="relative z-10 flex flex-col md:flex-row items-start gap-8">
63
- <div class="w-24 h-24 bg-white/20 backdrop-blur-xl rounded-2xl flex items-center justify-center border-2 border-white/40 overflow-hidden flex-shrink-0 text-2xl font-black">
63
+ <div class="w-24 h-24 bg-background/20 backdrop-blur-xl rounded-2xl flex items-center justify-center border-2 border-white/40 overflow-hidden flex-shrink-0 text-2xl font-black">
64
64
  <img v-if="persona.avatar_url" :src="persona.avatar_url" :alt="persona.name" class="w-full h-full object-cover" />
65
65
  <span v-else>{{ getInitials(persona.name) }}</span>
66
66
  </div>
@@ -73,7 +73,7 @@ const statusClass = {
73
73
  </div>
74
74
  </div>
75
75
  <div class="flex gap-3">
76
- <button @click="editMode = !editMode" class="px-5 py-2.5 bg-white/20 hover:bg-white/30 text-white rounded-xl font-bold text-sm transition-all flex items-center gap-2">
76
+ <button @click="editMode = !editMode" class="px-5 py-2.5 bg-background/20 hover:bg-background/30 text-white rounded-xl font-bold text-sm transition-all flex items-center gap-2">
77
77
  <Icon name="mdi:pencil" /> Modifier
78
78
  </button>
79
79
  </div>
@@ -81,7 +81,7 @@ const statusClass = {
81
81
  </div>
82
82
 
83
83
  <!-- Edit Form -->
84
- <div v-if="editMode" class="bg-white rounded-3xl p-8 border border-slate-200 shadow-sm mb-8">
84
+ <div v-if="editMode" class="bg-background rounded-3xl p-8 border border-slate-200 shadow-sm mb-8">
85
85
  <h2 class="text-xl font-bold text-slate-900 mb-6">Modifier le Profil</h2>
86
86
  <div class="grid grid-cols-2 gap-6 mb-6">
87
87
  <div>
@@ -113,17 +113,17 @@ const statusClass = {
113
113
 
114
114
  <!-- Info Cards -->
115
115
  <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
116
- <div class="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm">
116
+ <div class="bg-background rounded-2xl p-6 border border-slate-200 shadow-sm">
117
117
  <h3 class="font-black text-slate-900 mb-4 flex items-center gap-2"><Icon name="mdi:account-outline" class="text-blue-600" /> A propos</h3>
118
118
  <p class="text-slate-600 leading-relaxed">{{ persona.about || "Aucune description." }}</p>
119
119
  </div>
120
- <div v-if="(persona.core_needs || []).length > 0" class="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm">
120
+ <div v-if="(persona.core_needs || []).length > 0" class="bg-background rounded-2xl p-6 border border-slate-200 shadow-sm">
121
121
  <h3 class="font-black text-slate-900 mb-4 flex items-center gap-2"><Icon name="mdi:star-outline" class="text-amber-500" /> Besoins Principaux</h3>
122
122
  <div class="flex flex-wrap gap-2">
123
123
  <span v-for="need in persona.core_needs" :key="need" class="px-3 py-1.5 bg-blue-50 text-blue-700 rounded-xl text-sm font-semibold">{{ need }}</span>
124
124
  </div>
125
125
  </div>
126
- <div v-if="(persona.goals || []).length > 0" class="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm">
126
+ <div v-if="(persona.goals || []).length > 0" class="bg-background rounded-2xl p-6 border border-slate-200 shadow-sm">
127
127
  <h3 class="font-black text-slate-900 mb-4 flex items-center gap-2"><Icon name="mdi:target" class="text-emerald-500" /> Objectifs</h3>
128
128
  <ul class="space-y-2">
129
129
  <li v-for="goal in persona.goals" :key="goal" class="flex items-start gap-2 text-sm text-slate-600">
@@ -131,7 +131,7 @@ const statusClass = {
131
131
  </li>
132
132
  </ul>
133
133
  </div>
134
- <div v-if="(persona.pain_points || []).length > 0" class="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm">
134
+ <div v-if="(persona.pain_points || []).length > 0" class="bg-background rounded-2xl p-6 border border-slate-200 shadow-sm">
135
135
  <h3 class="font-black text-slate-900 mb-4 flex items-center gap-2"><Icon name="mdi:lightning-bolt" class="text-red-500" /> Points de Douleur</h3>
136
136
  <ul class="space-y-2">
137
137
  <li v-for="pain in persona.pain_points" :key="pain" class="flex items-start gap-2 text-sm text-slate-600">
@@ -142,7 +142,7 @@ const statusClass = {
142
142
  </div>
143
143
 
144
144
  <!-- Recent Content -->
145
- <div class="bg-white rounded-2xl p-6 border border-slate-200 shadow-sm">
145
+ <div class="bg-background rounded-2xl p-6 border border-slate-200 shadow-sm">
146
146
  <h3 class="font-black text-slate-900 mb-4 flex items-center gap-2">
147
147
  <Icon name="mdi:file-document-multiple-outline" class="text-purple-500" /> Contenus associes ({{ contents.length }})
148
148
  </h3>
@@ -102,12 +102,12 @@ const viewPersona = (persona) => navigateTo(`${basePath}/personas/${persona.id}`
102
102
  </div>
103
103
  <div class="flex items-center gap-4">
104
104
  <div class="relative group">
105
- <button class="px-5 py-4 bg-white border border-slate-200 rounded-2xl font-bold text-slate-700 flex items-center gap-3 hover:border-blue-300 transition-all shadow-sm">
105
+ <button class="px-5 py-4 bg-background border border-slate-200 rounded-2xl font-bold text-slate-700 flex items-center gap-3 hover:border-blue-300 transition-all shadow-sm">
106
106
  <Icon :name="layoutIcon" class="text-xl text-blue-600" />
107
107
  <span class="text-sm">{{ layoutLabel }}</span>
108
108
  <Icon name="mdi:chevron-down" class="text-slate-300" />
109
109
  </button>
110
- <div class="absolute right-0 mt-3 w-48 bg-white border border-slate-100 rounded-2xl shadow-2xl py-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all z-30">
110
+ <div class="absolute right-0 mt-3 w-48 bg-background border border-slate-100 rounded-2xl shadow-2xl py-2 opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all z-30">
111
111
  <button @click="currentLayout = 'table'" class="w-full px-4 py-3 text-left hover:bg-blue-50 flex items-center gap-3">
112
112
  <Icon name="mdi:table" class="text-slate-400" />
113
113
  <span :class="currentLayout === 'table' ? 'text-blue-600 font-black' : 'text-slate-600 font-bold'">Tableau</span>
@@ -128,7 +128,7 @@ const viewPersona = (persona) => navigateTo(`${basePath}/personas/${persona.id}`
128
128
  <div v-for="i in 3" :key="i" class="h-40 bg-slate-100 animate-pulse rounded-3xl"></div>
129
129
  </div>
130
130
 
131
- <div v-else-if="personas.length === 0" class="bg-white rounded-[3rem] p-20 text-center border-2 border-dashed border-slate-200">
131
+ <div v-else-if="personas.length === 0" class="bg-background rounded-[3rem] p-20 text-center border-2 border-dashed border-slate-200">
132
132
  <Icon name="mdi:account-question-outline" class="text-6xl text-slate-200 mb-6" />
133
133
  <h3 class="text-2xl font-black text-slate-800">Aucune persona</h3>
134
134
  <p class="text-slate-400 mt-2 mb-8">Creez vos premiers profils comportementaux.</p>
@@ -137,7 +137,7 @@ const viewPersona = (persona) => navigateTo(`${basePath}/personas/${persona.id}`
137
137
 
138
138
  <div v-else>
139
139
  <!-- Table Layout -->
140
- <div v-if="currentLayout === 'table'" class="bg-white rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
140
+ <div v-if="currentLayout === 'table'" class="bg-background rounded-2xl border border-slate-100 shadow-sm overflow-hidden">
141
141
  <table class="w-full">
142
142
  <thead>
143
143
  <tr class="bg-slate-50 border-b border-slate-200">
@@ -182,7 +182,7 @@ const viewPersona = (persona) => navigateTo(`${basePath}/personas/${persona.id}`
182
182
 
183
183
  <!-- Bento Layout -->
184
184
  <div v-else class="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-4 gap-6">
185
- <div v-for="persona in personas" :key="persona.id" class="bg-white rounded-[2rem] border border-slate-100 p-8 shadow-sm hover:shadow-xl hover:scale-[1.02] transition-all cursor-pointer group" @click="viewPersona(persona)">
185
+ <div v-for="persona in personas" :key="persona.id" class="bg-background rounded-[2rem] border border-slate-100 p-8 shadow-sm hover:shadow-xl hover:scale-[1.02] transition-all cursor-pointer group" @click="viewPersona(persona)">
186
186
  <div class="flex items-center gap-4 mb-6">
187
187
  <div class="w-16 h-16 rounded-2xl shrink-0 overflow-hidden bg-gradient-to-br from-purple-400 to-pink-400 flex items-center justify-center text-white font-black text-xl">
188
188
  <img v-if="persona.avatar_url" :src="persona.avatar_url" class="w-full h-full object-cover" />
@@ -209,7 +209,7 @@ const viewPersona = (persona) => navigateTo(`${basePath}/personas/${persona.id}`
209
209
  <!-- Modal -->
210
210
  <Teleport to="body">
211
211
  <div v-if="showModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4" @click.self="closeModal">
212
- <div class="bg-white rounded-3xl max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl">
212
+ <div class="bg-background rounded-3xl max-w-2xl w-full max-h-[90vh] overflow-y-auto shadow-2xl">
213
213
  <div class="p-8">
214
214
  <div class="flex items-center justify-between mb-6">
215
215
  <h2 class="text-2xl font-black text-slate-900">{{ editingPersona ? "Modifier Persona" : "Nouvelle Persona" }}</h2>
@@ -86,7 +86,7 @@ const handleDelete = async (id) => {
86
86
  const formatPrice = (n) => new Intl.NumberFormat("fr-FR").format(n);
87
87
  const statusClass = (s) => ({
88
88
  active: "px-3 py-1 bg-green-100 text-green-700 rounded-lg text-sm font-semibold",
89
- inactive: "px-3 py-1 bg-gray-100 text-gray-700 rounded-lg text-sm font-semibold",
89
+ inactive: "px-3 py-1 bg-mgray-100 text-mgray-700 rounded-lg text-sm font-semibold",
90
90
  draft: "px-3 py-1 bg-yellow-100 text-yellow-700 rounded-lg text-sm font-semibold",
91
91
  archived: "px-3 py-1 bg-red-100 text-red-700 rounded-lg text-sm font-semibold"
92
92
  })[s] || "px-3 py-1 bg-green-100 text-green-700 rounded-lg text-sm font-semibold";
@@ -108,7 +108,7 @@ const statusLabel = (s) => ({ active: "Actif", inactive: "Inactif", draft: "Brou
108
108
  </div>
109
109
 
110
110
  <div class="grid grid-cols-2 md:grid-cols-4 gap-6 mb-8">
111
- <div class="bg-white rounded-2xl p-6 border border-slate-200">
111
+ <div class="bg-background rounded-2xl p-6 border border-slate-200">
112
112
  <div class="flex items-center justify-between mb-2">
113
113
  <Icon name="mdi:package-variant" class="text-3xl text-blue-600" />
114
114
  <span class="px-3 py-1 bg-blue-100 text-blue-700 text-xs font-bold rounded-full">Total</span>
@@ -116,7 +116,7 @@ const statusLabel = (s) => ({ active: "Actif", inactive: "Inactif", draft: "Brou
116
116
  <p class="text-3xl font-black text-slate-900">{{ products.length }}</p>
117
117
  <p class="text-sm text-slate-500">Produits</p>
118
118
  </div>
119
- <div class="bg-white rounded-2xl p-6 border border-slate-200">
119
+ <div class="bg-background rounded-2xl p-6 border border-slate-200">
120
120
  <div class="flex items-center justify-between mb-2">
121
121
  <Icon name="mdi:check-circle" class="text-3xl text-green-600" />
122
122
  <span class="px-3 py-1 bg-green-100 text-green-700 text-xs font-bold rounded-full">Actifs</span>
@@ -124,7 +124,7 @@ const statusLabel = (s) => ({ active: "Actif", inactive: "Inactif", draft: "Brou
124
124
  <p class="text-3xl font-black text-slate-900">{{ activeProducts }}</p>
125
125
  <p class="text-sm text-slate-500">En vente</p>
126
126
  </div>
127
- <div class="bg-white rounded-2xl p-6 border border-slate-200">
127
+ <div class="bg-background rounded-2xl p-6 border border-slate-200">
128
128
  <div class="flex items-center justify-between mb-2">
129
129
  <Icon name="mdi:tag-multiple" class="text-3xl text-orange-600" />
130
130
  <span class="px-3 py-1 bg-orange-100 text-orange-700 text-xs font-bold rounded-full">Promos</span>
@@ -132,7 +132,7 @@ const statusLabel = (s) => ({ active: "Actif", inactive: "Inactif", draft: "Brou
132
132
  <p class="text-3xl font-black text-slate-900">{{ offerProducts }}</p>
133
133
  <p class="text-sm text-slate-500">Offres actives</p>
134
134
  </div>
135
- <div class="bg-white rounded-2xl p-6 border border-slate-200">
135
+ <div class="bg-background rounded-2xl p-6 border border-slate-200">
136
136
  <div class="flex items-center justify-between mb-2">
137
137
  <Icon name="mdi:cash-multiple" class="text-3xl text-purple-600" />
138
138
  <span class="px-3 py-1 bg-purple-100 text-purple-700 text-xs font-bold rounded-full">Revenue</span>
@@ -142,7 +142,7 @@ const statusLabel = (s) => ({ active: "Actif", inactive: "Inactif", draft: "Brou
142
142
  </div>
143
143
  </div>
144
144
 
145
- <div class="bg-white rounded-3xl border border-slate-200 shadow-sm overflow-hidden">
145
+ <div class="bg-background rounded-3xl border border-slate-200 shadow-sm overflow-hidden">
146
146
  <div class="overflow-x-auto">
147
147
  <table class="w-full">
148
148
  <thead>
@@ -204,7 +204,7 @@ const statusLabel = (s) => ({ active: "Actif", inactive: "Inactif", draft: "Brou
204
204
 
205
205
  <Teleport to="body">
206
206
  <div v-if="showModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-6" @click.self="closeModal">
207
- <div class="bg-white rounded-3xl p-8 max-w-4xl w-full max-h-[90vh] overflow-y-auto shadow-2xl">
207
+ <div class="bg-background rounded-3xl p-8 max-w-4xl w-full max-h-[90vh] overflow-y-auto shadow-2xl">
208
208
  <div class="flex items-center justify-between mb-6">
209
209
  <h3 class="text-2xl font-bold text-slate-900">{{ editingProduct ? "Modifier le Produit" : "Nouveau Produit" }}</h3>
210
210
  <button @click="closeModal" class="p-2 hover:bg-slate-100 rounded-xl transition-colors"><Icon name="mdi:close" class="text-2xl text-slate-400" /></button>