Урок 19. Решения

📁 Раздел: shadcn/ui ⏱️ Время изучения: ~50 мин 🎯 Сложность: Продвинутая

⚡ Кратко

Готовая фирменная тема, своя пара токенов и страница-образец.

Решение задания 1

📄 src/index.css
/* src/index.css */
:root {
  --primary: oklch(0.55 0.21 264);
  --primary-foreground: oklch(0.985 0 0);
}

.dark {
  --primary: oklch(0.62 0.19 264);
  --primary-foreground: oklch(0.145 0 0);
}

Почему в тёмной теме foreground тёмный: сам primary стал светлее (чтобы выделяться на тёмном фоне), значит, текст на нём должен быть тёмным. Пара всегда переворачивается вместе.

Переключите тему — пара перевернётся
<div class="flex flex-wrap items-center gap-3">
  <button class="inline-flex h-8 items-center justify-center rounded-lg bg-brand px-3 text-sm font-medium text-brand-foreground">Фирменная кнопка</button>
  <span class="text-sm text-muted-foreground">Переключите тему — пара перевернётся</span>
</div>

Решение задания 2

📄 src/index.css
@theme inline {
  --color-success: var(--success);
  --color-success-foreground: var(--success-foreground);
}

:root {
  --success: oklch(0.62 0.15 160);
  --success-foreground: oklch(0.985 0 0);
}

.dark {
  --success: oklch(0.72 0.14 160);
  --success-foreground: oklch(0.145 0 0);
}
<Badge className="bg-success text-success-foreground">Оплачено</Badge>
<Button className="bg-success text-success-foreground hover:opacity-90">Подтвердить</Button>
Если роль используется часто, не ограничивайтесь className — заведите вариант в компоненте: success: "bg-success text-success-foreground". Тогда применение будет единообразным по всему проекту.

Решение задания 3

📄 src/routes/theme.tsx
// src/routes/theme.tsx — страница-образец
import { Button } from "@/components/ui/button"
import { Badge } from "@/components/ui/badge"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Input } from "@/components/ui/input"

const TOKENS = [
  ["bg-background text-foreground", "background"],
  ["bg-card text-card-foreground", "card"],
  ["bg-primary text-primary-foreground", "primary"],
  ["bg-secondary text-secondary-foreground", "secondary"],
  ["bg-muted text-muted-foreground", "muted"],
  ["bg-accent text-accent-foreground", "accent"],
]

export function ThemePage() {
  return (
    <div className="space-y-6 p-6">
      <div className="grid gap-2 sm:grid-cols-3">
        {TOKENS.map(([classes, name]) => (
          <div key={name} className={`rounded-lg p-3 text-sm ring-1 ring-border ${classes}`}>{name}</div>
        ))}
      </div>
      <div className="flex flex-wrap gap-2">
        <Button>Default</Button>
        <Button variant="outline">Outline</Button>
        <Button variant="ghost">Ghost</Button>
        <Button variant="destructive">Destructive</Button>
      </div>
      <div className="flex flex-wrap gap-2">
        <Badge>Badge</Badge>
        <Badge variant="outline">Outline</Badge>
      </div>
      <Input placeholder="Поле ввода" />
      <Card><CardHeader><CardTitle>Карточка</CardTitle></CardHeader><CardContent>Содержимое</CardContent></Card>
    </div>
  )
}

Зачем это нужно: любая правка темы проверяется за десять секунд на одном экране, а не хождением по всему приложению. Это дешёвая страховка от «поправил кнопку — сломал меню».