Complete the six application screens
Adds the day timeline, team list, employee record and leave calendar. The design export shipped data for these but no markup, so their layout is designed here from the data shapes and the established style; only Aperçu and the week grid are ports. The day view carries a per-hour headcount band. Where the week view answers "who works how much", this one answers "who is on the floor at 14:00", and the band makes coverage gaps visible without reading every lane. Two fixes the tests and linter caught: - The poste derivation variables were missing from globals.css. Hues and tiers were ported but not the --post-*-bg/fg/edge that consume them, so every shift chip would have rendered colourless. The palette test now asserts all 36 exist. - ThemeToggle synced state in an effect. The document's data-theme attribute is the real store — it is set by the inline script before React exists — so it now subscribes with useSyncExternalStore instead of keeping a copy that is wrong on first render. Counter tests cover the DST cases in both directions: a 22:00–06:00 shift lasts 7 or 9 hours on the changeover nights, never 8. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cr9dkEHwbDgkWPnyGj1Rjv
This commit is contained in:
12 files changed
+1158
-11
No files matched your search
@@ -0,0 +1,25 @@
|
||||
import { PageBody, PageHeader } from '@/components/shell/PageHeader';
|
||||
import { EmptyState } from '@/components/ui/Card';
|
||||
|
||||
export const metadata = { title: 'Écran à venir · PlanFlow' };
|
||||
|
||||
export default async function BientotPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ ecran?: string }>;
|
||||
}) {
|
||||
const { ecran } = await searchParams;
|
||||
const label = ecran ?? 'Cet écran';
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<PageHeader title={label} subtitle="Nantes Atlantis" />
|
||||
<div className="rounded-3 border border-dashed border-line-2 bg-surface">
|
||||
<EmptyState
|
||||
title="Écran à venir"
|
||||
description={`« ${label} » fait partie du périmètre de PlanFlow mais n'est pas encore construit. L'entrée reste dans la navigation pour que celle-ci reflète le produit visé plutôt que son état d'avancement.`}
|
||||
/>
|
||||
</div>
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import { PageBody, PageHeader } from '@/components/shell/PageHeader';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Card, CardHeader } from '@/components/ui/Card';
|
||||
import { cx } from '@/lib/cx';
|
||||
import {
|
||||
CALENDAR_ABSENCES,
|
||||
MONTH_LABEL,
|
||||
MONTH_LENGTH,
|
||||
MONTH_OFFSET,
|
||||
PENDING_REQUESTS,
|
||||
} from '@/lib/demo/conges';
|
||||
|
||||
export const metadata = { title: 'Calendrier des absences · PlanFlow' };
|
||||
|
||||
const WEEKDAYS = [
|
||||
'Lundi',
|
||||
'Mardi',
|
||||
'Mercredi',
|
||||
'Jeudi',
|
||||
'Vendredi',
|
||||
'Samedi',
|
||||
'Dimanche',
|
||||
];
|
||||
|
||||
const KIND_STYLES: Record<string, string> = {
|
||||
cp: 'bg-info-soft text-info-soft-ink border-info',
|
||||
rtt: 'bg-accent-soft text-accent-soft-ink border-accent',
|
||||
maladie: 'bg-surface-3 text-ink-2 border-line-3',
|
||||
'sans-solde': 'bg-surface-2 text-ink-2 border-line-3',
|
||||
attente: 'bg-warn-soft text-warn-soft-ink border-warn',
|
||||
};
|
||||
|
||||
export default function CongesPage() {
|
||||
const cells = Array.from({ length: 42 }, (_, index) => {
|
||||
const dayNumber = index - MONTH_OFFSET + 1;
|
||||
const inMonth = dayNumber >= 1 && dayNumber <= MONTH_LENGTH;
|
||||
const items = inMonth
|
||||
? CALENDAR_ABSENCES.filter(
|
||||
(absence) => dayNumber >= absence.from && dayNumber <= absence.to,
|
||||
)
|
||||
: [];
|
||||
return { index, dayNumber, inMonth, items, weekend: index % 7 > 4 };
|
||||
});
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<PageHeader
|
||||
title="Calendrier des absences"
|
||||
subtitle={`${MONTH_LABEL} · Nantes Atlantis · ${PENDING_REQUESTS.length} demandes en attente`}
|
||||
actions={
|
||||
<>
|
||||
<Button>Exporter</Button>
|
||||
<Button variant="primary">Saisir une absence</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<Card>
|
||||
<div className="grid grid-cols-7 border-b border-line-2 bg-surface-2">
|
||||
{WEEKDAYS.map((day) => (
|
||||
<div
|
||||
key={day}
|
||||
className="border-r border-line-1 px-2 py-2 text-center text-micro font-semibold tracking-[0.06em] text-ink-3 uppercase last:border-r-0"
|
||||
>
|
||||
{day}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="grid grid-cols-7">
|
||||
{cells.map((cell) => (
|
||||
<div
|
||||
key={cell.index}
|
||||
className={cx(
|
||||
'min-h-24 border-r border-b border-line-1 p-1.5 last:border-r-0',
|
||||
!cell.inMonth && 'bg-surface-2',
|
||||
cell.inMonth && cell.weekend && 'bg-surface-2',
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cx(
|
||||
'tnum block text-micro font-semibold',
|
||||
cell.inMonth ? 'text-ink-1' : 'text-ink-3',
|
||||
)}
|
||||
>
|
||||
{cell.inMonth ? cell.dayNumber : ''}
|
||||
</span>
|
||||
<ul className="mt-1 flex flex-col gap-0.5">
|
||||
{cell.items.slice(0, 3).map((absence) => (
|
||||
<li
|
||||
key={`${absence.who}-${absence.type}`}
|
||||
className={cx(
|
||||
'truncate rounded-1 border px-1 py-px text-micro',
|
||||
KIND_STYLES[absence.kind],
|
||||
)}
|
||||
title={`${absence.who} · ${absence.type}`}
|
||||
>
|
||||
{absence.who.split(' ')[0]} · {absence.type}
|
||||
</li>
|
||||
))}
|
||||
{cell.items.length > 3 ? (
|
||||
<li className="px-1 text-micro text-ink-3">
|
||||
+{cell.items.length - 3}
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<span id="attente" />
|
||||
<CardHeader
|
||||
title="Demandes en attente"
|
||||
badge={<Badge tone="warn">{PENDING_REQUESTS.length}</Badge>}
|
||||
/>
|
||||
<ul>
|
||||
{PENDING_REQUESTS.map((request) => (
|
||||
<li
|
||||
key={`${request.who}-${request.range}`}
|
||||
className="flex flex-wrap items-center gap-3 border-b border-line-1 px-4 py-3 last:border-b-0"
|
||||
>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block text-sm font-medium">
|
||||
{request.who} · {request.type}
|
||||
</span>
|
||||
<span className="block text-micro text-ink-3">
|
||||
{request.note}
|
||||
</span>
|
||||
</span>
|
||||
<span className="tnum flex-none text-xs text-ink-2">
|
||||
{request.range}
|
||||
</span>
|
||||
<Badge tone="neutral">{request.days}</Badge>
|
||||
<span className="flex flex-none gap-2">
|
||||
<Button size="sm">Refuser</Button>
|
||||
<Button size="sm" variant="primary">
|
||||
Accepter
|
||||
</Button>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Card>
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
import { PageBody, PageHeader } from '@/components/shell/PageHeader';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Card, CardHeader } from '@/components/ui/Card';
|
||||
import { POSTE_LABELS, posteShort, posteTokens } from '@/lib/design/postes';
|
||||
import { EMPLOYEES, findEmployee } from '@/lib/demo/equipe';
|
||||
import {
|
||||
FICHE_COUNTERS,
|
||||
FICHE_DOCUMENTS,
|
||||
FICHE_SHIFTS,
|
||||
} from '@/lib/demo/fiche';
|
||||
import { fullName, initials } from '@/lib/demo/types';
|
||||
|
||||
export function generateStaticParams() {
|
||||
return EMPLOYEES.map((employee) => ({ id: employee.id }));
|
||||
}
|
||||
|
||||
export default async function FichePage({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
const { id } = await params;
|
||||
const employee = findEmployee(id);
|
||||
if (!employee) notFound();
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<PageHeader
|
||||
title={fullName(employee)}
|
||||
subtitle={`${employee.job} · Nantes Atlantis · entrée le ${employee.since}`}
|
||||
actions={
|
||||
<>
|
||||
<Button>Documents</Button>
|
||||
<Button variant="primary">Modifier le contrat</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-3 rounded-3 border border-line-1 bg-surface p-4">
|
||||
<span
|
||||
aria-hidden
|
||||
className="flex size-11 flex-none items-center justify-center rounded-full bg-surface-3 text-sm font-semibold text-ink-2"
|
||||
>
|
||||
{initials(employee)}
|
||||
</span>
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium">{employee.contract}</p>
|
||||
<p className="text-micro text-ink-3">
|
||||
Poste principal · {POSTE_LABELS[employee.poste]}
|
||||
</p>
|
||||
</div>
|
||||
<span className="flex-1" />
|
||||
{employee.forfaitJours ? (
|
||||
<Badge tone="accent">Forfait jours · 218 j</Badge>
|
||||
) : null}
|
||||
<ul className="flex flex-wrap items-center gap-2">
|
||||
{FICHE_COUNTERS.map((counter) => (
|
||||
<li
|
||||
key={counter.label}
|
||||
className="rounded-2 border border-line-1 bg-surface-2 px-3 py-1.5"
|
||||
>
|
||||
<span className="block text-micro text-ink-3">
|
||||
{counter.label}
|
||||
</span>
|
||||
<span
|
||||
className={`tnum block text-sm font-semibold ${
|
||||
counter.tone === 'warn' ? 'text-warn-soft-ink' : 'text-ink-1'
|
||||
}`}
|
||||
>
|
||||
{counter.value}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 [grid-template-columns:repeat(auto-fit,minmax(400px,1fr))]">
|
||||
<Card>
|
||||
<CardHeader
|
||||
title="Créneaux de la semaine"
|
||||
action={
|
||||
<Button size="sm" variant="ghost">
|
||||
Voir le planning
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
<ul>
|
||||
{FICHE_SHIFTS.map((shift, index) => {
|
||||
const tokens = posteTokens(shift.poste);
|
||||
return (
|
||||
<li
|
||||
key={`${shift.day}-${index}`}
|
||||
className="flex items-center gap-3 border-b border-line-1 px-4 py-2.5 last:border-b-0"
|
||||
>
|
||||
<span className="tnum w-28 flex-none text-xs text-ink-2">
|
||||
{shift.day}
|
||||
</span>
|
||||
<span
|
||||
className="flex-none rounded-2 px-1.5 py-0.5 text-micro font-semibold tracking-wide"
|
||||
style={{
|
||||
background: tokens.bg,
|
||||
color: tokens.fg,
|
||||
border: `1px solid ${tokens.edge}`,
|
||||
}}
|
||||
title={POSTE_LABELS[shift.poste]}
|
||||
>
|
||||
{posteShort(shift.poste)}
|
||||
</span>
|
||||
<span className="tnum flex-1 text-sm">{shift.time}</span>
|
||||
<span className="tnum flex-none text-xs text-ink-2">
|
||||
{shift.worked}
|
||||
</span>
|
||||
<Badge tone={shift.tone}>{shift.state}</Badge>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader title="Documents" />
|
||||
<ul>
|
||||
{FICHE_DOCUMENTS.map((document) => (
|
||||
<li
|
||||
key={document.label}
|
||||
className="flex items-center gap-3 border-b border-line-1 px-4 py-3 last:border-b-0"
|
||||
>
|
||||
<span className="min-w-0 flex-1">
|
||||
<span className="block truncate text-sm font-medium">
|
||||
{document.label}
|
||||
</span>
|
||||
<span className="tnum block text-micro text-ink-3">
|
||||
{document.date}
|
||||
</span>
|
||||
</span>
|
||||
<Badge tone={document.tone}>{document.state}</Badge>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</Card>
|
||||
</div>
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import Link from 'next/link';
|
||||
|
||||
import { PageBody, PageHeader } from '@/components/shell/PageHeader';
|
||||
import { Badge, type Tone } from '@/components/ui/Badge';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { POSTE_LABELS, posteShort, posteTokens } from '@/lib/design/postes';
|
||||
import { EMPLOYEES } from '@/lib/demo/equipe';
|
||||
import { fullName, initials } from '@/lib/demo/types';
|
||||
|
||||
export const metadata = { title: 'Équipe · PlanFlow' };
|
||||
|
||||
const STATUS: Record<string, { label: string; tone: Tone }> = {
|
||||
actif: { label: 'Actif', tone: 'ok' },
|
||||
essai: { label: 'Période d’essai', tone: 'info' },
|
||||
sortie: { label: 'Sortie prévue', tone: 'warn' },
|
||||
};
|
||||
|
||||
export default function EquipePage() {
|
||||
const actifs = EMPLOYEES.filter((e) => e.status !== 'sortie').length;
|
||||
const essai = EMPLOYEES.filter((e) => e.status === 'essai').length;
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<PageHeader
|
||||
title="Équipe"
|
||||
subtitle={`Nantes Atlantis · ${actifs} salariés actifs, ${essai} en période d’essai`}
|
||||
actions={
|
||||
<>
|
||||
<Button>Registre unique du personnel</Button>
|
||||
<Button variant="primary">Nouvelle embauche</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="overflow-x-auto rounded-3 border border-line-1 bg-surface">
|
||||
<table className="w-full min-w-[880px] border-collapse text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-line-2 bg-surface-2 text-left text-micro font-semibold tracking-[0.06em] text-ink-3 uppercase">
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
Collaborateur
|
||||
</th>
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
Poste principal
|
||||
</th>
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
Contrat
|
||||
</th>
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
Entrée
|
||||
</th>
|
||||
<th scope="col" className="px-4 py-2.5">
|
||||
Statut
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{EMPLOYEES.map((employee) => {
|
||||
const tokens = posteTokens(employee.poste);
|
||||
const status = STATUS[employee.status] ?? STATUS.actif!;
|
||||
return (
|
||||
<tr
|
||||
key={employee.id}
|
||||
className="border-b border-line-1 last:border-b-0 hover:bg-surface-2"
|
||||
>
|
||||
<td className="px-4 py-2.5">
|
||||
<Link
|
||||
href={`/equipe/${employee.id}`}
|
||||
className="flex items-center gap-2.5 rounded-2"
|
||||
>
|
||||
<span
|
||||
aria-hidden
|
||||
className="flex size-7 flex-none items-center justify-center rounded-full bg-surface-3 text-micro font-semibold text-ink-2"
|
||||
>
|
||||
{initials(employee)}
|
||||
</span>
|
||||
<span className="min-w-0">
|
||||
<span className="block truncate font-medium">
|
||||
{fullName(employee)}
|
||||
</span>
|
||||
<span className="block truncate text-micro text-ink-3">
|
||||
{employee.job}
|
||||
</span>
|
||||
</span>
|
||||
</Link>
|
||||
</td>
|
||||
<td className="px-4 py-2.5">
|
||||
<span
|
||||
className="inline-flex items-center gap-1.5 rounded-2 px-2 py-0.5 text-micro"
|
||||
style={{
|
||||
background: tokens.bg,
|
||||
color: tokens.fg,
|
||||
border: `1px solid ${tokens.edge}`,
|
||||
}}
|
||||
>
|
||||
<span className="font-semibold tracking-wide">
|
||||
{posteShort(employee.poste)}
|
||||
</span>
|
||||
{POSTE_LABELS[employee.poste]}
|
||||
</span>
|
||||
</td>
|
||||
<td className="tnum px-4 py-2.5 text-ink-2">
|
||||
{employee.contract}
|
||||
</td>
|
||||
<td className="tnum px-4 py-2.5 text-ink-2">
|
||||
{employee.since}
|
||||
</td>
|
||||
<td className="px-4 py-2.5">
|
||||
<Badge tone={status.tone}>{status.label}</Badge>
|
||||
</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { DayTimeline, type DayLane } from '@/components/planning/DayTimeline';
|
||||
import { PageBody, PageHeader } from '@/components/shell/PageHeader';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { UNASSIGNED_ROW, WEEK_ROWS } from '@/lib/demo/semaine';
|
||||
|
||||
export const metadata = { title: 'Planning · mercredi 12 août · PlanFlow' };
|
||||
|
||||
/** Mercredi = index 2 dans la semaine de démonstration. */
|
||||
const DAY_INDEX = 2;
|
||||
|
||||
export default function JourPage() {
|
||||
const lanes: DayLane[] = WEEK_ROWS.map((row) => ({
|
||||
employee: row.employee,
|
||||
shifts: row.days[DAY_INDEX] ?? [],
|
||||
})).filter((lane) => lane.shifts.length > 0);
|
||||
|
||||
const unassigned = UNASSIGNED_ROW.days[DAY_INDEX] ?? [];
|
||||
if (unassigned.length > 0) {
|
||||
lanes.push({
|
||||
employee: UNASSIGNED_ROW.employee,
|
||||
shifts: unassigned,
|
||||
unassigned: true,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<PageBody>
|
||||
<PageHeader
|
||||
title="Planning · mercredi 12 août"
|
||||
subtitle="Nantes Atlantis · amplitude 06:00 – 21:00"
|
||||
actions={
|
||||
<>
|
||||
<Button>Imprimer la journée</Button>
|
||||
<Button variant="primary">Ajouter un créneau</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<Badge tone="accent">{lanes.length} salariés présents</Badge>
|
||||
<Badge tone="warn">Creux de couverture à 13 h</Badge>
|
||||
</div>
|
||||
|
||||
<DayTimeline lanes={lanes} fromHour={6} toHour={21} />
|
||||
</PageBody>
|
||||
);
|
||||
}
|
||||
@@ -142,6 +142,117 @@
|
||||
--post-net-t: 0;
|
||||
--post-for-h: 68;
|
||||
--post-for-t: 0.045;
|
||||
|
||||
/* Dérivation : une seule formule pour les douze postes. Ajouter un poste
|
||||
revient à déclarer sa teinte et son palier, puis ces trois lignes. */
|
||||
--post-cai-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-cai-t)) var(--chip-bg-c)
|
||||
var(--post-cai-h)
|
||||
);
|
||||
--post-cai-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-cai-h));
|
||||
--post-cai-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-cai-t)) var(--chip-edge-c)
|
||||
var(--post-cai-h)
|
||||
);
|
||||
--post-vte-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-vte-t)) var(--chip-bg-c)
|
||||
var(--post-vte-h)
|
||||
);
|
||||
--post-vte-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-vte-h));
|
||||
--post-vte-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-vte-t)) var(--chip-edge-c)
|
||||
var(--post-vte-h)
|
||||
);
|
||||
--post-res-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-res-t)) var(--chip-bg-c)
|
||||
var(--post-res-h)
|
||||
);
|
||||
--post-res-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-res-h));
|
||||
--post-res-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-res-t)) var(--chip-edge-c)
|
||||
var(--post-res-h)
|
||||
);
|
||||
--post-acc-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-acc-t)) var(--chip-bg-c)
|
||||
var(--post-acc-h)
|
||||
);
|
||||
--post-acc-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-acc-h));
|
||||
--post-acc-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-acc-t)) var(--chip-edge-c)
|
||||
var(--post-acc-h)
|
||||
);
|
||||
--post-cab-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-cab-t)) var(--chip-bg-c)
|
||||
var(--post-cab-h)
|
||||
);
|
||||
--post-cab-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-cab-h));
|
||||
--post-cab-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-cab-t)) var(--chip-edge-c)
|
||||
var(--post-cab-h)
|
||||
);
|
||||
--post-rss-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-rss-t)) var(--chip-bg-c)
|
||||
var(--post-rss-h)
|
||||
);
|
||||
--post-rss-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-rss-h));
|
||||
--post-rss-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-rss-t)) var(--chip-edge-c)
|
||||
var(--post-rss-h)
|
||||
);
|
||||
--post-inv-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-inv-t)) var(--chip-bg-c)
|
||||
var(--post-inv-h)
|
||||
);
|
||||
--post-inv-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-inv-h));
|
||||
--post-inv-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-inv-t)) var(--chip-edge-c)
|
||||
var(--post-inv-h)
|
||||
);
|
||||
--post-liv-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-liv-t)) var(--chip-bg-c)
|
||||
var(--post-liv-h)
|
||||
);
|
||||
--post-liv-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-liv-h));
|
||||
--post-liv-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-liv-t)) var(--chip-edge-c)
|
||||
var(--post-liv-h)
|
||||
);
|
||||
--post-enc-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-enc-t)) var(--chip-bg-c)
|
||||
var(--post-enc-h)
|
||||
);
|
||||
--post-enc-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-enc-h));
|
||||
--post-enc-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-enc-t)) var(--chip-edge-c)
|
||||
var(--post-enc-h)
|
||||
);
|
||||
--post-clc-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-clc-t)) var(--chip-bg-c)
|
||||
var(--post-clc-h)
|
||||
);
|
||||
--post-clc-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-clc-h));
|
||||
--post-clc-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-clc-t)) var(--chip-edge-c)
|
||||
var(--post-clc-h)
|
||||
);
|
||||
--post-net-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-net-t)) var(--chip-bg-c)
|
||||
var(--post-net-h)
|
||||
);
|
||||
--post-net-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-net-h));
|
||||
--post-net-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-net-t)) var(--chip-edge-c)
|
||||
var(--post-net-h)
|
||||
);
|
||||
--post-for-bg: oklch(
|
||||
calc(var(--chip-bg-l) + var(--tier-dir) * var(--post-for-t)) var(--chip-bg-c)
|
||||
var(--post-for-h)
|
||||
);
|
||||
--post-for-fg: oklch(var(--chip-fg-l) var(--chip-fg-c) var(--post-for-h));
|
||||
--post-for-edge: oklch(
|
||||
calc(var(--chip-edge-l) + var(--tier-dir) * var(--post-for-t)) var(--chip-edge-c)
|
||||
var(--post-for-h)
|
||||
);
|
||||
}
|
||||
|
||||
/* Thème sombre : redéfinit les mêmes variables. --tier-dir s'inverse pour que
|
||||
|
||||
Reference in new issue
Block a user