feat(site,docs): aligne le site vitrine et la doc sur l'app « Emerald »

Site (packages/site) : adopte le design system Emerald (polices Inter +
JetBrains Mono variables, tokens sémantiques, thème clair/sombre + bascule)
et met les mockups à jour sur l'app réelle.

- style.css : tokens Emerald (@theme sombre + override html[data-theme=light]) ;
  lib/theme.ts + ThemeToggle.vue + anti-FOUC index.html ; sweep des couleurs
  brutes vers les tokens dans toutes les sections.
- Mockups fidèles à l'IDE multi-projet : HeroMockup (rail ActivityBar au lieu
  de la sidebar large + v obsolète retirée), ShowcaseSection (supervision au
  lieu du dashboard worktree-first, onglets mobiles réels), WorkspaceShowcase
  (diff-add/del, bouton commit accent-solid) ; framing « worktree-first »
  résiduel levé (i18n).
- og-cover.png rafraîchi (carte Emerald).

Docs : README.md + README.fr.md (retrait « Status: MVP », ajout du langage
Emerald + thème clair/sombre/système, VSIX 0.2.0 -> 0.3.0, section Screenshots),
vscode README (VSIX 0.3.0), brand README (thème clair), CHANGELOG daemon 3.2.0.
Captures IDE sombre + clair (brand/screenshot-ide-*.png).
This commit is contained in:
2026-07-20 22:48:59 +02:00
parent 063f5e928b
commit adc53b413e
37 changed files with 887 additions and 519 deletions
+7 -7
View File
@@ -9,7 +9,7 @@ const { t } = useI18n();
</script>
<template>
<footer class="relative z-[1] border-t border-[#1c1c1f]">
<footer class="relative z-[1] border-t border-border-soft">
<div class="mx-auto flex max-w-[1200px] flex-wrap items-center justify-between gap-5 px-6 py-[34px]">
<div class="flex items-center gap-[11px]">
<img
@@ -20,28 +20,28 @@ const { t } = useI18n();
class="h-[22px] w-[22px] object-contain"
style="filter: grayscale(1) brightness(1.5); opacity: 0.4"
/>
<span class="font-mono text-sm text-zinc-300">git-arboretum.com</span>
<span class="ml-1 text-[13px] text-zinc-600">· {{ t('footTag') }}</span>
<span class="font-mono text-sm text-fg-muted">git-arboretum.com</span>
<span class="ml-1 text-[13px] text-fg-subtle">· {{ t('footTag') }}</span>
</div>
<div class="flex items-center gap-[22px] text-sm">
<a :href="REPO" target="_blank" rel="noopener" class="inline-flex items-center gap-1.5 text-zinc-400 no-underline transition-colors hover:text-emerald-400">
<a :href="REPO" target="_blank" rel="noopener" class="inline-flex items-center gap-1.5 text-fg-muted no-underline transition-colors hover:text-accent">
<IconGitea :size="15" />
Gitea
</a>
<a :href="LICENSE" target="_blank" rel="noopener" class="text-zinc-400 no-underline transition-colors hover:text-emerald-400">
<a :href="LICENSE" target="_blank" rel="noopener" class="text-fg-muted no-underline transition-colors hover:text-accent">
{{ t('license') }}
</a>
<a
:href="COFFEE"
target="_blank"
rel="noopener"
class="inline-flex items-center gap-1.5 text-zinc-400 no-underline transition-colors hover:text-amber-400 focus-visible:rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-amber-400/70"
class="inline-flex items-center gap-1.5 text-fg-muted no-underline transition-colors hover:text-warn focus-visible:rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-warn/70"
>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2v2" /><path d="M14 2v2" /><path d="M5 8h13a1 1 0 0 1 1 1v2a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1Z" /><path d="M6 15a4 4 0 0 0 4 4h2a4 4 0 0 0 4-4" /><path d="M19 9h1.5a2.5 2.5 0 0 1 0 5H18" /></svg>
{{ t('coffee') }}
</a>
<div class="flex items-center gap-2">
<code class="font-mono text-[12.5px] text-zinc-600">{{ INSTALL_COMMAND }}</code>
<code class="font-mono text-[12.5px] text-fg-subtle">{{ INSTALL_COMMAND }}</code>
<CopyButton variant="icon" :text="INSTALL_COMMAND" :label="t('copyCommand')" />
</div>
</div>
+6 -4
View File
@@ -2,6 +2,7 @@
import { useI18n } from 'vue-i18n';
import { REPO } from '../lib/links';
import LangToggle from './LangToggle.vue';
import ThemeToggle from './ThemeToggle.vue';
import IconGitea from './icons/IconGitea.vue';
const { t } = useI18n();
@@ -18,10 +19,10 @@ const navLinks = [
<template>
<header
class="sticky top-0 z-50 border-b border-[#1c1c1f] bg-[rgba(9,9,11,0.72)] backdrop-blur-[14px]"
class="sticky top-0 z-50 border-b border-border-soft bg-surface-0/72 backdrop-blur-[14px]"
>
<div class="mx-auto flex h-16 max-w-[1200px] items-center justify-between gap-6 px-6">
<a href="#top" class="flex items-center gap-2.5 text-zinc-100 no-underline">
<a href="#top" class="flex items-center gap-2.5 text-fg no-underline">
<img
src="/assets/arboretum-mark.png"
alt="Arboretum"
@@ -37,20 +38,21 @@ const navLinks = [
v-for="link in navLinks"
:key="link.href"
:href="link.href"
class="text-[14.5px] text-zinc-400 no-underline transition-colors hover:text-zinc-100"
class="text-[14.5px] text-fg-muted no-underline transition-colors hover:text-fg"
>
{{ t(link.key) }}
</a>
</nav>
<div class="flex items-center gap-3.5">
<ThemeToggle />
<LangToggle />
<a
:href="REPO"
target="_blank"
rel="noopener"
aria-label="Gitea"
class="inline-flex items-center gap-[7px] rounded-lg border border-zinc-800 px-[13px] py-[7px] text-[13.5px] font-medium text-zinc-300 no-underline transition-colors hover:border-emerald-500/50 hover:text-emerald-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70"
class="inline-flex items-center gap-[7px] rounded-lg border border-border px-[13px] py-[7px] text-[13.5px] font-medium text-fg-muted no-underline transition-colors hover:border-accent hover:text-accent"
>
<IconGitea :size="16" />
Gitea
+5 -5
View File
@@ -28,9 +28,9 @@ const { copied, copy } = useCopy();
type="button"
:aria-label="label || t('copy')"
:class="[
'inline-flex flex-none items-center gap-[7px] border-l border-zinc-800 bg-zinc-900 font-mono text-[13px] font-semibold transition-colors hover:bg-zinc-800 hover:text-emerald-400 focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-emerald-500/70',
'inline-flex flex-none items-center gap-[7px] border-l border-border bg-surface-1 font-mono text-[13px] font-semibold transition-colors hover:bg-surface-2 hover:text-accent focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-accent/70',
barClass,
copied ? 'text-emerald-400' : 'text-zinc-300',
copied ? 'text-accent' : 'text-fg-muted',
]"
@click="copy(text)"
>
@@ -44,10 +44,10 @@ const { copied, copy } = useCopy();
:aria-label="label || t('copy')"
:title="copied ? t('copied') : label || t('copy')"
:class="[
'inline-flex flex-none items-center justify-center rounded-md border p-1.5 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70',
'inline-flex flex-none items-center justify-center rounded-md border p-1.5 transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent/70',
copied
? 'border-emerald-500/40 bg-zinc-800 text-emerald-400'
: 'border-zinc-800 bg-zinc-900/80 text-zinc-400 hover:border-emerald-500/40 hover:bg-zinc-800 hover:text-emerald-400',
? 'border-accent/40 bg-surface-2 text-accent'
: 'border-border bg-surface-1/80 text-fg-muted hover:border-accent/40 hover:bg-surface-2 hover:text-accent',
]"
@click="copy(text)"
>
@@ -16,30 +16,30 @@ const bullets = ['dlNoNode', 'dlBundled', 'dlAutoUpdate'] as const;
<template>
<section id="download" class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 pb-[100px]">
<div v-reveal class="mb-[40px] max-w-[720px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('dlKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,38px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('dlKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,38px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('dlTitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('dlBody') }}</p>
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('dlBody') }}</p>
</div>
<div v-reveal class="grid gap-4 md:grid-cols-3">
<div
v-for="p in platforms"
:key="p.key"
class="flex flex-col gap-1 rounded-[14px] border border-zinc-800 bg-[#09090b] p-5 shadow-card"
class="flex flex-col gap-1 rounded-[14px] border border-border bg-surface-0 p-5 shadow-card"
>
<div class="flex items-center gap-2 text-zinc-100">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-emerald-400" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line x1="12" x2="12" y1="15" y2="3" /></svg>
<div class="flex items-center gap-2 text-fg">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-accent" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line x1="12" x2="12" y1="15" y2="3" /></svg>
<span class="text-[15px] font-semibold">{{ t(p.key) }}</span>
</div>
<span class="pl-[26px] font-mono text-[12.5px] text-zinc-500">{{ t(p.hint) }}</span>
<span class="pl-[26px] font-mono text-[12.5px] text-fg-subtle">{{ t(p.hint) }}</span>
</div>
</div>
<ul v-reveal class="mt-6 flex flex-wrap gap-x-6 gap-y-2">
<li v-for="b in bullets" :key="b" class="flex items-center gap-2 text-[14px] text-zinc-300">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" class="text-emerald-400" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>
<li v-for="b in bullets" :key="b" class="flex items-center gap-2 text-[14px] text-fg-muted">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" class="text-accent" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>
{{ t(b) }}
</li>
</ul>
@@ -49,7 +49,7 @@ const bullets = ['dlNoNode', 'dlBundled', 'dlAutoUpdate'] as const;
:href="RELEASES"
target="_blank"
rel="noopener"
class="inline-flex items-center gap-2 rounded-lg bg-emerald-500 px-4 py-2.5 text-[14.5px] font-semibold text-emerald-950 no-underline transition-colors hover:bg-emerald-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70"
class="inline-flex items-center gap-2 rounded-lg bg-accent-solid px-4 py-2.5 text-[14.5px] font-semibold text-white no-underline transition-colors hover:bg-accent-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent/70"
>
{{ t('dlGet') }}
</a>
@@ -57,12 +57,12 @@ const bullets = ['dlNoNode', 'dlBundled', 'dlAutoUpdate'] as const;
:href="DESKTOP_SRC"
target="_blank"
rel="noopener"
class="inline-flex items-center gap-2 rounded-lg border border-zinc-800 px-4 py-2.5 text-[14.5px] font-medium text-zinc-300 no-underline transition-colors hover:border-emerald-500/50 hover:text-emerald-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70"
class="inline-flex items-center gap-2 rounded-lg border border-border px-4 py-2.5 text-[14.5px] font-medium text-fg-muted no-underline transition-colors hover:border-accent/50 hover:text-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent/70"
>
{{ t('dlSource') }}
</a>
</div>
<p v-reveal class="mt-4 max-w-[720px] text-[13.5px] leading-[1.55] text-zinc-500">{{ t('dlNote') }}</p>
<p v-reveal class="mt-4 max-w-[720px] text-[13.5px] leading-[1.55] text-fg-subtle">{{ t('dlNote') }}</p>
</section>
</template>
+7 -7
View File
@@ -25,26 +25,26 @@ function panelStyle(i: number) {
<template>
<section id="faq" class="mx-auto max-w-[780px] scroll-mt-[84px] px-6 pb-[100px]">
<div v-reveal class="mb-[38px] text-center">
<div class="mb-3.5 font-mono text-xs uppercase tracking-[0.14em] text-emerald-400">{{ t('navFaq') }}</div>
<h2 class="m-0 text-[clamp(28px,3.4vw,40px)] font-semibold tracking-[-0.025em] text-zinc-50">{{ t('faqTitle') }}</h2>
<div class="mb-3.5 font-mono text-xs uppercase tracking-[0.14em] text-accent">{{ t('navFaq') }}</div>
<h2 class="m-0 text-[clamp(28px,3.4vw,40px)] font-semibold tracking-[-0.025em] text-fg">{{ t('faqTitle') }}</h2>
</div>
<div v-reveal>
<div v-for="(f, i) in items" :key="i" class="border-t" :class="open === i ? 'border-emerald-400/40' : 'border-zinc-800'">
<div v-for="(f, i) in items" :key="i" class="border-t" :class="open === i ? 'border-accent/40' : 'border-border'">
<button
type="button"
:aria-expanded="open === i"
:aria-controls="`faq-panel-${i}`"
class="flex w-full cursor-pointer items-center justify-between gap-4 border-none bg-transparent px-1 py-5 text-left text-[clamp(16px,2vw,18px)] font-medium text-zinc-50 focus-visible:rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70"
class="flex w-full cursor-pointer items-center justify-between gap-4 border-none bg-transparent px-1 py-5 text-left text-[clamp(16px,2vw,18px)] font-medium text-fg focus-visible:rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent"
@click="toggle(i)"
>
<span>{{ f.q }}</span>
<span class="flex flex-none text-emerald-400 transition-transform duration-300" :class="open === i ? 'rotate-180' : ''">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
<span class="flex flex-none text-accent transition-transform duration-300" :class="open === i ? 'rotate-180' : ''">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
</span>
</button>
<div :id="`faq-panel-${i}`" :style="panelStyle(i)" :inert="open !== i" :aria-hidden="open !== i">
<p class="m-0 max-w-[640px] px-1 pb-5 text-[15.5px] leading-[1.6] text-zinc-400">{{ f.a }}</p>
<p class="m-0 max-w-[640px] px-1 pb-5 text-[15.5px] leading-[1.6] text-fg-muted">{{ f.a }}</p>
</div>
</div>
</div>
+4 -4
View File
@@ -4,14 +4,14 @@ defineProps<{ title: string }>();
<template>
<div
class="rounded-xl border border-zinc-800 bg-zinc-900/50 p-6 transition-[transform,border-color] duration-[180ms] ease-in-out hover:-translate-y-[3px] hover:border-emerald-400/40"
class="rounded-xl border border-border bg-surface-1/50 p-6 transition-[transform,border-color] duration-[180ms] ease-in-out hover:-translate-y-[3px] hover:border-accent/40"
>
<div
class="mb-4 inline-flex h-[42px] w-[42px] items-center justify-center rounded-[10px] bg-emerald-500/10 text-emerald-400"
class="mb-4 inline-flex h-[42px] w-[42px] items-center justify-center rounded-[10px] bg-accent/10 text-accent"
>
<slot name="icon" />
</div>
<h3 class="m-0 mb-[7px] text-lg font-semibold text-zinc-50">{{ title }}</h3>
<p class="m-0 text-[14.5px] leading-[1.55] text-zinc-400"><slot /></p>
<h3 class="m-0 mb-[7px] text-lg font-semibold text-fg">{{ title }}</h3>
<p class="m-0 text-[14.5px] leading-[1.55] text-fg-muted"><slot /></p>
</div>
</template>
@@ -7,8 +7,8 @@ const { t } = useI18n();
<template>
<section id="features" class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 pb-[100px]">
<div v-reveal class="mb-[46px] text-center">
<div class="mb-3.5 font-mono text-xs uppercase tracking-[0.14em] text-emerald-400">{{ t('featKicker') }}</div>
<h2 class="m-0 text-[clamp(28px,3.4vw,40px)] font-semibold tracking-[-0.025em] text-zinc-50">
<div class="mb-3.5 font-mono text-xs uppercase tracking-[0.14em] text-accent">{{ t('featKicker') }}</div>
<h2 class="m-0 text-[clamp(28px,3.4vw,40px)] font-semibold tracking-[-0.025em] text-fg">
{{ t('featTitle') }}
</h2>
</div>
@@ -32,9 +32,9 @@ const { t } = useI18n();
<template #icon>
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 12h-4l-3 9L9 3l-3 9H2" /></svg>
</template>
<span class="text-sky-300">{{ t('busy') }}</span> ·
<span class="text-amber-300">{{ t('waiting') }}</span> ·
<span class="text-emerald-400">{{ t('idle') }}</span> · {{ t('feat3Desc') }}
<span class="text-info">{{ t('busy') }}</span> ·
<span class="text-warn">{{ t('waiting') }}</span> ·
<span class="text-accent">{{ t('idle') }}</span> · {{ t('feat3Desc') }}
</FeatureCard>
<FeatureCard :title="t('feat4Title')">
+7 -7
View File
@@ -12,8 +12,8 @@ const { t } = useI18n();
<section class="mx-auto max-w-[1200px] px-6 pb-[100px]">
<div
v-reveal
class="rounded-[20px] border border-zinc-800 px-6 py-[clamp(36px,5vw,64px)] text-center"
style="background: radial-gradient(120% 140% at 50% 0%, rgba(16, 185, 129, 0.1), transparent 60%), #0c0c0e"
class="rounded-[20px] border border-border px-6 py-[clamp(36px,5vw,64px)] text-center"
style="background: radial-gradient(120% 140% at 50% 0%, color-mix(in srgb, var(--color-accent) 10%, transparent), transparent 60%), var(--color-surface-0)"
>
<img
src="/assets/arboretum-mark.png"
@@ -22,16 +22,16 @@ const { t } = useI18n();
height="52"
class="mx-auto mb-5 block h-[52px] w-[52px] object-contain"
/>
<h2 class="m-0 mb-3.5 text-[clamp(30px,4vw,46px)] font-bold leading-[1.08] tracking-[-0.03em] text-zinc-50">
<h2 class="m-0 mb-3.5 text-[clamp(30px,4vw,46px)] font-bold leading-[1.08] tracking-[-0.03em] text-fg">
{{ t('ctaTitle') }}
</h2>
<p class="mx-auto mb-7 max-w-[480px] text-[17px] text-zinc-400">{{ t('ctaBody') }}</p>
<p class="mx-auto mb-7 max-w-[480px] text-[17px] text-fg-muted">{{ t('ctaBody') }}</p>
<div
class="mx-auto flex max-w-[460px] items-stretch overflow-hidden rounded-[10px] border border-zinc-800 bg-zinc-950"
class="mx-auto flex max-w-[460px] items-stretch overflow-hidden rounded-[10px] border border-border bg-surface-0"
>
<div class="flex min-w-0 flex-1 items-center gap-2.5 overflow-x-auto whitespace-nowrap px-4 font-mono text-sm">
<span class="text-emerald-400">$</span><span class="text-zinc-200">{{ INSTALL_COMMAND }}</span>
<span class="text-accent">$</span><span class="text-fg">{{ INSTALL_COMMAND }}</span>
</div>
<CopyButton variant="bar" :text="INSTALL_COMMAND" :label="t('copyCommand')" bar-class="px-4" />
</div>
@@ -41,7 +41,7 @@ const { t } = useI18n();
:href="REPO"
target="_blank"
rel="noopener"
class="inline-flex items-center gap-2 text-[14.5px] text-zinc-400 no-underline transition-colors hover:text-emerald-400"
class="inline-flex items-center gap-2 text-[14.5px] text-fg-muted no-underline transition-colors hover:text-accent"
>
<IconGitea :size="16" />
{{ t('ctaSource') }}
+109 -126
View File
@@ -4,35 +4,47 @@ import { useI18n } from 'vue-i18n';
import { useHeroTimeline, type SessionState } from '../composables/useHeroTimeline';
import { DLG_OPTS } from '../i18n/content';
import type { AppLocale } from '../i18n';
import IconGitea from './icons/IconGitea.vue';
const { t, locale } = useI18n();
const { anim } = useHeroTimeline('hero-stage');
// Couleurs des lignes de terminal par type (porté de renderVals.C).
// Couleurs des lignes de terminal par type, tokenisées (suivent le thème clair/sombre).
const LINE_COLORS: Record<string, string> = {
cmd: '#52525b',
tool: '#a1a1aa',
edit: '#34d399',
add: '#34d399',
del: '#f87171',
ok: '#34d399',
warn: '#fcd34d',
run: '#7dd3fc',
cmd: 'var(--color-fg-subtle)',
tool: 'var(--color-fg-muted)',
edit: 'var(--color-accent)',
add: 'var(--color-accent)',
del: 'var(--color-danger)',
ok: 'var(--color-accent)',
warn: 'var(--color-warn)',
run: 'var(--color-info)',
};
// Couleurs alignées sur SessionStateBadge de l'app (zinc/emerald/amber/sky de Tailwind).
const PILL: Record<SessionState, { bg: string; fg: string; dot: string; pulse: string }> = {
idle: { bg: '#022c22', fg: '#34d399', dot: '#34d399', pulse: '' },
busy: { bg: '#082f49', fg: '#7dd3fc', dot: '#7dd3fc', pulse: 'pulseSky 2s ease-in-out infinite' },
waiting: { bg: '#451a03', fg: '#fcd34d', dot: '#fcd34d', pulse: 'pulseAmber 2.2s ease-in-out infinite' },
// Pastille d'état, alignée sur SessionStateBadge + lib/status-tokens de l'app
// (waiting -> warn, busy -> info, idle -> accent), via color-mix pour le fond teinté.
const PILL: Record<SessionState, { bg: string; fg: string; pulse: string }> = {
idle: {
bg: 'color-mix(in oklab, var(--color-accent) 15%, transparent)',
fg: 'var(--color-accent)',
pulse: '',
},
busy: {
bg: 'color-mix(in oklab, var(--color-info) 15%, transparent)',
fg: 'var(--color-info)',
pulse: 'pulseSky 2s ease-in-out infinite',
},
waiting: {
bg: 'color-mix(in oklab, var(--color-warn) 15%, transparent)',
fg: 'var(--color-warn)',
pulse: 'pulseAmber 2.2s ease-in-out infinite',
},
};
const pill = computed(() => PILL[anim.value.sess]);
const sessText = computed(() => t(anim.value.sess));
const termLines = computed(() =>
anim.value.lines.map((l) => ({ text: l.text, color: LINE_COLORS[l.k] ?? '#d4d4d8' })),
anim.value.lines.map((l) => ({ text: l.text, color: LINE_COLORS[l.k] ?? 'var(--color-fg-muted)' })),
);
// Options du dialogue de permission : reproduit DialogPrompt (boutons numérotés + Deny).
@@ -48,137 +60,108 @@ const dlgOptions = computed(() =>
<template>
<div id="hero-stage" class="relative min-w-[300px] flex-[1_1_480px]">
<div
class="relative overflow-hidden rounded-[14px] border border-zinc-800 bg-zinc-950 shadow-hero"
>
<div class="relative overflow-hidden rounded-[14px] border border-border bg-surface-0 shadow-hero">
<!-- barre de fenêtre -->
<div class="flex items-center gap-2 border-b border-[#1c1c1f] bg-[#0c0c0e] px-[14px] py-[11px]">
<span class="h-2.5 w-2.5 rounded-full bg-zinc-700"></span>
<span class="h-2.5 w-2.5 rounded-full bg-zinc-700"></span>
<span class="h-2.5 w-2.5 rounded-full bg-zinc-700"></span>
<span class="ml-2 font-mono text-[11.5px] text-zinc-600">arboretum · localhost:7317</span>
<div class="flex items-center gap-2 border-b border-border-soft bg-surface-1 px-[14px] py-[11px]">
<span class="h-2.5 w-2.5 rounded-full bg-danger"></span>
<span class="h-2.5 w-2.5 rounded-full bg-warn"></span>
<span class="h-2.5 w-2.5 rounded-full bg-accent"></span>
<span class="ml-2 font-mono text-[11.5px] text-fg-subtle">arboretum · localhost:7317</span>
</div>
<div class="flex min-h-[440px]">
<!-- sidebar (fidèle à AppSidebar : Worktrees / Sessions / Groups, puis Réglages / Aide / Gitea / Café) -->
<div
class="flex w-[190px] flex-none flex-col border-r border-[#1c1c1f] bg-zinc-900/40 px-2 py-3"
>
<div class="flex items-center gap-2 px-2 pb-3">
<img
src="/assets/arboretum-mark.png"
alt=""
width="22"
height="22"
class="h-[22px] w-[22px] object-contain"
/>
<span class="text-[14px] font-semibold text-zinc-100">Arboretum</span>
<!-- rail ActivityBar (fidèle à ActivityBar.vue : icônes explorer / git / sessions / groups) -->
<div class="flex w-12 flex-none flex-col items-center gap-1 border-r border-border bg-surface-1 py-2">
<!-- explorer (actif) -->
<div class="relative flex h-9 w-9 items-center justify-center rounded-[9px] bg-surface-2 text-accent">
<span class="absolute top-1/2 left-0 h-5 w-0.5 -translate-y-1/2 rounded-full bg-accent"></span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M9 21V9" /></svg>
</div>
<div
class="mb-2 flex items-center gap-2 rounded-lg border border-zinc-800 bg-zinc-950/40 px-2.5 py-1.5"
>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#52525b" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>
<span class="flex-1 text-[12px] text-zinc-500">{{ t('mSearch') }}</span>
<span class="rounded border border-zinc-700 px-[5px] py-px font-mono text-[10px] text-zinc-500">⌘K</span>
<!-- git -->
<div class="flex h-9 w-9 items-center justify-center rounded-[9px] text-fg-subtle">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
</div>
<!-- nav primaire (fidèle à AppSidebar : IDE actif, puis Worktrees / Sessions / Groups) -->
<div class="flex flex-col gap-1">
<div class="flex items-center gap-2.5 rounded-lg bg-zinc-800 px-2.5 py-1.5 text-zinc-100">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M9 21V9" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mIde') }}</span>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mWorktrees') }}</span>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 11 2-2-2-2" /><path d="M11 13h4" /><rect width="18" height="18" x="3" y="3" rx="2" ry="2" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mSessions') }}</span>
<span
v-show="anim.att > 0"
class="rounded-full bg-amber-500/20 px-1.5 text-[11px] font-semibold text-amber-300"
>{{ anim.att }}</span
>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /><path d="M7 16.5 12 13.5" /><path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /><path d="m17 16.5 4.74-2.85" /><path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0z" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mGroups') }}</span>
</div>
<!-- sessions (+ badge attention) -->
<div class="relative flex h-9 w-9 items-center justify-center rounded-[9px] text-fg-subtle">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 11 2-2-2-2" /><path d="M11 13h4" /><rect width="18" height="18" x="3" y="3" rx="2" ry="2" /></svg>
<span v-show="anim.att > 0" class="absolute top-1 right-1 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-warn px-1 text-[9px] font-semibold text-zinc-950">{{ anim.att }}</span>
</div>
<!-- groups -->
<div class="flex h-9 w-9 items-center justify-center rounded-[9px] text-fg-subtle">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /><path d="M7 16.5 12 13.5" /><path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /><path d="m17 16.5 4.74-2.85" /><path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0z" /></svg>
</div>
<div class="flex-1"></div>
<!-- nav secondaire -->
<div class="flex flex-col gap-1">
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" /><circle cx="12" cy="12" r="3" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mSettings') }}</span>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10" /><path d="m4.93 4.93 4.24 4.24" /><path d="m14.83 9.17 4.24-4.24" /><path d="m14.83 14.83 4.24 4.24" /><path d="m9.17 14.83-4.24 4.24" /><circle cx="12" cy="12" r="4" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('mHelp') }}</span>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<IconGitea :size="16" />
<span class="flex-1 text-[12.5px] font-medium">{{ t('mGitea') }}</span>
</div>
<div class="flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-zinc-400">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2v2" /><path d="M14 2v2" /><path d="M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1" /><path d="M6 2v2" /></svg>
<span class="flex-1 text-[12.5px] font-medium">{{ t('coffee') }}</span>
</div>
<!-- bas : thème / réglages / aide -->
<div class="flex h-9 w-9 items-center justify-center rounded-[9px] text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z" /></svg>
</div>
<div class="flex h-9 w-9 items-center justify-center rounded-[9px] text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3" /><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" /></svg>
</div>
</div>
<!-- pied : langue · notifications · déconnexion + version (fidèle à AppShellFooter) -->
<div class="mt-2 flex items-center gap-2 border-t border-[#1c1c1f] px-1 pt-2.5">
<span class="rounded border border-zinc-700 px-1.5 py-px font-mono text-[10px] text-zinc-400">{{ locale.toUpperCase() }}</span>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10.268 21a2 2 0 0 0 3.464 0" /><path d="M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326" /></svg>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#71717a" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" /><polyline points="16 17 21 12 16 7" /><line x1="21" x2="9" y1="12" y2="12" /></svg>
<span class="ml-auto font-mono text-[10px] text-zinc-600">v2.0.0</span>
<!-- panneau Projects (fidèle à ProjectTree : arbre projet -> worktree -> session) -->
<div class="flex w-[176px] flex-none flex-col border-r border-border bg-surface-1 py-2">
<div class="label-mono px-3 pb-2">{{ t('mProjects') }}</div>
<div class="flex flex-col gap-px px-1 text-[12px]">
<div class="flex items-center gap-1.5 rounded px-2 py-1 text-fg-muted">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 3h16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z" /><circle cx="12" cy="10" r="2" /><path d="M12 12v4" /></svg>
<span class="truncate">api</span>
</div>
<div class="flex items-center gap-1.5 rounded bg-surface-2 px-2 py-1 pl-5 text-fg">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="truncate font-mono text-accent">feat/auth</span>
</div>
<div class="flex items-center gap-1.5 rounded px-2 py-0.5 pl-9 text-[11px] text-fg-muted">
<span class="h-1.5 w-1.5 flex-none rounded-full" :style="{ background: pill.fg, animation: pill.pulse }"></span>
<span class="truncate font-mono">claude</span>
</div>
<div class="flex items-center gap-1.5 rounded px-2 py-1 text-fg-muted">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 3h16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z" /><circle cx="12" cy="10" r="2" /><path d="M12 12v4" /></svg>
<span class="truncate">web</span>
</div>
<div class="flex items-center gap-1.5 rounded px-2 py-1 text-fg-muted">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 3h16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2Z" /><circle cx="12" cy="10" r="2" /><path d="M12 12v4" /></svg>
<span class="truncate">docs</span>
</div>
</div>
</div>
<!-- main -->
<div class="flex min-w-0 flex-1 flex-col gap-[11px] p-[13px]">
<div class="flex min-w-0 flex-1 flex-col gap-[11px] bg-surface-0 p-[13px]">
<!-- terminal pane -->
<div
class="flex min-h-0 flex-1 flex-col overflow-hidden rounded-[10px] border border-zinc-800 bg-zinc-950"
>
<div class="flex items-center justify-between border-b border-[#1c1c1f] px-[11px] py-2">
<span class="font-mono text-[11.5px] text-zinc-300">api · feat/auth</span>
<div class="flex min-h-0 flex-1 flex-col overflow-hidden rounded-[10px] border border-border bg-surface-0">
<div class="flex items-center justify-between border-b border-border-soft px-[11px] py-2">
<span class="font-mono text-[11.5px] text-fg-muted">api · feat/auth</span>
<span
class="inline-flex items-center gap-1.5 rounded px-2 py-[3px] font-mono text-[11px]"
class="inline-flex items-center gap-1.5 rounded-full px-2 py-[3px] font-mono text-[11px]"
:style="{ background: pill.bg, color: pill.fg }"
>
<span
class="h-1.5 w-1.5 flex-none rounded-full"
:style="{ background: pill.dot, animation: pill.pulse }"
></span>
<span class="h-1.5 w-1.5 flex-none rounded-full" :style="{ background: pill.fg, animation: pill.pulse }"></span>
{{ sessText }}
</span>
</div>
<div
class="flex min-h-[150px] flex-1 flex-col justify-end overflow-hidden p-[11px] font-mono text-xs leading-[1.7] text-zinc-300"
>
<div class="flex min-h-[150px] flex-1 flex-col justify-end overflow-hidden p-[11px] font-mono text-xs leading-[1.7] text-fg-muted">
<div v-for="(ln, i) in termLines" :key="i" :style="{ color: ln.color, whiteSpace: 'pre' }">
{{ ln.text }}
</div>
<div v-if="anim.cur">
<span class="text-emerald-400">$</span>
<span class="ml-1 inline-block h-[13px] w-[7px] animate-blink align-middle bg-zinc-200"></span>
<span class="text-accent">$</span>
<span class="ml-1 inline-block h-[13px] w-[7px] animate-blink bg-fg align-middle"></span>
</div>
</div>
</div>
<!-- dialogue de permission (fidèle à DialogPrompt : badge type + question + options + Deny) -->
<div
v-if="anim.dlg"
class="animate-dlg-in rounded-lg border border-amber-900/60 bg-amber-950/30 p-[11px]"
>
<!-- dialogue de permission (fidèle à DialogPrompt) -->
<div v-if="anim.dlg" class="animate-dlg-in rounded-lg border border-warn/40 bg-warn/10 p-[11px]">
<div class="mb-2 flex items-center gap-2">
<span class="inline-flex items-center rounded bg-amber-900 px-1.5 py-0.5 text-[11px] font-medium text-amber-200">{{ t('mPermission') }}</span>
<span class="text-[12.5px] text-amber-100">{{ t('dlgQ') }}</span>
<span class="inline-flex items-center rounded-full bg-warn/15 px-1.5 py-0.5 font-mono text-[11px] text-warn">{{ t('mPermission') }}</span>
<span class="text-[12.5px] text-fg">{{ t('dlgQ') }}</span>
</div>
<div class="flex flex-wrap gap-[6px]">
<span
@@ -186,15 +169,15 @@ const dlgOptions = computed(() =>
:key="i"
class="inline-flex items-center gap-1.5 rounded-lg border px-2.5 py-1.5 text-xs font-medium transition-colors"
:class="op.answered
? 'border-emerald-500/70 bg-emerald-950/50 text-emerald-300'
? 'border-accent/70 bg-accent/15 text-accent'
: op.highlighted
? 'border-amber-400 bg-amber-950/50 text-amber-200'
: 'border-zinc-700 bg-zinc-800 text-zinc-200'"
? 'border-warn bg-warn/15 text-warn'
: 'border-border bg-surface-2 text-fg'"
>
<span class="font-mono" :class="op.answered ? 'text-emerald-400' : 'text-amber-400'">{{ op.num }}</span>
<span class="font-mono" :class="op.answered ? 'text-accent' : 'text-warn'">{{ op.num }}</span>
{{ op.text }}
</span>
<span class="inline-flex items-center rounded-lg border border-red-900 bg-red-950 px-2.5 py-1.5 text-xs font-medium text-red-300">{{ t('mDeny') }}</span>
<span class="inline-flex items-center rounded-lg border border-danger/40 bg-danger/10 px-2.5 py-1.5 text-xs font-medium text-danger">{{ t('mDeny') }}</span>
</div>
</div>
</div>
@@ -204,18 +187,18 @@ const dlgOptions = computed(() =>
<!-- toast push -->
<div
v-if="anim.toast"
class="animate-toast-in absolute bottom-[14px] right-[14px] flex w-[248px] items-start gap-2.5 rounded-[11px] border border-[rgba(120,53,15,0.5)] bg-[#0c0c0e] p-3 shadow-toast"
class="animate-toast-in absolute right-[14px] bottom-[14px] flex w-[248px] items-start gap-2.5 rounded-[11px] border border-border bg-surface-1 p-3 shadow-toast"
>
<span class="inline-flex h-[30px] w-[30px] flex-none items-center justify-center rounded-lg bg-emerald-500/15">
<span class="inline-flex h-[30px] w-[30px] flex-none items-center justify-center rounded-lg bg-accent/15">
<img src="/assets/arboretum-mark.png" alt="" width="18" height="18" class="h-[18px] w-[18px] object-contain" />
</span>
<div class="min-w-0 flex-1">
<div class="flex items-center justify-between">
<span class="font-mono text-[11px] text-emerald-400">Arboretum</span>
<span class="text-[10px] text-zinc-600">now</span>
<span class="font-mono text-[11px] text-accent">Arboretum</span>
<span class="text-[10px] text-fg-subtle">now</span>
</div>
<div class="mt-[3px] text-[13px] font-semibold text-zinc-100">{{ t('toastTitle') }}</div>
<div class="mt-px text-[11.5px] leading-[1.4] text-zinc-400">{{ t('toastBody') }}</div>
<div class="mt-[3px] text-[13px] font-semibold text-fg">{{ t('toastTitle') }}</div>
<div class="mt-px text-[11.5px] leading-[1.4] text-fg-muted">{{ t('toastBody') }}</div>
</div>
</div>
</div>
+8 -8
View File
@@ -21,27 +21,27 @@ const { t } = useI18n();
class="block h-[46px] w-[46px] object-contain"
/>
<span
class="inline-flex items-center gap-2 rounded-full border border-emerald-500/30 bg-emerald-500/[0.07] px-[11px] py-[5px] font-mono text-[11.5px] uppercase tracking-[0.1em] text-emerald-400"
class="inline-flex items-center gap-2 rounded-full border border-accent/30 bg-accent/[0.07] px-[11px] py-[5px] font-mono text-[11.5px] uppercase tracking-[0.1em] text-accent"
>
<span class="h-1.5 w-1.5 rounded-full bg-emerald-400 shadow-[0_0_8px_#34d399]"></span>
<span class="h-1.5 w-1.5 rounded-full bg-accent shadow-[0_0_8px_var(--color-accent)]"></span>
{{ t('heroBadge') }}
</span>
</div>
<h1 class="m-0 text-[clamp(40px,5.6vw,64px)] font-bold leading-[1.04] tracking-[-0.035em] text-zinc-50">
<h1 class="m-0 text-[clamp(40px,5.6vw,64px)] font-bold leading-[1.04] tracking-[-0.035em] text-fg">
{{ t('heroTitle') }}
</h1>
<p class="mt-[22px] max-w-[520px] text-[clamp(17px,1.7vw,20px)] leading-[1.55] text-zinc-400">
<p class="mt-[22px] max-w-[520px] text-[clamp(17px,1.7vw,20px)] leading-[1.55] text-fg-muted">
{{ t('heroSub') }}
</p>
<div
class="mt-[30px] flex max-w-[480px] items-stretch overflow-hidden rounded-[10px] border border-zinc-800 bg-zinc-950/60"
class="mt-[30px] flex max-w-[480px] items-stretch overflow-hidden rounded-[10px] border border-border bg-surface-0/60"
>
<div
class="flex min-w-0 flex-1 items-center gap-2.5 overflow-x-auto whitespace-nowrap px-[15px] font-mono text-sm"
>
<span class="text-emerald-400">$</span><span class="text-zinc-200">{{ INSTALL_COMMAND }}</span>
<span class="text-accent">$</span><span class="text-fg">{{ INSTALL_COMMAND }}</span>
</div>
<CopyButton variant="bar" :text="INSTALL_COMMAND" :label="t('copyCommand')" />
</div>
@@ -49,7 +49,7 @@ const { t } = useI18n();
<div class="mt-6 flex flex-wrap gap-[13px]">
<a
href="#how"
class="inline-flex items-center gap-[9px] rounded-[9px] bg-emerald-600 px-6 py-[13px] text-[15.5px] font-semibold text-white no-underline transition-[background,transform] duration-150 ease-in-out hover:-translate-y-px hover:bg-emerald-500 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70"
class="inline-flex items-center gap-[9px] rounded-[9px] bg-accent-solid px-6 py-[13px] text-[15.5px] font-semibold text-white no-underline transition-[background,transform] duration-150 ease-in-out hover:-translate-y-px hover:bg-accent-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent/70"
>
{{ t('getStarted') }}
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="m12 5 7 7-7 7" /></svg>
@@ -58,7 +58,7 @@ const { t } = useI18n();
:href="REPO"
target="_blank"
rel="noopener"
class="inline-flex items-center gap-[9px] rounded-[9px] border border-zinc-800 px-[22px] py-[13px] text-[15.5px] font-medium text-zinc-100 no-underline transition-colors hover:border-emerald-500/45 hover:text-emerald-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500/70"
class="inline-flex items-center gap-[9px] rounded-[9px] border border-border px-[22px] py-[13px] text-[15.5px] font-medium text-fg no-underline transition-colors hover:border-accent/45 hover:text-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent/70"
>
<IconGitea :size="17" />
{{ t('gitea') }}
@@ -11,41 +11,41 @@ const LOCAL_URL = 'http://localhost:7317';
<template>
<section id="how" class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 pb-[100px]">
<div v-reveal class="mb-[46px] text-center">
<div class="mb-3.5 font-mono text-xs uppercase tracking-[0.14em] text-emerald-400">{{ t('howKicker') }}</div>
<h2 class="m-0 text-[clamp(28px,3.4vw,40px)] font-semibold tracking-[-0.025em] text-zinc-50">{{ t('howTitle') }}</h2>
<div class="mb-3.5 font-mono text-xs uppercase tracking-[0.14em] text-accent">{{ t('howKicker') }}</div>
<h2 class="m-0 text-[clamp(28px,3.4vw,40px)] font-semibold tracking-[-0.025em] text-fg">{{ t('howTitle') }}</h2>
</div>
<div v-reveal class="grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-4">
<div class="rounded-xl border border-zinc-800 bg-zinc-900/50 p-[26px]">
<div class="mb-[18px] font-mono text-[13px] text-emerald-400">01</div>
<h3 class="m-0 mb-2.5 text-lg font-semibold text-zinc-50">{{ t('step1Title') }}</h3>
<p class="m-0 mb-4 text-[14.5px] leading-[1.55] text-zinc-400">{{ t('step1Desc') }}</p>
<div class="flex items-center gap-2 rounded-lg border border-zinc-800 bg-zinc-950 p-[11px]">
<code class="min-w-0 flex-1 overflow-x-auto whitespace-nowrap font-mono text-[12.5px] text-zinc-200">
<span class="text-emerald-400">$ </span>{{ INSTALL_COMMAND }}
<div class="rounded-xl border border-border bg-surface-1/50 p-[26px]">
<div class="mb-[18px] font-mono text-[13px] text-accent">01</div>
<h3 class="m-0 mb-2.5 text-lg font-semibold text-fg">{{ t('step1Title') }}</h3>
<p class="m-0 mb-4 text-[14.5px] leading-[1.55] text-fg-muted">{{ t('step1Desc') }}</p>
<div class="flex items-center gap-2 rounded-lg border border-border bg-surface-0 p-[11px]">
<code class="min-w-0 flex-1 overflow-x-auto whitespace-nowrap font-mono text-[12.5px] text-fg">
<span class="text-accent">$ </span>{{ INSTALL_COMMAND }}
</code>
<CopyButton variant="icon" :text="INSTALL_COMMAND" :label="t('copyCommand')" />
</div>
</div>
<div class="rounded-xl border border-zinc-800 bg-zinc-900/50 p-[26px]">
<div class="mb-[18px] font-mono text-[13px] text-emerald-400">02</div>
<h3 class="m-0 mb-2.5 text-lg font-semibold text-zinc-50">{{ t('step2Title') }}</h3>
<p class="m-0 mb-4 text-[14.5px] leading-[1.55] text-zinc-400">{{ t('step2Desc') }}</p>
<div class="flex items-center gap-2 rounded-lg border border-zinc-800 bg-zinc-950 p-[11px]">
<code class="min-w-0 flex-1 overflow-x-auto whitespace-nowrap font-mono text-[12.5px] text-sky-300">
<div class="rounded-xl border border-border bg-surface-1/50 p-[26px]">
<div class="mb-[18px] font-mono text-[13px] text-accent">02</div>
<h3 class="m-0 mb-2.5 text-lg font-semibold text-fg">{{ t('step2Title') }}</h3>
<p class="m-0 mb-4 text-[14.5px] leading-[1.55] text-fg-muted">{{ t('step2Desc') }}</p>
<div class="flex items-center gap-2 rounded-lg border border-border bg-surface-0 p-[11px]">
<code class="min-w-0 flex-1 overflow-x-auto whitespace-nowrap font-mono text-[12.5px] text-info">
→ {{ LOCAL_URL }}
</code>
<CopyButton variant="icon" :text="LOCAL_URL" :label="t('copyUrl')" />
</div>
</div>
<div class="rounded-xl border border-zinc-800 bg-zinc-900/50 p-[26px]">
<div class="mb-[18px] font-mono text-[13px] text-emerald-400">03</div>
<h3 class="m-0 mb-2.5 text-lg font-semibold text-zinc-50">{{ t('step3Title') }}</h3>
<p class="m-0 mb-4 text-[14.5px] leading-[1.55] text-zinc-400">{{ t('step3Desc') }}</p>
<div class="rounded-xl border border-border bg-surface-1/50 p-[26px]">
<div class="mb-[18px] font-mono text-[13px] text-accent">03</div>
<h3 class="m-0 mb-2.5 text-lg font-semibold text-fg">{{ t('step3Title') }}</h3>
<p class="m-0 mb-4 text-[14.5px] leading-[1.55] text-fg-muted">{{ t('step3Desc') }}</p>
<div class="flex flex-wrap gap-1.5">
<span class="rounded-md bg-emerald-500/10 px-[9px] py-1 font-mono text-[11px] text-emerald-400">{{ t('idle') }}</span>
<span class="rounded-md bg-[rgba(8,47,73,0.7)] px-[9px] py-1 font-mono text-[11px] text-sky-300">{{ t('busy') }}</span>
<span class="rounded-md bg-[rgba(69,26,3,0.6)] px-[9px] py-1 font-mono text-[11px] text-amber-300">{{ t('waiting') }}</span>
<span class="rounded-md bg-accent/10 px-[9px] py-1 font-mono text-[11px] text-accent">{{ t('idle') }}</span>
<span class="rounded-md bg-info/15 px-[9px] py-1 font-mono text-[11px] text-info">{{ t('busy') }}</span>
<span class="rounded-md bg-warn/15 px-[9px] py-1 font-mono text-[11px] text-warn">{{ t('waiting') }}</span>
</div>
</div>
</div>
+5 -5
View File
@@ -13,13 +13,13 @@ function set(l: AppLocale): void {
<div
role="group"
aria-label="Language"
class="flex items-center overflow-hidden rounded-lg border border-zinc-800 bg-zinc-950/40"
class="flex items-center overflow-hidden rounded-lg border border-border bg-surface-0/40"
>
<button
type="button"
:aria-pressed="locale === 'en'"
class="cursor-pointer border-none px-[11px] py-1.5 font-mono text-xs font-semibold focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-emerald-500/70"
:class="locale === 'en' ? 'bg-zinc-800 text-emerald-400' : 'bg-transparent text-zinc-500'"
class="cursor-pointer border-none px-[11px] py-1.5 font-mono text-xs font-semibold focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent/70"
:class="locale === 'en' ? 'bg-surface-2 text-accent' : 'bg-transparent text-fg-subtle'"
@click="set('en')"
>
EN
@@ -27,8 +27,8 @@ function set(l: AppLocale): void {
<button
type="button"
:aria-pressed="locale === 'fr'"
class="cursor-pointer border-none px-[11px] py-1.5 font-mono text-xs font-semibold focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-emerald-500/70"
:class="locale === 'fr' ? 'bg-zinc-800 text-emerald-400' : 'bg-transparent text-zinc-500'"
class="cursor-pointer border-none px-[11px] py-1.5 font-mono text-xs font-semibold focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-accent/70"
:class="locale === 'fr' ? 'bg-surface-2 text-accent' : 'bg-transparent text-fg-subtle'"
@click="set('fr')"
>
FR
@@ -5,10 +5,10 @@ const { t } = useI18n();
<template>
<section v-reveal class="mx-auto max-w-[920px] px-6 pb-[92px] pt-12 text-center">
<div class="mb-4 font-mono text-xs uppercase tracking-[0.14em] text-emerald-400">{{ t('probKicker') }}</div>
<h2 class="m-0 text-[clamp(28px,3.6vw,42px)] font-semibold leading-[1.18] tracking-[-0.025em] text-zinc-50">
<div class="mb-4 font-mono text-xs uppercase tracking-[0.14em] text-accent">{{ t('probKicker') }}</div>
<h2 class="m-0 text-[clamp(28px,3.6vw,42px)] font-semibold leading-[1.18] tracking-[-0.025em] text-fg">
{{ t('probTitle') }}
</h2>
<p class="mx-auto mt-[22px] max-w-[640px] text-[clamp(17px,1.6vw,19px)] text-zinc-400">{{ t('probBody') }}</p>
<p class="mx-auto mt-[22px] max-w-[640px] text-[clamp(17px,1.6vw,19px)] text-fg-muted">{{ t('probBody') }}</p>
</section>
</template>
@@ -15,12 +15,12 @@ const connections = [
<section id="remotegit" class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 pb-[100px]">
<div v-reveal class="flex flex-wrap items-center gap-12">
<div class="min-w-[280px] flex-[1_1_360px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('rgKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('rgKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('rgTitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('rgBody') }}</p>
<div class="mt-4 inline-flex items-center gap-2 rounded-lg border border-emerald-500/30 bg-emerald-500/[0.08] px-3 py-1.5 text-[13px] font-medium text-emerald-300">
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('rgBody') }}</p>
<div class="mt-4 inline-flex items-center gap-2 rounded-lg border border-accent/30 bg-accent/[0.08] px-3 py-1.5 text-[13px] font-medium text-accent">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></svg>
{{ t('rgEncrypted') }}
</div>
@@ -28,8 +28,8 @@ const connections = [
<div class="flex min-w-[280px] flex-[1_1_440px] flex-col gap-3">
<!-- carte connexions (fidèle à GitConnectionsSection) -->
<div class="flex flex-col gap-2 rounded-xl border border-zinc-800 bg-zinc-900/50 p-3 shadow-card">
<h3 class="flex items-center gap-2 text-sm font-semibold text-zinc-100">
<div class="flex flex-col gap-2 rounded-xl border border-border bg-surface-1/50 p-3 shadow-card">
<h3 class="flex items-center gap-2 text-sm font-semibold text-fg">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 2v6" /><path d="M15 2v6" /><path d="M12 17v5" /><path d="M5 8h14" /><path d="M6 11V8h12v3a6 6 0 0 1-12 0Z" /></svg>
{{ t('rgConnections') }}
</h3>
@@ -38,19 +38,19 @@ const connections = [
<li
v-for="c in connections"
:key="c.label"
class="flex flex-wrap items-center gap-2 rounded-lg border border-zinc-800 bg-zinc-900/40 px-2.5 py-2"
class="flex flex-wrap items-center gap-2 rounded-lg border border-border bg-surface-1/40 px-2.5 py-2"
>
<!-- icône service (Gitea / GitHub / GitLab) -->
<span class="inline-flex h-6 w-6 flex-none items-center justify-center rounded-md bg-zinc-800 text-zinc-300">
<span class="inline-flex h-6 w-6 flex-none items-center justify-center rounded-md bg-surface-2 text-fg-muted">
<svg v-if="c.service === 'github'" width="14" height="14" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 1.3a10.7 10.7 0 0 0-3.38 20.86c.53.1.73-.23.73-.51l-.01-1.79c-2.98.65-3.61-1.44-3.61-1.44-.49-1.24-1.19-1.57-1.19-1.57-.97-.66.07-.65.07-.65 1.08.08 1.64 1.11 1.64 1.11.96 1.64 2.51 1.16 3.12.89.1-.69.37-1.16.68-1.43-2.38-.27-4.88-1.19-4.88-5.3 0-1.17.42-2.13 1.1-2.88-.11-.27-.48-1.36.1-2.84 0 0 .9-.29 2.96 1.1a10.3 10.3 0 0 1 5.38 0c2.05-1.39 2.95-1.1 2.95-1.1.59 1.48.22 2.57.11 2.84.69.75 1.1 1.71 1.1 2.88 0 4.12-2.51 5.02-4.9 5.29.39.33.73.98.73 1.97l-.01 2.92c0 .29.2.62.74.51A10.7 10.7 0 0 0 12 1.3" /></svg>
<svg v-else-if="c.service === 'gitlab'" width="15" height="15" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="m12 21.42 3.68-11.33H8.32L12 21.42Z" /><path d="M12 21.42 8.32 10.09H3.16L12 21.42Z" /><path d="M3.16 10.09 2.04 13.53a.76.76 0 0 0 .28.85L12 21.42 3.16 10.09Z" /><path d="M3.16 10.09h5.16L6.1 3.26a.38.38 0 0 0-.72 0l-2.22 6.83Z" /><path d="M12 21.42l3.68-11.33h5.16L12 21.42Z" /><path d="m20.84 10.09 1.12 3.44a.76.76 0 0 1-.28.85L12 21.42l8.84-11.33Z" /><path d="M20.84 10.09h-5.16l2.22-6.83a.38.38 0 0 1 .72 0l2.22 6.83Z" /></svg>
<svg v-else width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 10h12v4a4 4 0 0 1-4 4H8a4 4 0 0 1-4-4z" /><path d="M16 11h2.5a2.5 2.5 0 0 1 0 5H16" /><path d="M7 3c-.5.8.5 1.6 0 2.5" /><path d="M11 3c-.5.8.5 1.6 0 2.5" /></svg>
</span>
<span class="inline-flex items-center rounded bg-sky-950 px-1.5 py-0.5 text-[11px] font-medium text-sky-300">{{ c.service }}</span>
<span class="font-medium text-zinc-200">{{ c.label }}</span>
<span class="text-xs text-zinc-500">{{ c.username }}</span>
<span class="font-mono text-xs text-zinc-600">••••{{ c.last4 }}</span>
<span class="ml-auto inline-flex items-center gap-1 rounded bg-emerald-950 px-1.5 py-0.5 text-[11px] font-medium text-emerald-400">
<span class="inline-flex items-center rounded bg-info/15 px-1.5 py-0.5 text-[11px] font-medium text-info">{{ c.service }}</span>
<span class="font-medium text-fg">{{ c.label }}</span>
<span class="text-xs text-fg-subtle">{{ c.username }}</span>
<span class="font-mono text-xs text-fg-subtle">••••{{ c.last4 }}</span>
<span class="ml-auto inline-flex items-center gap-1 rounded bg-accent/15 px-1.5 py-0.5 text-[11px] font-medium text-accent">
<svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>
{{ t('rgTested') }}
</span>
@@ -58,7 +58,7 @@ const connections = [
</ul>
<div>
<span class="inline-flex items-center gap-1.5 rounded-lg border border-zinc-700 bg-zinc-800 px-2.5 py-1.5 text-xs font-medium text-zinc-200">
<span class="inline-flex items-center gap-1.5 rounded-lg border border-border-strong bg-surface-2 px-2.5 py-1.5 text-xs font-medium text-fg">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>
{{ t('rgAddConnection') }}
</span>
@@ -66,16 +66,16 @@ const connections = [
</div>
<!-- progression de clone (fidèle à CloneRepoModal) -->
<div class="flex flex-col gap-2 rounded-xl border border-zinc-800 bg-zinc-900/50 p-3 shadow-card">
<div class="flex flex-col gap-2 rounded-xl border border-border bg-surface-1/50 p-3 shadow-card">
<div class="flex items-center gap-2">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line x1="12" x2="12" y1="15" y2="3" /></svg>
<span class="font-mono text-[13px] text-zinc-200">github.com/jleroy/api</span>
<span class="ml-auto font-mono text-xs text-zinc-500">62%</span>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><polyline points="7 10 12 15 17 10" /><line x1="12" x2="12" y1="15" y2="3" /></svg>
<span class="font-mono text-[13px] text-fg">github.com/jleroy/api</span>
<span class="ml-auto font-mono text-xs text-fg-subtle">62%</span>
</div>
<div class="h-2 w-full overflow-hidden rounded bg-zinc-800">
<div class="h-full rounded bg-emerald-500" style="width: 62%"></div>
<div class="h-2 w-full overflow-hidden rounded bg-surface-2">
<div class="h-full rounded bg-accent" style="width: 62%"></div>
</div>
<span class="font-mono text-xs text-zinc-500">{{ t('rgCloneReceiving') }}… 62%</span>
<span class="font-mono text-xs text-fg-subtle">{{ t('rgCloneReceiving') }}… 62%</span>
</div>
</div>
</div>
@@ -7,44 +7,44 @@ const { t } = useI18n();
<section id="security" class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 pb-[100px]">
<div
v-reveal
class="rounded-[18px] border border-emerald-500/[0.18] p-[clamp(28px,4vw,48px)]"
style="background: linear-gradient(180deg, rgba(16, 185, 129, 0.05), rgba(16, 185, 129, 0))"
class="rounded-[18px] border border-accent/[0.18] p-[clamp(28px,4vw,48px)]"
style="background: linear-gradient(180deg, color-mix(in srgb, var(--color-accent) 5%, transparent), transparent)"
>
<div class="mb-[30px] flex flex-wrap items-end justify-between gap-3.5">
<div>
<div class="mb-3 font-mono text-xs uppercase tracking-[0.14em] text-emerald-400">{{ t('secKicker') }}</div>
<h2 class="m-0 text-[clamp(26px,3.2vw,38px)] font-semibold leading-[1.12] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.14em] text-accent">{{ t('secKicker') }}</div>
<h2 class="m-0 text-[clamp(26px,3.2vw,38px)] font-semibold leading-[1.12] tracking-[-0.025em] text-fg">
{{ t('secTitle') }}
</h2>
</div>
<p class="m-0 max-w-[380px] text-[15.5px] leading-[1.55] text-zinc-400">{{ t('secIntro') }}</p>
<p class="m-0 max-w-[380px] text-[15.5px] leading-[1.55] text-fg-muted">{{ t('secIntro') }}</p>
</div>
<div class="grid grid-cols-[repeat(auto-fit,minmax(200px,1fr))] gap-3.5">
<div class="flex flex-col gap-2.5 rounded-[11px] border border-zinc-800 bg-[#0c0c0e] p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></svg>
<div class="text-[15px] font-semibold text-zinc-50">{{ t('sec1Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-zinc-400">{{ t('sec1Desc') }}</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-border bg-surface-0 p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /></svg>
<div class="text-[15px] font-semibold text-fg">{{ t('sec1Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-fg-muted">{{ t('sec1Desc') }}</div>
</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-zinc-800 bg-[#0c0c0e] p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4" /><path d="m21 2-9.6 9.6" /><circle cx="7.5" cy="15.5" r="5.5" /></svg>
<div class="text-[15px] font-semibold text-zinc-50">{{ t('sec2Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-zinc-400">{{ t('sec2Desc') }}</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-border bg-surface-0 p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4" /><path d="m21 2-9.6 9.6" /><circle cx="7.5" cy="15.5" r="5.5" /></svg>
<div class="text-[15px] font-semibold text-fg">{{ t('sec2Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-fg-muted">{{ t('sec2Desc') }}</div>
</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-zinc-800 bg-[#0c0c0e] p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" /><path d="m9 12 2 2 4-4" /></svg>
<div class="text-[15px] font-semibold text-zinc-50">{{ t('sec3Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-zinc-400">{{ t('sec3Desc') }}</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-border bg-surface-0 p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z" /><path d="m9 12 2 2 4-4" /></svg>
<div class="text-[15px] font-semibold text-fg">{{ t('sec3Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-fg-muted">{{ t('sec3Desc') }}</div>
</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-zinc-800 bg-[#0c0c0e] p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.55a11 11 0 0 1 14.08 0" /><path d="M1.42 9a16 16 0 0 1 21.16 0" /><path d="M8.53 16.11a6 6 0 0 1 6.95 0" /><path d="M12 20h.01" /></svg>
<div class="text-[15px] font-semibold text-zinc-50">{{ t('sec4Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-zinc-400">{{ t('sec4Desc') }}</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-border bg-surface-0 p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12.55a11 11 0 0 1 14.08 0" /><path d="M1.42 9a16 16 0 0 1 21.16 0" /><path d="M8.53 16.11a6 6 0 0 1 6.95 0" /><path d="M12 20h.01" /></svg>
<div class="text-[15px] font-semibold text-fg">{{ t('sec4Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-fg-muted">{{ t('sec4Desc') }}</div>
</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-zinc-800 bg-[#0c0c0e] p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#34d399" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /><path d="M12 16v-2" /></svg>
<div class="text-[15px] font-semibold text-zinc-50">{{ t('sec5Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-zinc-400">{{ t('sec5Desc') }}</div>
<div class="flex flex-col gap-2.5 rounded-[11px] border border-border bg-surface-0 p-[18px]">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="11" x="3" y="11" rx="2" /><path d="M7 11V7a5 5 0 0 1 10 0v4" /><path d="M12 16v-2" /></svg>
<div class="text-[15px] font-semibold text-fg">{{ t('sec5Title') }}</div>
<div class="text-[13.5px] leading-[1.5] text-fg-muted">{{ t('sec5Desc') }}</div>
</div>
</div>
</div>
+129 -125
View File
@@ -12,246 +12,250 @@ const dlgOpts = computed(() => DLG_OPTS[locale.value as AppLocale]);
<template>
<section id="showcase" class="mx-auto flex max-w-[1200px] scroll-mt-[84px] flex-col gap-[92px] px-6">
<!-- a) dashboard worktree-first : rail « À traiter » + section de repo (fidèle à AttentionSection + RepoSection) -->
<!-- a) supervision : rail « À traiter » + section de repo (AttentionList + worktrees / git) -->
<div v-reveal class="flex flex-wrap items-center gap-12">
<div class="min-w-[280px] flex-[1_1_360px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('scAKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('scAKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('scATitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('scABody') }}</p>
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('scABody') }}</p>
</div>
<div class="flex min-w-[280px] flex-[1_1_440px] flex-col gap-3">
<!-- rail « À traiter » -->
<div class="flex flex-col gap-2 rounded-xl border border-amber-900/50 bg-amber-950/20 p-3 shadow-card">
<div class="flex flex-col gap-2 rounded-xl border border-warn/40 bg-warn/10 p-3 shadow-card">
<div class="flex items-center gap-2">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4" /><path d="M12 17h.01" /></svg>
<h3 class="text-sm font-semibold text-amber-200">{{ t('mAttn') }}</h3>
<span class="rounded-full bg-amber-500/20 px-1.5 text-[11px] font-semibold text-amber-300">1</span>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--color-warn)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4" /><path d="M12 17h.01" /></svg>
<h3 class="text-sm font-semibold text-warn">{{ t('mAttn') }}</h3>
<span class="rounded-full bg-warn/20 px-1.5 text-[11px] font-semibold text-warn">1</span>
</div>
<span class="truncate font-mono text-xs text-amber-300/80">~/code/arboretum/api</span>
<span class="truncate font-mono text-xs text-warn/80">~/code/arboretum/api</span>
<!-- DialogPrompt -->
<div class="rounded-lg border border-amber-900/60 bg-amber-950/30 p-2.5">
<div class="rounded-lg border border-warn/40 bg-warn/10 p-2.5">
<div class="flex items-center gap-2">
<span class="inline-flex items-center rounded bg-amber-900 px-1.5 py-0.5 text-[11px] font-medium text-amber-200">{{ t('mPermission') }}</span>
<span class="text-[12.5px] text-amber-100">{{ t('dlgQ') }}</span>
<span class="inline-flex items-center rounded-full bg-warn/15 px-1.5 py-0.5 font-mono text-[11px] text-warn">{{ t('mPermission') }}</span>
<span class="text-[12.5px] text-fg">{{ t('dlgQ') }}</span>
</div>
<div class="mt-2 flex flex-wrap gap-1.5">
<span
v-for="(op, i) in dlgOpts"
:key="i"
class="inline-flex items-center gap-1.5 rounded-lg border border-zinc-700 bg-zinc-800 px-2.5 py-1.5 text-xs font-medium text-zinc-200"
class="inline-flex items-center gap-1.5 rounded-lg border border-border bg-surface-2 px-2.5 py-1.5 text-xs font-medium text-fg"
>
<span class="font-mono text-amber-400">{{ i + 1 }}</span> {{ op }}
<span class="font-mono text-warn">{{ i + 1 }}</span> {{ op }}
</span>
<span class="inline-flex items-center rounded-lg border border-red-900 bg-red-950 px-2.5 py-1.5 text-xs font-medium text-red-300">{{ t('mDeny') }}</span>
<span class="inline-flex items-center rounded-lg border border-danger/40 bg-danger/10 px-2.5 py-1.5 text-xs font-medium text-danger">{{ t('mDeny') }}</span>
</div>
</div>
</div>
<!-- section de repo : worktrees + état de session -->
<div class="flex flex-col gap-2 rounded-xl border border-zinc-800 bg-zinc-900/50 p-3 shadow-card">
<div class="flex flex-col gap-2 rounded-xl border border-border bg-surface-1/50 p-3 shadow-card">
<header class="flex flex-wrap items-center gap-2">
<h3 class="font-semibold text-zinc-100">arboretum</h3>
<span class="truncate font-mono text-xs text-zinc-500">~/code/arboretum</span>
<span class="ml-auto inline-flex items-center gap-1.5 rounded-lg border border-zinc-700 bg-zinc-800 px-2 py-1 text-xs font-medium text-zinc-200">
<h3 class="font-semibold text-fg">arboretum</h3>
<span class="truncate font-mono text-xs text-fg-subtle">~/code/arboretum</span>
<span class="ml-auto inline-flex items-center gap-1.5 rounded-lg border border-border bg-surface-2 px-2 py-1 text-xs font-medium text-fg">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14" /><path d="M12 5v14" /></svg>
{{ t('mStart') }}
</span>
</header>
<!-- worktree : branche principale, session au repos -->
<div class="rounded border border-zinc-800 bg-zinc-900/40 p-2">
<div class="rounded border border-border bg-surface-1/40 p-2">
<div class="flex items-center gap-2">
<span class="font-mono text-sm text-zinc-200">main</span>
<span class="inline-flex items-center rounded bg-zinc-800 px-1.5 py-0.5 text-[11px] font-medium text-zinc-400">{{ t('mMain') }}</span>
<span class="ml-auto text-xs text-zinc-600">{{ t('mClean') }}</span>
<span class="font-mono text-sm text-fg">main</span>
<span class="inline-flex items-center rounded bg-surface-2 px-1.5 py-0.5 text-[11px] font-medium text-fg-muted">{{ t('mMain') }}</span>
<span class="ml-auto text-xs text-fg-subtle">{{ t('mClean') }}</span>
</div>
<p class="truncate font-mono text-xs text-zinc-500">~/code/arboretum</p>
<p class="truncate font-mono text-xs text-fg-subtle">~/code/arboretum</p>
<div class="mt-1 flex items-center gap-2">
<span class="inline-flex items-center gap-1 rounded bg-zinc-800/60 px-1.5 py-0.5">
<span class="inline-flex items-center gap-1 rounded bg-emerald-950 px-1.5 py-0.5 text-[11px] font-medium text-emerald-400">
<span class="h-1.5 w-1.5 rounded-full bg-emerald-400"></span>{{ t('idle') }}
<span class="inline-flex items-center gap-1 rounded bg-surface-2/60 px-1.5 py-0.5">
<span class="inline-flex items-center gap-1 rounded-full bg-accent/15 px-1.5 py-0.5 text-[11px] font-medium text-accent">
<span class="h-1.5 w-1.5 rounded-full bg-accent"></span>{{ t('idle') }}
</span>
<span class="font-mono text-[11px] text-zinc-400">claude</span>
<span class="font-mono text-[11px] text-fg-muted">claude</span>
</span>
</div>
</div>
<!-- worktree : branche de feature, session occupée -->
<div class="rounded border border-zinc-800 bg-zinc-900/40 p-2">
<div class="rounded border border-border bg-surface-1/40 p-2">
<div class="flex items-center gap-2">
<span class="font-mono text-sm text-zinc-200">feat/auth</span>
<span class="ml-auto flex items-center gap-2 text-xs text-zinc-500">
<span class="font-mono text-sm text-fg">feat/auth</span>
<span class="ml-auto flex items-center gap-2 text-xs text-fg-subtle">
<span>↑2</span>
<span class="text-amber-400">● {{ t('mDirty') }}</span>
<span class="text-warn">● {{ t('mDirty') }}</span>
</span>
</div>
<p class="truncate font-mono text-xs text-zinc-500">~/code/arboretum/.wt/feat-auth</p>
<p class="truncate font-mono text-xs text-fg-subtle">~/code/arboretum/.wt/feat-auth</p>
<div class="mt-1 flex items-center gap-2">
<span class="inline-flex items-center gap-1 rounded bg-zinc-800/60 px-1.5 py-0.5">
<span class="inline-flex items-center gap-1 rounded bg-sky-950 px-1.5 py-0.5 text-[11px] font-medium text-sky-300">
<span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-sky-300"></span>{{ t('busy') }}
<span class="inline-flex items-center gap-1 rounded bg-surface-2/60 px-1.5 py-0.5">
<span class="inline-flex items-center gap-1 rounded-full bg-info/15 px-1.5 py-0.5 text-[11px] font-medium text-info">
<span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-info"></span>{{ t('busy') }}
</span>
<span class="font-mono text-[11px] text-zinc-400">claude</span>
<span class="font-mono text-[11px] text-fg-muted">claude</span>
</span>
</div>
<!-- actions git de la carte : commit / push (fidèle au WorktreeCard) -->
<!-- actions git de la carte : commit / push -->
<div class="mt-1 flex items-center gap-1.5">
<span class="inline-flex items-center rounded border border-zinc-700 bg-zinc-800 px-1.5 py-0.5 text-[11px] font-medium text-zinc-300">{{ t('mCommit') }}</span>
<span class="inline-flex items-center rounded border border-zinc-700 bg-zinc-800 px-1.5 py-0.5 text-[11px] font-medium text-zinc-300">{{ t('mPush') }} ↑2</span>
<span class="inline-flex items-center rounded border border-border bg-surface-2 px-1.5 py-0.5 text-[11px] font-medium text-fg-muted">{{ t('mCommit') }}</span>
<span class="inline-flex items-center rounded border border-border bg-surface-2 px-1.5 py-0.5 text-[11px] font-medium text-fg-muted">{{ t('mPush') }} ↑2</span>
</div>
</div>
</div>
</div>
</div>
<!-- b) grille multi-terminaux (fidèle à TerminalCell : badge d'état + titre repo · branche + commande) -->
<!-- b) grille multi-terminaux (badge d'état + titre repo · branche + commande) -->
<div v-reveal class="flex flex-wrap-reverse items-center gap-12">
<div class="min-w-[280px] flex-[1_1_440px]">
<div class="grid grid-cols-2 gap-2.5 overflow-hidden rounded-xl border border-zinc-800 bg-[#0c0c0e] p-3 shadow-card">
<div class="overflow-hidden rounded-lg border border-zinc-800 bg-[#09090b]">
<div class="flex items-center gap-2 border-b border-zinc-800 px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded bg-sky-950 px-1.5 py-0.5 text-[10px] font-medium text-sky-300"><span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-sky-300"></span>{{ t('busy') }}</span>
<span class="truncate font-mono text-[11px] text-zinc-300">api · feat/auth</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-zinc-500">claude</span>
<div class="grid grid-cols-2 gap-2.5 overflow-hidden rounded-xl border border-border bg-surface-1 p-3 shadow-card">
<div class="overflow-hidden rounded-lg border border-border bg-surface-0">
<div class="flex items-center gap-2 border-b border-border px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded-full bg-info/15 px-1.5 py-0.5 text-[10px] font-medium text-info"><span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-info"></span>{{ t('busy') }}</span>
<span class="truncate font-mono text-[11px] text-fg-muted">api · feat/auth</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-fg-subtle">claude</span>
</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-zinc-300">
<div class="text-emerald-400">● Edit session.ts</div>
<div class="text-emerald-400">+ const token = sign(...)</div>
<div class="text-red-400">- legacy cookie auth</div>
<div class="text-zinc-500">refactoring guards…</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-fg-muted">
<div class="text-accent">● Edit session.ts</div>
<div class="text-accent">+ const token = sign(...)</div>
<div class="text-danger">- legacy cookie auth</div>
<div class="text-fg-subtle">refactoring guards…</div>
</div>
</div>
<div class="overflow-hidden rounded-lg border border-zinc-800 bg-[#09090b]">
<div class="flex items-center gap-2 border-b border-zinc-800 px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded bg-emerald-950 px-1.5 py-0.5 text-[10px] font-medium text-emerald-400"><span class="h-1.5 w-1.5 rounded-full bg-emerald-400"></span>{{ t('idle') }}</span>
<span class="truncate font-mono text-[11px] text-zinc-300">web · fix/cart</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-zinc-500">claude</span>
<div class="overflow-hidden rounded-lg border border-border bg-surface-0">
<div class="flex items-center gap-2 border-b border-border px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded-full bg-accent/15 px-1.5 py-0.5 text-[10px] font-medium text-accent"><span class="h-1.5 w-1.5 rounded-full bg-accent"></span>{{ t('idle') }}</span>
<span class="truncate font-mono text-[11px] text-fg-muted">web · fix/cart</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-fg-subtle">claude</span>
</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-zinc-300">
<div class="text-emerald-400">✓ all tests passing</div>
<div class="text-zinc-500">24 passed, 0 failed</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-fg-muted">
<div class="text-accent">✓ all tests passing</div>
<div class="text-fg-subtle">24 passed, 0 failed</div>
<div>
<span class="text-emerald-400">$</span>
<span class="ml-1 inline-block h-[11px] w-1.5 animate-blink align-middle bg-zinc-200"></span>
<span class="text-accent">$</span>
<span class="ml-1 inline-block h-[11px] w-1.5 animate-blink bg-fg align-middle"></span>
</div>
</div>
</div>
<div class="overflow-hidden rounded-lg border border-zinc-800 bg-[#09090b]">
<div class="flex items-center gap-2 border-b border-zinc-800 px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded bg-sky-950 px-1.5 py-0.5 text-[10px] font-medium text-sky-300"><span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-sky-300"></span>{{ t('busy') }}</span>
<span class="truncate font-mono text-[11px] text-zinc-300">db · refactor</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-zinc-500">claude</span>
<div class="overflow-hidden rounded-lg border border-border bg-surface-0">
<div class="flex items-center gap-2 border-b border-border px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded-full bg-info/15 px-1.5 py-0.5 text-[10px] font-medium text-info"><span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-info"></span>{{ t('busy') }}</span>
<span class="truncate font-mono text-[11px] text-fg-muted">db · refactor</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-fg-subtle">claude</span>
</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-zinc-300">
<div class="text-emerald-400">● Write migration</div>
<div class="text-zinc-500">0003_add_index.sql</div>
<div class="text-zinc-500">applying to schema…</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-fg-muted">
<div class="text-accent">● Write migration</div>
<div class="text-fg-subtle">0003_add_index.sql</div>
<div class="text-fg-subtle">applying to schema…</div>
</div>
</div>
<div class="overflow-hidden rounded-lg border border-zinc-800 bg-[#09090b]">
<div class="flex items-center gap-2 border-b border-zinc-800 px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded bg-amber-950 px-1.5 py-0.5 text-[10px] font-medium text-amber-300"><span class="h-1.5 w-1.5 animate-pulse-amber rounded-full bg-amber-300"></span>{{ t('waiting') }}</span>
<span class="truncate font-mono text-[11px] text-zinc-300">docs · api</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-zinc-500">claude</span>
<div class="overflow-hidden rounded-lg border border-border bg-surface-0">
<div class="flex items-center gap-2 border-b border-border px-2 py-1.5">
<span class="inline-flex items-center gap-1 rounded-full bg-warn/15 px-1.5 py-0.5 text-[10px] font-medium text-warn"><span class="h-1.5 w-1.5 animate-pulse-amber rounded-full bg-warn"></span>{{ t('waiting') }}</span>
<span class="truncate font-mono text-[11px] text-fg-muted">docs · api</span>
<span class="ml-auto shrink-0 font-mono text-[11px] text-fg-subtle">claude</span>
</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-zinc-300">
<div class="text-emerald-400">● Read README.md</div>
<div class="text-amber-300">Permission required</div>
<div class="text-zinc-500">waiting for input…</div>
<div class="p-[11px] font-mono text-[11px] leading-[1.75] text-fg-muted">
<div class="text-accent">● Read README.md</div>
<div class="text-warn">Permission required</div>
<div class="text-fg-subtle">waiting for input…</div>
</div>
</div>
</div>
</div>
<div class="min-w-[280px] flex-[1_1_360px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('scBKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('scBKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('scBTitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('scBBody') }}</p>
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('scBBody') }}</p>
</div>
</div>
<!-- c) mobile : push + réponse au dialogue (fidèle à DialogPrompt) + barre d'onglets -->
<!-- c) mobile : push + réponse au dialogue + barre d'onglets -->
<div v-reveal class="flex flex-wrap items-center gap-12">
<div class="min-w-[280px] flex-[1_1_380px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('scCKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('scCKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,34px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('scCTitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('scCBody') }}</p>
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('scCBody') }}</p>
</div>
<div class="flex min-w-[280px] flex-[1_1_320px] justify-center">
<div class="relative w-[300px] overflow-hidden rounded-[40px] border-[9px] border-zinc-900 bg-zinc-950 shadow-phone">
<div class="relative w-[300px] overflow-hidden rounded-[40px] border-[9px] border-surface-1 bg-surface-0 shadow-phone">
<div class="flex h-[30px] items-center justify-center">
<div class="h-1.5 w-[90px] rounded-full bg-zinc-800"></div>
<div class="h-1.5 w-[90px] rounded-full bg-surface-2"></div>
</div>
<div class="px-3 pb-[64px]">
<!-- toast push -->
<div class="flex items-start gap-[11px] rounded-[15px] border border-[rgba(120,53,15,0.5)] bg-[#0c0c0e] p-[13px] shadow-toast-sm">
<span class="inline-flex h-[30px] w-[30px] flex-none items-center justify-center rounded-lg bg-emerald-500/[0.14]">
<div class="flex items-start gap-[11px] rounded-[15px] border border-border bg-surface-1 p-[13px] shadow-toast-sm">
<span class="inline-flex h-[30px] w-[30px] flex-none items-center justify-center rounded-lg bg-accent/15">
<img src="/assets/arboretum-mark.png" alt="" width="18" height="18" class="h-[18px] w-[18px] object-contain" />
</span>
<div class="min-w-0 flex-1">
<div class="flex items-center justify-between">
<span class="font-mono text-[11px] text-emerald-400">Arboretum</span>
<span class="text-[10px] text-zinc-600">now</span>
<span class="font-mono text-[11px] text-accent">Arboretum</span>
<span class="text-[10px] text-fg-subtle">now</span>
</div>
<div class="mt-[3px] text-[13.5px] font-semibold text-zinc-50">{{ t('toastTitle') }}</div>
<div class="text-xs leading-[1.45] text-zinc-400">{{ t('toastBody') }}</div>
<div class="mt-[3px] text-[13.5px] font-semibold text-fg">{{ t('toastTitle') }}</div>
<div class="text-xs leading-[1.45] text-fg-muted">{{ t('toastBody') }}</div>
</div>
</div>
<!-- carte « À traiter » + DialogPrompt -->
<div class="mt-[14px] flex flex-col gap-2 rounded-[15px] border border-amber-900/50 bg-amber-950/20 p-2.5">
<div class="mt-[14px] flex flex-col gap-2 rounded-[15px] border border-warn/40 bg-warn/10 p-2.5">
<div class="flex items-center gap-2">
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#fbbf24" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4" /><path d="M12 17h.01" /></svg>
<span class="text-[13px] font-semibold text-amber-200">{{ t('mAttn') }}</span>
<span class="rounded-full bg-amber-500/20 px-1.5 text-[11px] font-semibold text-amber-300">1</span>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="var(--color-warn)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /><path d="M12 9v4" /><path d="M12 17h.01" /></svg>
<span class="text-[13px] font-semibold text-warn">{{ t('mAttn') }}</span>
<span class="rounded-full bg-warn/20 px-1.5 text-[11px] font-semibold text-warn">1</span>
</div>
<span class="font-mono text-[11px] text-amber-300/80">api · feat/auth</span>
<div class="rounded-lg border border-amber-900/60 bg-amber-950/30 p-2.5">
<span class="inline-flex items-center rounded bg-amber-900 px-1.5 py-0.5 text-[11px] font-medium text-amber-200">{{ t('mPermission') }}</span>
<div class="mt-1.5 text-[13px] leading-[1.4] text-amber-100">{{ t('dlgQ') }}</div>
<span class="font-mono text-[11px] text-warn/80">api · feat/auth</span>
<div class="rounded-lg border border-warn/40 bg-warn/10 p-2.5">
<span class="inline-flex items-center rounded-full bg-warn/15 px-1.5 py-0.5 font-mono text-[11px] text-warn">{{ t('mPermission') }}</span>
<div class="mt-1.5 text-[13px] leading-[1.4] text-fg">{{ t('dlgQ') }}</div>
<div class="mt-2 flex flex-col gap-1.5">
<span
v-for="(op, i) in dlgOpts"
:key="i"
class="flex items-center gap-2 rounded-lg border border-zinc-700 bg-zinc-800 px-2.5 py-2 text-[13px] font-medium text-zinc-200"
class="flex items-center gap-2 rounded-lg border border-border bg-surface-2 px-2.5 py-2 text-[13px] font-medium text-fg"
>
<span class="font-mono text-amber-400">{{ i + 1 }}</span> {{ op }}
<span class="font-mono text-warn">{{ i + 1 }}</span> {{ op }}
</span>
<span class="rounded-lg border border-red-900 bg-red-950 px-2.5 py-2 text-center text-[13px] font-medium text-red-300">{{ t('mDeny') }}</span>
<span class="rounded-lg border border-danger/40 bg-danger/10 px-2.5 py-2 text-center text-[13px] font-medium text-danger">{{ t('mDeny') }}</span>
</div>
</div>
</div>
</div>
<!-- barre d'onglets mobile (fidèle à MobileTabBar) -->
<div class="absolute inset-x-0 bottom-0 flex border-t border-zinc-800 bg-zinc-950/95 backdrop-blur">
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-zinc-500">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M9 21V9" /></svg>
<span class="text-[10px]">{{ t('mIde') }}</span>
<!-- barre d'onglets mobile (fidèle a IdeShell : explorer / editor / terminal / git / sessions / groups) -->
<div class="absolute inset-x-0 bottom-0 flex border-t border-border bg-surface-0/95 backdrop-blur">
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2" /><path d="M3 9h18" /><path d="M9 21V9" /></svg>
<span class="text-[9px]">{{ t('mExplorer') }}</span>
</div>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-zinc-500">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="text-[10px]">{{ t('mWorktrees') }}</span>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /><path d="M14 2v5h5" /><path d="m10 13-2 2 2 2" /><path d="m14 17 2-2-2-2" /></svg>
<span class="text-[9px]">{{ t('mEditor') }}</span>
</div>
<div class="relative flex flex-1 flex-col items-center gap-0.5 py-2 text-emerald-400">
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 11 2-2-2-2" /><path d="M11 13h4" /><rect width="18" height="18" x="3" y="3" rx="2" /></svg>
<span class="text-[9px]">{{ t('mTerminal') }}</span>
</div>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="18" cy="18" r="3" /><circle cx="6" cy="6" r="3" /><path d="M13 6h3a2 2 0 0 1 2 2v7" /><path d="M11 18H8a2 2 0 0 1-2-2V9" /></svg>
<span class="text-[9px]">{{ t('mGit') }}</span>
</div>
<div class="relative flex flex-1 flex-col items-center gap-0.5 py-2 text-accent">
<span class="relative">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 11 2-2-2-2" /><path d="M11 13h4" /><rect width="18" height="18" x="3" y="3" rx="2" ry="2" /></svg>
<span class="absolute -right-1.5 -top-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-amber-500 px-1 text-[9px] font-semibold text-amber-950">1</span>
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 12h-4l-3 9L9 3l-3 9H2" /></svg>
<span class="absolute -top-1.5 -right-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full bg-warn px-1 text-[9px] font-semibold text-zinc-950">1</span>
</span>
<span class="text-[10px]">{{ t('mSessions') }}</span>
<span class="text-[9px]">{{ t('mSessions') }}</span>
</div>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-zinc-500">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /><path d="M7 16.5 12 13.5" /><path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /><path d="m17 16.5 4.74-2.85" /><path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0z" /></svg>
<span class="text-[10px]">{{ t('mGroups') }}</span>
</div>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-zinc-500">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="4" x2="20" y1="12" y2="12" /><line x1="4" x2="20" y1="6" y2="6" /><line x1="4" x2="20" y1="18" y2="18" /></svg>
<span class="text-[10px]">{{ t('mMore') }}</span>
<div class="flex flex-1 flex-col items-center gap-0.5 py-2 text-fg-subtle">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /><path d="M7 16.5 12 13.5" /><path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /><path d="m17 16.5 4.74-2.85" /><path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0z" /></svg>
<span class="text-[9px]">{{ t('mGroups') }}</span>
</div>
</div>
</div>
@@ -0,0 +1,64 @@
<script setup lang="ts">
// Bascule de thème du site (dark -> light -> system), alignée sur l'app.
import { useI18n } from 'vue-i18n';
import { themeMode, cycleTheme } from '../lib/theme';
const { t } = useI18n();
</script>
<template>
<button
type="button"
class="inline-flex h-9 w-9 items-center justify-center rounded-lg border border-border text-fg-muted transition-colors hover:border-accent hover:text-accent"
:title="t('themeToggle')"
:aria-label="t('themeToggle')"
@click="cycleTheme()"
>
<!-- soleil (clair) -->
<svg
v-if="themeMode === 'light'"
viewBox="0 0 24 24"
width="17"
height="17"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="4" />
<path
d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"
/>
</svg>
<!-- écran (système) -->
<svg
v-else-if="themeMode === 'system'"
viewBox="0 0 24 24"
width="17"
height="17"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect x="2" y="3" width="20" height="14" rx="2" />
<path d="M8 21h8M12 17v4" />
</svg>
<!-- lune (sombre) -->
<svg
v-else
viewBox="0 0 24 24"
width="17"
height="17"
fill="none"
stroke="currentColor"
stroke-width="1.8"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79Z" />
</svg>
</button>
</template>
@@ -7,45 +7,45 @@ const { t } = useI18n();
<section class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 py-[92px]">
<div
v-reveal
class="flex flex-wrap items-center gap-12 rounded-[18px] border border-zinc-800 p-[clamp(28px,4vw,52px)]"
style="background: linear-gradient(180deg, rgba(24, 24, 27, 0.55), rgba(12, 12, 14, 0.55))"
class="flex flex-wrap items-center gap-12 rounded-[18px] border border-border p-[clamp(28px,4vw,52px)]"
style="background: linear-gradient(180deg, color-mix(in srgb, var(--color-surface-1) 55%, transparent), color-mix(in srgb, var(--color-surface-0) 55%, transparent))"
>
<div class="min-w-[280px] flex-[1_1_360px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('grpKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,36px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('grpKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,36px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('grpTitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('grpBody') }}</p>
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('grpBody') }}</p>
</div>
<div class="flex min-w-[280px] flex-[1_1_360px] justify-center">
<div class="flex w-full max-w-[380px] items-center">
<div class="flex flex-none flex-col items-center gap-2">
<div
class="inline-flex h-[62px] w-[62px] items-center justify-center rounded-[15px] border border-emerald-500/35 bg-emerald-500/[0.12] text-emerald-400"
class="inline-flex h-[62px] w-[62px] items-center justify-center rounded-[15px] border border-accent/35 bg-accent/[0.12] text-accent"
>
<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z" /><path d="M7 16.5 12 13.5" /><path d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z" /><path d="m17 16.5 4.74-2.85" /><path d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0z" /></svg>
</div>
<span class="font-mono text-[11px] text-zinc-300">{{ t('grpHub') }}</span>
<span class="font-mono text-[11px] text-fg-muted">{{ t('grpHub') }}</span>
</div>
<div class="relative h-[96px] flex-1">
<svg width="100%" height="100%" viewBox="0 0 100 96" preserveAspectRatio="none" class="absolute inset-0" aria-hidden="true">
<path d="M0 48 H40 V14 H100" fill="none" stroke="rgba(16,185,129,.45)" stroke-width="1.4" />
<path d="M0 48 H40 V48 H100" fill="none" stroke="rgba(16,185,129,.45)" stroke-width="1.4" />
<path d="M0 48 H40 V82 H100" fill="none" stroke="rgba(16,185,129,.45)" stroke-width="1.4" />
<path d="M0 48 H40 V14 H100" fill="none" stroke="var(--color-accent)" stroke-width="1.4" />
<path d="M0 48 H40 V48 H100" fill="none" stroke="var(--color-accent)" stroke-width="1.4" />
<path d="M0 48 H40 V82 H100" fill="none" stroke="var(--color-accent)" stroke-width="1.4" />
</svg>
</div>
<div class="flex flex-none flex-col gap-2.5">
<div class="flex items-center gap-2 rounded-lg border border-zinc-800 bg-[#0c0c0e] px-3 py-2">
<span class="h-1.5 w-1.5 rounded-full bg-sky-300"></span>
<span class="font-mono text-[11px] text-zinc-300">api</span>
<div class="flex items-center gap-2 rounded-lg border border-border bg-surface-0 px-3 py-2">
<span class="h-1.5 w-1.5 rounded-full bg-info"></span>
<span class="font-mono text-[11px] text-fg-muted">api</span>
</div>
<div class="flex items-center gap-2 rounded-lg border border-zinc-800 bg-[#0c0c0e] px-3 py-2">
<span class="h-1.5 w-1.5 rounded-full bg-sky-300"></span>
<span class="font-mono text-[11px] text-zinc-300">web</span>
<div class="flex items-center gap-2 rounded-lg border border-border bg-surface-0 px-3 py-2">
<span class="h-1.5 w-1.5 rounded-full bg-info"></span>
<span class="font-mono text-[11px] text-fg-muted">web</span>
</div>
<div class="flex items-center gap-2 rounded-lg border border-zinc-800 bg-[#0c0c0e] px-3 py-2">
<span class="h-1.5 w-1.5 rounded-full bg-sky-300"></span>
<span class="font-mono text-[11px] text-zinc-300">sdk</span>
<div class="flex items-center gap-2 rounded-lg border border-border bg-surface-0 px-3 py-2">
<span class="h-1.5 w-1.5 rounded-full bg-info"></span>
<span class="font-mono text-[11px] text-fg-muted">sdk</span>
</div>
</div>
</div>
@@ -3,7 +3,7 @@ import { useI18n } from 'vue-i18n';
const { t } = useI18n();
// Lignes du diff (fidele a DiffViewer : add -> emerald-950/40, del -> rose-950/40).
// Lignes du diff (fidèle a DiffViewer : fond teinté add/del, texte neutre).
type DiffLine = { o: string; n: string; type: 'ctx' | 'add' | 'del' | 'hunk'; text: string };
const diffLines: DiffLine[] = [
{ o: '', n: '', type: 'hunk', text: '@@ -12,7 +12,9 @@ export function session(' },
@@ -16,9 +16,9 @@ const diffLines: DiffLine[] = [
];
function rowClass(type: DiffLine['type']): string {
if (type === 'add') return 'bg-emerald-950/40 text-emerald-200';
if (type === 'del') return 'bg-rose-950/40 text-rose-200';
return 'text-zinc-300';
if (type === 'add') return 'diff-add';
if (type === 'del') return 'diff-del';
return 'diff-ctx';
}
function marker(type: DiffLine['type']): string {
return type === 'add' ? '+' : type === 'del' ? '-' : ' ';
@@ -28,30 +28,31 @@ function marker(type: DiffLine['type']): string {
<template>
<section id="workspace" class="mx-auto max-w-[1200px] scroll-mt-[84px] px-6 pb-[100px]">
<div v-reveal class="mb-[40px] max-w-[760px]">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-emerald-400">{{ t('wsKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,38px)] font-semibold leading-[1.15] tracking-[-0.025em] text-zinc-50">
<div class="mb-3 font-mono text-xs uppercase tracking-[0.12em] text-accent">{{ t('wsKicker') }}</div>
<h2 class="m-0 mb-4 text-[clamp(26px,3vw,38px)] font-semibold leading-[1.15] tracking-[-0.025em] text-fg">
{{ t('wsTitle') }}
</h2>
<p class="m-0 text-[16.5px] leading-[1.6] text-zinc-400">{{ t('wsBody') }}</p>
<p class="m-0 text-[16.5px] leading-[1.6] text-fg-muted">{{ t('wsBody') }}</p>
</div>
<!-- maquette IDE multi-projet : barre d'activite, arbre unifie, onglets d'editeur, dock bas -->
<div v-reveal class="overflow-hidden rounded-[14px] border border-zinc-800 bg-[#09090b] shadow-card">
<div v-reveal class="overflow-hidden rounded-[14px] border border-border bg-surface-0 shadow-card">
<!-- barre superieure -->
<header class="flex items-center gap-3 border-b border-zinc-800 px-3 py-2">
<span class="flex items-center gap-2 text-sm font-medium text-zinc-200">
<header class="flex items-center gap-3 border-b border-border px-3 py-2">
<span class="flex items-center gap-2 text-sm font-medium text-fg">
<img src="/assets/arboretum-mark.png" alt="" width="16" height="16" class="h-4 w-4 object-contain" />
Arboretum
</span>
<span class="ml-auto flex items-center gap-1.5 text-[11px] text-zinc-500">
<span class="h-1.5 w-1.5 rounded-full bg-amber-400"></span>{{ t('waiting') }}
<span class="ml-auto flex items-center gap-1.5 text-[11px] text-fg-subtle">
<span class="h-1.5 w-1.5 rounded-full bg-warn"></span>{{ t('waiting') }}
</span>
</header>
<div class="flex">
<!-- barre d'activite -->
<nav class="flex w-11 flex-none flex-col items-center gap-1 border-r border-zinc-800 bg-zinc-900/50 py-2 text-zinc-500">
<span class="flex h-9 w-9 items-center justify-center rounded-lg bg-zinc-700 text-zinc-100" :title="t('wsFiles')">
<nav class="flex w-11 flex-none flex-col items-center gap-1 border-r border-border bg-surface-1 py-2 text-fg-subtle">
<span class="relative flex h-9 w-9 items-center justify-center rounded-lg bg-surface-2 text-accent" :title="t('wsFiles')">
<span class="absolute top-1/2 left-0 h-5 w-0.5 -translate-y-1/2 rounded-full bg-accent"></span>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-2.5a1 1 0 0 1-.8-.4l-.9-1.2A1 1 0 0 0 14 3h-3a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z" /><path d="M3 5a2 2 0 0 0 2 2h3" /><path d="M3 3v13a2 2 0 0 0 2 2h3" /></svg>
</span>
<span class="flex h-9 w-9 items-center justify-center rounded-lg" :title="t('wsChanges')">
@@ -63,39 +64,39 @@ function marker(type: DiffLine['type']): string {
</nav>
<!-- arbre unifie : plusieurs projets a la fois -->
<aside class="hidden w-[248px] flex-none flex-col border-r border-zinc-800 md:flex">
<div class="px-3 py-2 text-[11px] font-semibold uppercase tracking-wide text-zinc-500">Projects</div>
<aside class="hidden w-[248px] flex-none flex-col border-r border-border md:flex">
<div class="label-mono px-3 py-2">Projects</div>
<div class="px-1 pb-2 font-mono text-xs">
<!-- projet api (ouvert) -->
<div class="flex items-center gap-1 rounded py-0.5 pl-1.5 pr-2 text-zinc-200">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-zinc-500" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
<div class="flex items-center gap-1 rounded py-0.5 pr-2 pl-1.5 text-fg">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-fg-subtle" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
<span class="font-medium">api</span>
</div>
<!-- worktree feat/auth (actif) -->
<div class="flex items-center gap-1 rounded bg-zinc-800/70 py-0.5 pl-[18px] pr-2 text-zinc-100">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-zinc-500" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-zinc-500" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="truncate">feat/auth</span>
<div class="flex items-center gap-1 rounded bg-surface-2 py-0.5 pr-2 pl-[18px] text-fg">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-fg-subtle" aria-hidden="true"><path d="m6 9 6 6 6-6" /></svg>
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="var(--color-accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
<span class="truncate text-accent">feat/auth</span>
</div>
<!-- session claude corrélée -->
<div class="flex items-center gap-1.5 rounded py-0.5 pl-[38px] pr-2 text-zinc-300">
<span class="inline-flex items-center gap-1 rounded bg-sky-950 px-1.5 py-[1px] text-[10px] text-sky-300"><span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-sky-300"></span>{{ t('busy') }}</span>
<div class="flex items-center gap-1.5 rounded py-0.5 pr-2 pl-[38px] text-fg-muted">
<span class="inline-flex items-center gap-1 rounded-full bg-info/15 px-1.5 py-[1px] text-[10px] text-info"><span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-info"></span>{{ t('busy') }}</span>
<span class="truncate">claude</span>
</div>
<!-- fichiers du worktree -->
<div class="flex items-center justify-between gap-1 rounded bg-zinc-800 py-0.5 pl-[30px] pr-2 text-zinc-100">
<span class="truncate">session.ts</span><span class="font-bold text-amber-400">M</span>
<div class="flex items-center justify-between gap-1 rounded bg-surface-2 py-0.5 pr-2 pl-[30px] text-fg">
<span class="truncate">session.ts</span><span class="font-bold text-warn">M</span>
</div>
<div class="flex items-center justify-between gap-1 rounded py-0.5 pl-[30px] pr-2 text-zinc-300">
<span class="truncate">token.ts</span><span class="font-bold text-emerald-400">A</span>
<div class="flex items-center justify-between gap-1 rounded py-0.5 pr-2 pl-[30px] text-fg-muted">
<span class="truncate">token.ts</span><span class="font-bold text-accent">A</span>
</div>
<!-- projet web (replie) -->
<div class="flex items-center gap-1 rounded py-0.5 pl-1.5 pr-2 text-zinc-300">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-zinc-500" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
<div class="flex items-center gap-1 rounded py-0.5 pr-2 pl-1.5 text-fg-muted">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-fg-subtle" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
<span class="font-medium">web</span>
</div>
<div class="flex items-center gap-1 rounded py-0.5 pl-1.5 pr-2 text-zinc-300">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-zinc-500" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
<div class="flex items-center gap-1 rounded py-0.5 pr-2 pl-1.5 text-fg-muted">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="shrink-0 text-fg-subtle" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
<span class="font-medium">docs</span>
</div>
</div>
@@ -104,21 +105,21 @@ function marker(type: DiffLine['type']): string {
<!-- centre : onglets d'editeur + diff + dock terminaux -->
<main class="flex min-w-0 flex-1 flex-col">
<!-- onglets d'editeur (plusieurs fichiers, potentiellement de projets differents) -->
<div class="flex items-stretch overflow-x-auto border-b border-zinc-800 text-xs">
<span class="flex items-center gap-1.5 border-r border-zinc-800 bg-[#09090b] px-3 py-1.5 text-zinc-100">
session.ts <span class="h-1.5 w-1.5 rounded-full bg-amber-400"></span>
<div class="flex items-stretch overflow-x-auto border-b border-border text-xs">
<span class="flex items-center gap-1.5 border-r border-border bg-surface-0 px-3 py-1.5 text-fg">
session.ts <span class="h-1.5 w-1.5 rounded-full bg-warn"></span>
</span>
<span class="flex items-center gap-1.5 border-r border-zinc-800 px-3 py-1.5 text-zinc-400">token.ts</span>
<span class="flex items-center gap-1.5 border-r border-zinc-800 px-3 py-1.5 text-zinc-500">app.vue</span>
<span class="flex items-center gap-1.5 border-r border-border px-3 py-1.5 text-fg-muted">token.ts</span>
<span class="flex items-center gap-1.5 border-r border-border px-3 py-1.5 text-fg-subtle">app.vue</span>
</div>
<!-- barre : bascule Editor/Diff + chemin -->
<div class="flex items-center gap-2 border-b border-zinc-800 px-2 py-1">
<div class="inline-flex rounded-lg border border-zinc-800 bg-zinc-950/40 p-0.5">
<span class="rounded-md px-2.5 py-1 text-xs font-medium text-zinc-400">{{ t('wsEditor') }}</span>
<span class="rounded-md bg-zinc-800 px-2.5 py-1 text-xs font-medium text-zinc-100">{{ t('wsDiff') }}</span>
<div class="flex items-center gap-2 border-b border-border px-2 py-1">
<div class="inline-flex rounded-lg border border-border bg-surface-0/40 p-0.5">
<span class="rounded-[9px] px-2.5 py-1 text-xs font-medium text-fg-muted">{{ t('wsEditor') }}</span>
<span class="rounded-[9px] bg-surface-2 px-2.5 py-1 text-xs font-medium text-fg">{{ t('wsDiff') }}</span>
</div>
<span class="truncate font-mono text-[11px] text-zinc-500">api · src/core/session.ts</span>
<span class="ml-auto inline-flex items-center gap-1.5 rounded-md bg-emerald-500 px-2.5 py-1 text-xs font-semibold text-emerald-950">
<span class="truncate font-mono text-[11px] text-fg-subtle">api · src/core/session.ts</span>
<span class="ml-auto inline-flex items-center gap-1.5 rounded-[9px] bg-accent-solid px-2.5 py-1 text-xs font-semibold text-white">
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg>
{{ t('wsCommitBtn') }}
</span>
@@ -127,46 +128,46 @@ function marker(type: DiffLine['type']): string {
<div class="overflow-x-auto">
<table class="w-full border-collapse font-mono text-xs leading-5">
<tbody>
<tr v-for="(l, i) in diffLines" :key="i" :class="l.type === 'hunk' ? 'bg-zinc-900/60 text-sky-300/80' : rowClass(l.type)">
<td class="w-10 select-none px-2 text-right text-zinc-600">{{ l.o }}</td>
<td class="w-10 select-none px-2 text-right text-zinc-600">{{ l.n }}</td>
<td class="whitespace-pre px-2">{{ l.type === 'hunk' ? l.text : marker(l.type) + l.text }}</td>
<tr v-for="(l, i) in diffLines" :key="i" :class="l.type === 'hunk' ? 'bg-surface-1/60 text-info/80' : rowClass(l.type)">
<td class="w-10 px-2 text-right text-fg-subtle select-none">{{ l.o }}</td>
<td class="w-10 px-2 text-right text-fg-subtle select-none">{{ l.n }}</td>
<td class="px-2 whitespace-pre">{{ l.type === 'hunk' ? l.text : marker(l.type) + l.text }}</td>
</tr>
</tbody>
</table>
</div>
<!-- dock terminaux en bas (onglets par session) -->
<div class="border-t border-zinc-800">
<div class="flex items-stretch border-b border-zinc-800 text-[11px]">
<span class="flex items-center gap-1 px-2 py-1.5 font-semibold uppercase tracking-wide text-zinc-500">
<div class="border-t border-border">
<div class="flex items-stretch border-b border-border text-[11px]">
<span class="label-mono flex items-center gap-1 px-2 py-1.5">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m7 11 2-2-2-2" /><path d="M11 13h4" /><rect width="18" height="18" x="3" y="3" rx="2" /></svg>
{{ t('wsTerminal') }}
</span>
<span class="flex items-center gap-1.5 border-l border-zinc-800 bg-[#09090b] px-2.5 py-1.5 font-mono text-zinc-100">
<span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-sky-300"></span>api · feat/auth
<span class="flex items-center gap-1.5 border-l border-border bg-surface-0 px-2.5 py-1.5 font-mono text-fg">
<span class="h-1.5 w-1.5 animate-pulse-sky rounded-full bg-info"></span>api · feat/auth
</span>
<span class="flex items-center gap-1.5 border-l border-zinc-800 px-2.5 py-1.5 font-mono text-zinc-400">web · main</span>
<span class="flex items-center gap-1.5 border-l border-border px-2.5 py-1.5 font-mono text-fg-muted">web · main</span>
</div>
<div class="min-h-[112px] p-[11px] font-mono text-[11px] leading-[1.7] text-zinc-300">
<div class="text-emerald-400">● Edit session.ts</div>
<div class="text-emerald-400">+ const token = sign(...)</div>
<div class="text-zinc-500">running tests…</div>
<div class="text-emerald-400">✓ 24 passed</div>
<div><span class="text-emerald-400">$</span><span class="ml-1 inline-block h-[11px] w-1.5 animate-blink align-middle bg-zinc-200"></span></div>
<div class="min-h-[112px] p-[11px] font-mono text-[11px] leading-[1.7] text-fg-muted">
<div class="text-accent">● Edit session.ts</div>
<div class="text-accent">+ const token = sign(...)</div>
<div class="text-fg-subtle">running tests…</div>
<div class="text-accent">✓ 24 passed</div>
<div><span class="text-accent">$</span><span class="ml-1 inline-block h-[11px] w-1.5 animate-blink bg-fg align-middle"></span></div>
</div>
</div>
</main>
</div>
<!-- barre de statut -->
<footer class="flex items-center gap-3 border-t border-zinc-800 px-3 py-1 text-[11px] text-zinc-500">
<span class="flex items-center gap-1 font-mono text-zinc-400">
<footer class="flex items-center gap-3 border-t border-border px-3 py-1 text-[11px] text-fg-subtle">
<span class="flex items-center gap-1 font-mono text-fg-muted">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="6" x2="6" y1="3" y2="15" /><circle cx="18" cy="6" r="3" /><circle cx="6" cy="18" r="3" /><path d="M18 9a9 9 0 0 1-9 9" /></svg>
feat/auth
</span>
<span class="text-emerald-400">↑2</span>
<span class="text-amber-400">○3</span>
<span class="text-accent">↑2</span>
<span class="text-warn">○3</span>
<span class="ml-auto">api · {{ t('busy') }}</span>
</footer>
</div>