feat(ui): refonte de l'interface
This commit is contained in:
1 parent
3ede3e808c
commit
09eb1fa3aa
79 files changed
+5323
-3514
No files matched your search
@@ -6,10 +6,10 @@
|
||||
</div>
|
||||
|
||||
<template v-else>
|
||||
<section class="settings-card flex items-center gap-4">
|
||||
<section class="card flex items-center gap-4">
|
||||
<span
|
||||
class="w-9 h-9 rounded-lg flex items-center justify-center shrink-0"
|
||||
:class="status.empty ? 'bg-yellow-500/10 text-yellow-500' : 'bg-green-500/10 text-green-400'"
|
||||
class="w-9 h-9 rounded-full flex items-center justify-center shrink-0"
|
||||
:class="status.empty ? 'bg-accent-muted text-accent' : 'bg-ok/10 text-ok'"
|
||||
>
|
||||
<Library :size="17" />
|
||||
</span>
|
||||
@@ -17,7 +17,7 @@
|
||||
<p class="text-sm text-primary font-medium">
|
||||
{{ status.empty ? 'Catalogue non téléchargé' : `${status.count} séries disponibles` }}
|
||||
</p>
|
||||
<p class="text-xs text-muted mt-0.5">
|
||||
<p class="text-meta text-muted mt-0.5">
|
||||
{{ status.empty
|
||||
? 'Sans catalogue, la médiathèque reste vide.'
|
||||
: 'Le catalogue se met à jour automatiquement.' }}
|
||||
@@ -28,13 +28,13 @@
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<section class="settings-card flex items-center gap-4">
|
||||
<span class="w-9 h-9 rounded-lg bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<section class="card flex items-center gap-4">
|
||||
<span class="w-9 h-9 rounded-full bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<ScanSearch :size="17" />
|
||||
</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-primary font-medium">Vous avez déjà des séries Fankai ?</p>
|
||||
<p class="text-xs text-muted mt-0.5">
|
||||
<p class="text-meta text-muted mt-0.5">
|
||||
<template v-if="scanResult">{{ scanResult.found }} fichiers analysés · {{ scanResult.added }} référencés.</template>
|
||||
<template v-else>Analysez la médiathèque pour référencer les fichiers présents, sans les déplacer.</template>
|
||||
</p>
|
||||
@@ -44,7 +44,7 @@
|
||||
</button>
|
||||
</section>
|
||||
|
||||
<p v-if="warnEmpty" class="text-sm text-yellow-500" role="alert">
|
||||
<p v-if="warnEmpty" class="text-body text-accent" role="alert">
|
||||
Le catalogue est encore vide. Téléchargez-le, ou cliquez à nouveau sur « Suivant » pour continuer.
|
||||
</p>
|
||||
</template>
|
||||
|
||||
@@ -8,25 +8,25 @@
|
||||
<template v-else>
|
||||
<!-- Clients existants -->
|
||||
<div v-if="clients.length > 0" class="flex flex-col gap-2">
|
||||
<div v-for="client in clients" :key="client.uuid" class="settings-card flex items-center gap-3">
|
||||
<div v-for="client in clients" :key="client.uuid" class="card flex items-center gap-3">
|
||||
<span
|
||||
class="w-2 h-2 rounded-full shrink-0"
|
||||
:class="health[client.uuid] === true ? 'bg-green-500' : health[client.uuid] === false ? 'bg-red-500' : 'bg-border'"
|
||||
:class="health[client.uuid] === true ? 'bg-ok' : health[client.uuid] === false ? 'bg-err' : 'bg-border'"
|
||||
/>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-primary font-medium truncate">{{ client.name }}</p>
|
||||
<p class="text-xs text-muted mt-0.5">
|
||||
<p class="text-meta text-muted mt-0.5">
|
||||
{{ labelOf(client.type) }}
|
||||
<template v-if="health[client.uuid] === false"> · <span class="text-red-400">injoignable</span></template>
|
||||
<template v-else-if="health[client.uuid] === true"> · <span class="text-green-400">connecté</span></template>
|
||||
<template v-if="health[client.uuid] === false"> · <span class="text-err">injoignable</span></template>
|
||||
<template v-else-if="health[client.uuid] === true"> · <span class="text-ok">connecté</span></template>
|
||||
</p>
|
||||
</div>
|
||||
<button @click="edit(client)" class="btn-ghost text-xs">Modifier</button>
|
||||
<button @click="edit(client)" class="btn-ghost btn-sm">Modifier</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Formulaire -->
|
||||
<div v-if="formOpen" class="settings-card flex flex-col gap-4">
|
||||
<div v-if="formOpen" class="card flex flex-col gap-4">
|
||||
<p class="text-sm font-semibold text-primary">{{ editing ? 'Modifier le client' : 'Ajouter un client' }}</p>
|
||||
<TorrentClientForm
|
||||
:key="formKey"
|
||||
@@ -42,22 +42,22 @@
|
||||
</button>
|
||||
|
||||
<!-- Rappel chemins -->
|
||||
<div class="flex items-start gap-3 px-4 py-3 rounded-lg border border-border bg-card/50">
|
||||
<div class="flex items-start gap-3 px-4 py-3 rounded-field border border-border bg-card/50">
|
||||
<Info :size="15" class="text-muted mt-0.5 shrink-0" />
|
||||
<p class="text-xs text-muted leading-relaxed">
|
||||
<p class="text-meta text-muted leading-relaxed">
|
||||
Le client doit enregistrer ses téléchargements dans un dossier que FanKarr voit
|
||||
<template v-if="settings.completePath">(<code class="font-mono text-secondary">{{ settings.completePath }}</code>)</template>.
|
||||
<template v-if="settings.completePath">(<span class="text-secondary">{{ settings.completePath }}</span>)</template>.
|
||||
S'il tourne sur une autre machine ou dans un autre conteneur, renseignez
|
||||
<span class="text-secondary">Chemin distant</span> et <span class="text-secondary">Chemin local</span>
|
||||
dans les paramètres avancés du client.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="warnSkip" class="flex items-start gap-3 px-4 py-3 rounded-lg border border-yellow-500/40 bg-yellow-500/5" role="alert">
|
||||
<TriangleAlert :size="15" class="text-yellow-500 mt-0.5 shrink-0" />
|
||||
<div v-if="warnSkip" class="flex items-start gap-3 px-4 py-3 rounded-field border border-accent/30 bg-accent/5" role="alert">
|
||||
<TriangleAlert :size="15" class="text-accent mt-0.5 shrink-0" />
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<p class="text-sm text-yellow-500 font-medium">Aucun client configuré</p>
|
||||
<p class="text-xs text-muted">
|
||||
<p class="text-body text-accent font-medium">Aucun client configuré</p>
|
||||
<p class="text-meta text-muted">
|
||||
Sans client, FanKarr ne pourra rien télécharger. Cliquez à nouveau sur « Suivant » pour continuer quand même,
|
||||
vous pourrez l'ajouter plus tard dans Paramètres → Clients de téléchargement.
|
||||
</p>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6">
|
||||
|
||||
<div class="settings-card flex flex-col gap-5">
|
||||
<div class="card flex flex-col gap-5">
|
||||
<SettingsToggle
|
||||
v-model="form.autoImport"
|
||||
label="Import automatique"
|
||||
@@ -25,13 +25,13 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="settings-card flex flex-col gap-3">
|
||||
<div class="card flex flex-col gap-3">
|
||||
<SettingsToggle
|
||||
v-model="form.nfoSupport"
|
||||
label="Fichiers NFO et images"
|
||||
description="Télécharge NFO et visuels à côté de chaque épisode lors de l'import."
|
||||
/>
|
||||
<div class="flex items-start gap-2.5 px-3 py-2.5 rounded-lg border border-border bg-shell/50 text-xs text-muted leading-relaxed">
|
||||
<div class="flex items-start gap-2.5 px-3 py-2.5 rounded-field border border-border bg-main/50 text-meta text-muted leading-relaxed">
|
||||
<Info :size="13" class="shrink-0 mt-0.5" />
|
||||
<p>
|
||||
Inutile si vous utilisez l'agent Fankai sur <span class="text-primary">Jellyfin, Plex, Emby ou Kodi</span> :
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="error" class="text-sm text-red-400" role="alert">{{ error }}</p>
|
||||
<p v-if="error" class="text-body text-err" role="alert">{{ error }}</p>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -2,67 +2,68 @@
|
||||
<div class="flex flex-col gap-4">
|
||||
|
||||
<!-- Jellyfin -->
|
||||
<section class="settings-card flex flex-col gap-4">
|
||||
<section class="card flex flex-col gap-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="w-9 h-9 rounded-lg bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<span class="w-9 h-9 rounded-full bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<Server :size="17" />
|
||||
</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-primary font-medium flex items-center gap-2">
|
||||
Jellyfin
|
||||
<span v-if="jellyfin?.test?.ok" class="text-[11px] text-green-400 font-normal">connecté</span>
|
||||
<span v-if="jellyfin?.test?.ok" class="pill pill-ok h-5 px-2 text-[10.5px]">Connecté</span>
|
||||
</p>
|
||||
<p class="text-xs text-muted mt-0.5 leading-relaxed">
|
||||
<p class="text-meta text-muted mt-0.5 leading-relaxed">
|
||||
Permet à vos utilisateurs Jellyfin de se connecter à FanKarr et de faire des demandes depuis le plugin FanKarr Search.
|
||||
</p>
|
||||
</div>
|
||||
<button @click="jellyfinOpen = !jellyfinOpen" :aria-expanded="jellyfinOpen" class="btn-secondary shrink-0 text-xs">
|
||||
<button @click="jellyfinOpen = !jellyfinOpen" :aria-expanded="jellyfinOpen" class="btn-secondary btn-sm shrink-0">
|
||||
{{ jellyfinOpen ? 'Replier' : 'Configurer' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<template v-if="jellyfinOpen">
|
||||
<div class="h-px bg-hover" />
|
||||
<JellyfinConnectionForm @change="jellyfin = $event" />
|
||||
|
||||
<div v-if="jellyfin?.test?.ok" class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-3 flex-wrap">
|
||||
<button @click="syncUsers" :disabled="syncing" class="btn-secondary text-xs">
|
||||
<button @click="syncUsers" :disabled="syncing" class="btn-secondary btn-sm">
|
||||
{{ syncing ? 'Synchronisation…' : 'Synchroniser les utilisateurs' }}
|
||||
</button>
|
||||
<span v-if="syncResult" class="text-xs text-green-400">
|
||||
<span v-if="syncResult" class="text-meta text-ok">
|
||||
{{ syncResult.created }} créé{{ syncResult.created > 1 ? 's' : '' }} · {{ syncResult.skipped }} ignoré{{ syncResult.skipped > 1 ? 's' : '' }}
|
||||
</span>
|
||||
<span v-if="syncError" class="text-xs text-red-400">{{ syncError }}</span>
|
||||
<span v-if="syncError" class="text-meta text-err">{{ syncError }}</span>
|
||||
</div>
|
||||
<p class="text-xs text-muted">Crée un compte FanKarr pour chaque utilisateur Jellyfin. La synchronisation se relance ensuite toutes les heures.</p>
|
||||
<p class="text-meta text-muted">Crée un compte FanKarr pour chaque utilisateur Jellyfin. La synchronisation se relance ensuite toutes les heures.</p>
|
||||
</div>
|
||||
</template>
|
||||
</section>
|
||||
|
||||
<!-- Plex -->
|
||||
<section class="settings-card flex flex-col gap-4">
|
||||
<section class="card flex flex-col gap-4">
|
||||
<div class="flex items-start gap-3">
|
||||
<span class="w-9 h-9 rounded-lg bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<span class="w-9 h-9 rounded-full bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<Tv :size="17" />
|
||||
</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-primary font-medium flex items-center gap-2">
|
||||
Plex
|
||||
<span v-if="context.plexOpened" class="text-[11px] text-muted font-normal">assistant ouvert</span>
|
||||
<span v-if="context.plexOpened" class="text-meta text-muted font-normal">assistant ouvert</span>
|
||||
</p>
|
||||
<p class="text-xs text-muted mt-0.5 leading-relaxed">
|
||||
<p class="text-meta text-muted mt-0.5 leading-relaxed">
|
||||
Crée une bibliothèque Plex sur votre médiathèque, reliée à l'agent de métadonnées Fankai.
|
||||
Requiert Plex Media Server 1.43 ou plus récent pour la configuration automatique.
|
||||
</p>
|
||||
</div>
|
||||
<button @click="openPlex" :disabled="!settings.mediaPath" class="btn-secondary shrink-0 text-xs">
|
||||
<button @click="openPlex" :disabled="!settings.mediaPath" class="btn-secondary btn-sm shrink-0">
|
||||
Lancer l'assistant Plex
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="!settings.mediaPath" class="text-xs text-yellow-500">Renseignez d'abord la médiathèque à l'étape Dossiers.</p>
|
||||
<p v-if="!settings.mediaPath" class="text-meta text-accent">Renseignez d'abord la médiathèque à l'étape Dossiers.</p>
|
||||
</section>
|
||||
|
||||
<p class="text-xs text-muted">Pas de serveur multimédia pour l'instant ? Passez cette étape, tout se configure aussi plus tard.</p>
|
||||
<p class="text-meta text-muted">Pas de serveur multimédia pour l'instant ? Passez cette étape, tout se configure aussi plus tard.</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,84 +1,84 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6">
|
||||
|
||||
<div class="settings-card flex flex-col gap-5">
|
||||
<div class="card flex flex-col gap-5">
|
||||
<div v-for="field in fields" :key="field.key">
|
||||
<div class="flex items-center gap-2 mb-1.5">
|
||||
<label :for="`setup-${field.key}`" class="settings-label">
|
||||
<label :for="`setup-${field.key}`" class="field-label">
|
||||
{{ field.label }}
|
||||
<span v-if="field.required" class="text-red-400 ml-0.5">*</span>
|
||||
<span v-if="field.required" class="text-err ml-0.5">*</span>
|
||||
</label>
|
||||
<span v-if="!field.required" class="text-[10px] text-muted border border-border px-1.5 py-0.5 rounded">recommandé</span>
|
||||
<span v-if="!field.required" class="pill pill-neutral h-5 px-2 text-[10.5px]">recommandé</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<input
|
||||
:id="`setup-${field.key}`"
|
||||
v-model.trim="form[field.key]"
|
||||
:placeholder="field.placeholder"
|
||||
class="settings-input font-mono"
|
||||
class="field"
|
||||
spellcheck="false"
|
||||
/>
|
||||
<button @click="openPicker(field.key)" class="btn-secondary shrink-0 flex items-center gap-1.5" :title="`Parcourir — ${field.label}`">
|
||||
<button @click="openPicker(field.key)" class="btn-secondary shrink-0" :title="`Parcourir — ${field.label}`">
|
||||
<FolderOpen :size="14" /> <span class="hidden sm:inline">Parcourir</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p v-if="checking && form[field.key]" class="text-xs text-muted mt-1.5">Vérification…</p>
|
||||
<p v-else-if="statusOf(field.key)?.error" class="text-xs text-red-400 mt-1.5 flex items-center gap-1.5">
|
||||
<p v-if="checking && form[field.key]" class="text-meta text-muted mt-1.5">Vérification…</p>
|
||||
<p v-else-if="statusOf(field.key)?.error" class="text-meta text-err mt-1.5 flex items-center gap-1.5">
|
||||
<X :size="12" class="shrink-0" /> {{ statusOf(field.key)?.error }}
|
||||
</p>
|
||||
<p v-else-if="statusOf(field.key)?.writable" class="text-xs text-green-400 mt-1.5 flex items-center gap-1.5">
|
||||
<p v-else-if="statusOf(field.key)?.writable" class="text-meta text-ok mt-1.5 flex items-center gap-1.5">
|
||||
<Check :size="12" class="shrink-0" /> Dossier accessible en écriture
|
||||
</p>
|
||||
<p v-else class="text-xs text-muted mt-1.5">{{ field.help }}</p>
|
||||
<p v-else class="text-meta text-muted mt-1.5">{{ field.help }}</p>
|
||||
</div>
|
||||
|
||||
<p v-if="result?.relation === 'same'" class="text-xs text-red-400 flex items-start gap-1.5">
|
||||
<p v-if="result?.relation === 'same'" class="text-meta text-err flex items-start gap-1.5">
|
||||
<X :size="12" class="shrink-0 mt-0.5" /> La médiathèque doit être distincte du dossier de téléchargements.
|
||||
</p>
|
||||
<p v-else-if="result?.relation === 'nested'" class="text-xs text-yellow-500 flex items-start gap-1.5">
|
||||
<p v-else-if="result?.relation === 'nested'" class="text-meta text-accent flex items-start gap-1.5">
|
||||
<TriangleAlert :size="12" class="shrink-0 mt-0.5" />
|
||||
Un dossier est à l'intérieur de l'autre : ça fonctionne, mais le scan de la médiathèque verra aussi les téléchargements.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Mode d'import -->
|
||||
<div class="settings-card flex flex-col gap-3">
|
||||
<label class="settings-label">Mode d'import</label>
|
||||
<div class="card flex flex-col gap-3">
|
||||
<label class="field-label">Mode d'import</label>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-2">
|
||||
<button
|
||||
v-for="mode in modes"
|
||||
:key="mode.id"
|
||||
@click="form.organizeMode = mode.id"
|
||||
:aria-pressed="form.organizeMode === mode.id"
|
||||
class="p-3 rounded-lg border text-left transition-colors"
|
||||
:class="form.organizeMode === mode.id ? 'border-accent bg-accent-muted' : 'border-border hover:border-secondary'"
|
||||
class="flex flex-col justify-start px-3.5 py-3 rounded-field border text-left transition-colors"
|
||||
:class="form.organizeMode === mode.id ? 'border-accent/50 bg-accent-muted' : 'border-border-light hover:bg-hover'"
|
||||
>
|
||||
<p class="text-sm font-medium" :class="form.organizeMode === mode.id ? 'text-accent' : 'text-primary'">
|
||||
{{ mode.label }}
|
||||
<span v-if="mode.id === 'hardlink'" class="text-[10px] font-normal text-muted ml-1">recommandé</span>
|
||||
<span v-if="mode.id === 'hardlink'" class="text-meta font-normal text-muted ml-1">recommandé</span>
|
||||
</p>
|
||||
<p class="text-xs text-muted mt-1 leading-relaxed">{{ mode.text }}</p>
|
||||
<p class="text-meta text-muted mt-1 leading-relaxed">{{ mode.text }}</p>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Résultat du test hardlink -->
|
||||
<div v-if="result && form.organizeMode === 'hardlink'" class="text-xs">
|
||||
<p v-if="result.hardlink.tested && result.hardlink.ok" class="text-green-400 flex items-center gap-1.5">
|
||||
<div v-if="result && form.organizeMode === 'hardlink'" class="text-meta">
|
||||
<p v-if="result.hardlink.tested && result.hardlink.ok" class="text-ok flex items-center gap-1.5">
|
||||
<Check :size="12" class="shrink-0" /> {{ result.hardlink.message }}
|
||||
</p>
|
||||
<div v-else-if="result.hardlink.tested" class="flex flex-col gap-2 px-3 py-2.5 rounded-lg border border-yellow-500/40 bg-yellow-500/5">
|
||||
<p class="text-yellow-500 flex items-start gap-1.5">
|
||||
<div v-else-if="result.hardlink.tested" class="flex flex-col gap-2 px-3 py-2.5 rounded-field border border-accent/30 bg-accent/5">
|
||||
<p class="text-accent flex items-start gap-1.5">
|
||||
<TriangleAlert :size="12" class="shrink-0 mt-0.5" /> {{ result.hardlink.message }}
|
||||
</p>
|
||||
<p class="text-muted">Sans hardlink, FanKarr copiera les fichiers (espace disque doublé).</p>
|
||||
<button @click="form.organizeMode = 'copy'" class="btn-secondary text-xs self-start">Passer en mode Copier</button>
|
||||
<button @click="form.organizeMode = 'copy'" class="btn-secondary btn-sm self-start">Passer en mode Copier</button>
|
||||
</div>
|
||||
<p v-else class="text-muted">{{ result.hardlink.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p v-if="error" class="text-sm text-red-400" role="alert">{{ error }}</p>
|
||||
<p v-if="error" class="text-body text-err" role="alert">{{ error }}</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-6">
|
||||
|
||||
<ul class="settings-card p-0 divide-y divide-border">
|
||||
<ul class="card p-0 divide-y divide-border">
|
||||
<li v-for="row in rows" :key="row.label" class="flex items-center gap-3 px-4 py-3">
|
||||
<span class="w-6 h-6 rounded-full flex items-center justify-center shrink-0" :class="stateClass[row.state]">
|
||||
<span v-if="row.state === 'loading'" class="w-3 h-3 border border-border border-t-accent rounded-full animate-spin" />
|
||||
@@ -12,14 +12,14 @@
|
||||
</span>
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="text-sm text-primary">{{ row.label }}</p>
|
||||
<p class="text-xs text-muted truncate" :title="row.value">{{ row.value }}</p>
|
||||
<p class="text-meta text-muted truncate" :title="row.value">{{ row.value }}</p>
|
||||
</div>
|
||||
<button @click="context.goto(row.step)" class="btn-ghost text-xs shrink-0">Modifier</button>
|
||||
<button @click="context.goto(row.step)" class="btn-ghost btn-sm shrink-0">Modifier</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-2">
|
||||
<button @click="done(true)" :disabled="finishing || !settings.mediaPath" class="btn-primary flex items-center justify-center gap-1.5">
|
||||
<button @click="done(true)" :disabled="finishing || !settings.mediaPath" class="btn-primary">
|
||||
<Compass :size="15" />
|
||||
{{ context.relaunch ? 'Revoir la visite guidée' : "Terminer et découvrir l'interface" }}
|
||||
</button>
|
||||
@@ -27,7 +27,7 @@
|
||||
{{ context.relaunch ? 'Fermer' : 'Terminer sans la visite' }}
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="!context.relaunch" class="text-xs text-muted -mt-3">
|
||||
<p v-if="!context.relaunch" class="text-meta text-muted -mt-3">
|
||||
La visite guidée présente chaque écran en une minute. Vous pourrez la relancer depuis le bouton « ? » de la barre latérale.
|
||||
</p>
|
||||
|
||||
@@ -49,9 +49,9 @@ const finishing = ref(false)
|
||||
|
||||
const stateClass: Record<RowState, string> = {
|
||||
loading: 'bg-hover',
|
||||
ok : 'bg-green-500/15 text-green-400',
|
||||
warn : 'bg-yellow-500/15 text-yellow-500',
|
||||
error : 'bg-red-500/15 text-red-400',
|
||||
ok : 'bg-ok/15 text-ok',
|
||||
warn : 'bg-accent-muted text-accent',
|
||||
error : 'bg-err/15 text-err',
|
||||
neutral: 'bg-hover text-muted',
|
||||
}
|
||||
|
||||
|
||||
@@ -3,42 +3,42 @@
|
||||
|
||||
<!-- Fonctionnement -->
|
||||
<ol class="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<li v-for="(item, i) in flow" :key="item.title" class="settings-card flex gap-3">
|
||||
<span class="w-8 h-8 rounded-lg bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<li v-for="(item, i) in flow" :key="item.title" class="card flex gap-3">
|
||||
<span class="w-8 h-8 rounded-full bg-accent-muted text-accent flex items-center justify-center shrink-0">
|
||||
<component :is="item.icon" :size="16" />
|
||||
</span>
|
||||
<div class="min-w-0">
|
||||
<p class="text-sm text-primary font-medium">{{ i + 1 }}. {{ item.title }}</p>
|
||||
<p class="text-xs text-muted mt-0.5 leading-relaxed">{{ item.text }}</p>
|
||||
<p class="text-meta text-muted mt-0.5 leading-relaxed">{{ item.text }}</p>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<!-- Ce qu'on va configurer -->
|
||||
<div class="settings-card flex flex-col gap-3">
|
||||
<p class="settings-label">Au programme</p>
|
||||
<div class="card flex flex-col gap-3">
|
||||
<p class="field-label">Au programme</p>
|
||||
<ul class="flex flex-col gap-2">
|
||||
<li v-for="item in checklist" :key="item.label" class="flex items-start gap-2.5 text-sm">
|
||||
<li v-for="item in checklist" :key="item.label" class="flex items-start gap-2.5 text-body">
|
||||
<Check :size="14" class="text-accent mt-0.5 shrink-0" />
|
||||
<span class="text-secondary">
|
||||
{{ item.label }}
|
||||
<span v-if="item.optional" class="text-muted text-xs">(optionnel)</span>
|
||||
<span v-if="item.optional" class="text-muted text-meta">(optionnel)</span>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
<p class="text-xs text-muted">Comptez environ 5 minutes.</p>
|
||||
<p class="text-meta text-muted">Comptez environ 5 minutes.</p>
|
||||
</div>
|
||||
|
||||
<!-- Docker -->
|
||||
<div v-if="isDocker" class="flex items-start gap-3 px-4 py-3 rounded-lg border border-accent/30 bg-accent-muted">
|
||||
<div v-if="isDocker" class="flex items-start gap-3 px-4 py-3 rounded-field border border-accent/30 bg-accent-muted">
|
||||
<HardDrive :size="16" class="text-accent mt-0.5 shrink-0" />
|
||||
<div class="flex flex-col gap-1">
|
||||
<p class="text-sm text-primary font-medium">FanKarr tourne dans Docker</p>
|
||||
<p class="text-xs text-muted leading-relaxed">
|
||||
<p class="text-meta text-muted leading-relaxed">
|
||||
Les chemins à renseigner sont ceux <span class="text-primary">vus depuis le conteneur</span>.
|
||||
Pour profiter des hardlinks, montez un seul volume parent qui contient à la fois les téléchargements
|
||||
et la médiathèque (ex. <code class="font-mono text-secondary">/data/downloads</code> et
|
||||
<code class="font-mono text-secondary">/data/medias</code>).
|
||||
et la médiathèque (ex. <span class="text-secondary">/data/downloads</span> et
|
||||
<span class="text-secondary">/data/medias</span>).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user