- Add product vision/market research doc (VISION.md) - Set up shadcn/ui (radix + nova preset) with blue/orange theme, Outfit + Work Sans fonts - Landing page: hero with rank input, problem/steps sections, comparison table, FAQ - Data pipeline: CSV archive ingest (2021-2024) + live YÖK Atlas API refresh (2025) into SQLite (npm run ingest / refresh); zeros normalized to NULL - /sonuc page: hayal/dengeli/garanti buckets by COALESCE(sira2025, sira2024), score-type switcher, 2024→2025 trend indicators - Add ui-ux-pro-max and shadcn agent skills, shadcn MCP config, launch.json Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4.6 KiB
Styling & Customization
See customization.md for theming, CSS variables, and adding custom colors.
Contents
- Semantic colors
- Built-in variants first
- className for layout only
- No space-x-* / space-y-*
- Prefer size-* over w-* h-* when equal
- Prefer truncate shorthand
- No manual dark: color overrides
- Use cn() for conditional classes
- No manual z-index on overlay components
- Use shimmer / scroll-fade utilities, not custom animations
Semantic colors
Incorrect:
<div className="bg-blue-500 text-white">
<p className="text-gray-600">Secondary text</p>
</div>
Correct:
<div className="bg-primary text-primary-foreground">
<p className="text-muted-foreground">Secondary text</p>
</div>
No raw color values for status/state indicators
For positive, negative, or status indicators, use Badge variants, semantic tokens like text-destructive, or define custom CSS variables — don't reach for raw Tailwind colors.
Incorrect:
<span className="text-emerald-600">+20.1%</span>
<span className="text-green-500">Active</span>
<span className="text-red-600">-3.2%</span>
Correct:
<Badge variant="secondary">+20.1%</Badge>
<Badge>Active</Badge>
<span className="text-destructive">-3.2%</span>
If you need a success/positive color that doesn't exist as a semantic token, use a Badge variant or ask the user about adding a custom CSS variable to the theme (see customization.md).
Built-in variants first
Incorrect:
<Button className="border border-input bg-transparent hover:bg-accent">
Click me
</Button>
Correct:
<Button variant="outline">Click me</Button>
className for layout only
Use className for layout (e.g. max-w-md, mx-auto, mt-4), not for overriding component colors or typography. To change colors, use semantic tokens, built-in variants, or CSS variables.
Incorrect:
<Card className="bg-blue-100 text-blue-900 font-bold">
<CardContent>Dashboard</CardContent>
</Card>
Correct:
<Card className="max-w-md mx-auto">
<CardContent>Dashboard</CardContent>
</Card>
To customize a component's appearance, prefer these approaches in order:
- Built-in variants —
variant="outline",variant="destructive", etc. - Semantic color tokens —
bg-primary,text-muted-foreground. - CSS variables — define custom colors in the global CSS file (see customization.md).
No space-x-* / space-y-*
Use gap-* instead. space-y-4 → flex flex-col gap-4. space-x-2 → flex gap-2.
<div className="flex flex-col gap-4">
<Input />
<Input />
<Button>Submit</Button>
</div>
Prefer size-* over w-* h-* when equal
size-10 not w-10 h-10. Applies to icons, avatars, skeletons, etc.
Prefer truncate shorthand
truncate not overflow-hidden text-ellipsis whitespace-nowrap.
No manual dark: color overrides
Use semantic tokens — they handle light/dark via CSS variables. bg-background text-foreground not bg-white dark:bg-gray-950.
Use cn() for conditional classes
Use the cn() utility from the project for conditional or merged class names. Don't write manual ternaries in className strings.
Incorrect:
<div className={`flex items-center ${isActive ? "bg-primary text-primary-foreground" : "bg-muted"}`}>
Correct:
import { cn } from "@/lib/utils"
<div className={cn("flex items-center", isActive ? "bg-primary text-primary-foreground" : "bg-muted")}>
No manual z-index on overlay components
Dialog, Sheet, Drawer, AlertDialog, DropdownMenu, Popover, Tooltip, HoverCard handle their own stacking. Never add z-50 or z-[999].
Use shimmer / scroll-fade utilities, not custom animations
For a live "thinking…" or loading-text shimmer, apply the shimmer utility. Don't author a custom @keyframes or a bg-clip-text gradient sweep.
For scroll-aware edge fading on a scroll container, use scroll-fade (and the axis variants scroll-fade-x / scroll-fade-b). Don't hand-roll mask gradients. The chat components already apply these internally: Attachment shimmers its title during upload, and MessageScrollerViewport fades its edges.
Incorrect:
<span className="animate-pulse bg-gradient-to-r from-muted-foreground/40 via-foreground/70 to-muted-foreground/40 bg-clip-text text-transparent [animation:shimmer_1.6s_infinite]">
Thinking…
</span>
Correct:
<span className="shimmer">Thinking…</span>