8
Styling, Token Warna, dan Tema
src/styles/globals.css adalah stylesheet global utama. Berkas itu mengimpor tailwindcss dan plugin @tailwindcss/forms, lalu menaruh seluruh token desain di dalam blok @theme. src/styles/globals.css:1-21 Berkas kedua, src/styles/colors.css, bukan stylesheet umum: isinya hanya preset palet primary untuk keperluan demo pergantian warna, dan baris pertamanya meminta berkas itu dihapus setelah warna yang diinginkan disalin. src/styles/colors.css:1-152
Pipeline CSS dari @theme sampai kelas utilitas
Tailwind di repository ini dikonfigurasi sepenuhnya lewat CSS; tidak ada tailwind.config.js. Kedua berkas stylesheet masuk ke PostCSS dengan dua plugin, @tailwindcss/postcss dan autoprefixer. postcss.config.js:1-63 Alur dari berkas sumber sampai CSS final terlihat pada diagram berikut.
graph LR
G["src/styles/globals.css"] --> PC["postcss.config.js"]
C["src/styles/colors.css"] --> PC
PC --> TW["@tailwindcss/postcss"]
PC --> AP["autoprefixer"]
TW --> OUT["CSS final"]
style G fill:#336791,color:#fff
style C fill:#336791,color:#fff
style PC fill:#f59e0b,color:#000
style TW fill:#8b5cf6,color:#fff
style AP fill:#8b5cf6,color:#fff
style OUT fill:#2d7d46,color:#fff
%% fig: Rantai PostCSS untuk dua berkas stylesheet
%% desc: globals.css dan colors.css diolah @tailwindcss/postcss lalu autoprefixer, dan keluar sebagai satu CSS final.Urutan impor ditentukan di root layout: globals.css lebih dulu, lalu colors.css dengan komentar !STARTERCONF yang meminta impor demo itu segera dihapus. src/app/layout.tsx:4-64 Layout segmen komponen mengimpor colors.css sendiri tanpa globals.css. src/app/components/layout.tsx:45
Token di dalam blok @theme
Satu blok @theme memuat semua variabel yang dipakai lintas komponen: font, palet primary 11 langkah, satu warna gelap, dan dua animasi. src/styles/globals.css:4-276
| Token | Nilai | Pemakai nyata |
|---|---|---|
--font-primary | 'Inter', system-ui, sans-serif | kelas .h0 sampai .p lewat font-primary |
--color-primary-50 … --color-primary-950 | 11 langkah oklch dengan hue 213.79 | bg-primary-*, text-primary-*, ring-primary-* |
--color-dark | #222222 | bg-dark pada halaman komponen dan variant light Button |
--animate-flicker | flicker 3s linear infinite | ikon peringatan di error.tsx dan not-found.tsx |
--animate-shimmer | shimmer 1.3s linear infinite | Skeleton |
Setiap variabel warna di @theme langsung menjadi kelas utilitas. Buktinya ada di komponen: variant primary pada Button memakai bg-primary-500, border-primary-600, hover:bg-primary-600, dan active:bg-primary-700. src/components/buttons/Button.tsx:61-677 UnderlineLink memakai focus-visible:ring-primary-500 bersama border-dark. src/components/links/UnderlineLink.tsx:16-188 Pemetaan variant Button ke token terlihat di tabel ini.
Variant Button | Kelas warna | Sumber token |
|---|---|---|
primary | bg-primary-500 text-white, border-primary-600 | --color-primary-500, --color-primary-600 |
outline | text-primary-500, border-primary-500, hover:bg-primary-50 | --color-primary-50, --color-primary-500 |
ghost | text-primary-500, hover:bg-primary-50 | --color-primary-50, --color-primary-500 |
light | bg-white text-gray-700, hover:text-dark | --color-dark |
dark | bg-gray-900 text-white, border-gray-600 | palet bawaan Tailwind |
Rincian katalog komponen ada di Katalog Komponen Pratinjau, dengan pembahasan terpisah di Komponen Tombol dan Komponen Link.
Animasi dan keyframes
Dua token animasi ditopang oleh dua @keyframes di berkas yang sama. flicker menurunkan opacity ke 0.4 dan melepas drop-shadow pada persentase tertentu dari siklus 3 detik, sedangkan shimmer menggeser background-position dari -700px ke 700px. src/styles/globals.css:30-629
Konsumsi keduanya nyata di tiga tempat. Ikon RiAlarmWarningFill di halaman error dan halaman 404 memakai drop-shadow-glow animate-flicker text-red-500. src/app/error.tsx:24-2610 src/app/not-found.tsx:14-1611 Skeleton memakai animate-shimmer bersama backgroundImage linear-gradient dan backgroundSize: '700px 100%', yang cocok dengan jarak geser keyframe shimmer. src/components/Skeleton.tsx:7-1912
⚠️ Kelas
drop-shadow-glowtidak didefinisikan disrc/styles/globals.css. Hanyaanimate-flickeryang punya token di@theme, jadi bagian glow dari ikon peringatan tidak berasal dari stylesheet repository ini.
Tipografi dan kelas layout di @layer base
@layer base menampung @font-face Inter dari /fonts/inter-var-latin.woff2 dengan font-display: block, kursor khusus .cursor-newtab, seluruh aturan tipografi, dan dua kelas layout. src/styles/globals.css:64-12613 Skala tipografi memakai @apply sehingga ukuran naik pada breakpoint md.
| Selektor | Aturan @apply |
|---|---|
.h0 | font-primary text-3xl font-bold md:text-5xl |
h1, .h1 | font-primary text-2xl font-bold md:text-4xl |
h2, .h2 | font-primary text-xl font-bold md:text-3xl |
h3, .h3 | font-primary text-lg font-bold md:text-2xl |
h4, .h4 | font-primary text-base font-bold md:text-lg |
body, .p | font-primary text-sm md:text-base |
Kelas .h0 sampai .p itu menempel langsung pada elemen h1–h4 dan body, jadi ukuran judul sudah berlaku tanpa kelas tambahan. src/styles/globals.css:81-11014 Di bagian yang sama ada .layout dengan max-width: 68.75rem, .min-h-main dengan min-h-[calc(100vh-56px)], dan penyesuaian .bg-dark a.custom-link. src/styles/globals.css:112-12515
Utilitas animated-underline
@layer utilities hanya berisi satu kelas, .animated-underline. Kelas itu menyusun dua lapis linear-gradient: lapis pertama transparan sebagai penahan ruang, lapis kedua bergradasi dari var(--color-primary-400) ke var(--color-primary-500). background-size dimulai dari 100% 2px, 0 2px dan berubah menjadi 0 2px, 100% 2px saat :hover atau :focus-visible, dengan transition: 0.3s ease yang dibungkus prefers-reduced-motion: no-preference. src/styles/globals.css:128-15116 Karena memakai var(--color-primary-*) secara langsung, garis bawah ini ikut berubah ketika palet primary diganti.
Demo pergantian palet dari colors.css
src/styles/colors.css mendefinisikan ulang --color-primary-50 sampai --color-primary-950 di dalam kelas bernama sesuai palet Tailwind, misalnya .slate dan .rose sebagai blok terakhir. src/styles/colors.css:296-30817 Mekanisme demo bergantung pada sifat inherit variabel CSS: kelas palet dipasang pada elemen section, sehingga semua utilitas bg-primary-* di dalam subtree itu membaca nilai baru.
graph TD
LIST["colorList: 22 nama palet"] --> SEL["select onChange setColor"]
SEL --> SEC["section dengan kelas mode dan nama palet"]
SEC --> VAR["--color-primary-* di subtree section"]
VAR --> SW["bg-primary-50 sampai bg-primary-950"]
SW --> VIS["kotak swatch berganti warna"]
style LIST fill:#8b5cf6,color:#fff
style SEL fill:#f59e0b,color:#000
style SEC fill:#2d7d46,color:#fff
style VAR fill:#336791,color:#fff
style SW fill:#2d7d46,color:#fff
style VIS fill:#2d7d46,color:#fff
%% fig: Alur pergantian palet primary pada halaman komponen
%% desc: Nama palet dari colorList menjadi kelas pada section, variabel primary di subtree berubah, dan utilitas bg-primary-* ikut berganti.Halaman pratinjau menyimpan dua state: mode bertipe 'dark' | 'light' dengan nilai awal 'light', dan color bertipe turunan colorList dengan nilai awal 'sky'. src/app/components/page.tsx:25-2918 Keduanya digabung pada satu section: kelas warna latar bg-dark atau bg-white, lalu nama palet sebagai kelas tambahan. src/app/components/page.tsx:39-4019 Bagian "Customize Colors" memuat teks pengantar bahwa warna primary bisa diganti lewat globals.css, sebuah select dengan opsi dari colorList, dan tautan ke berkas colors.css di GitHub. src/app/components/page.tsx:64-6820 Di bawah select itu ada 11 kotak bg-primary-50 sampai bg-primary-950 sebagai contoh skala penuh. src/app/components/page.tsx:93-12721
colorList berisi 22 nama palet, dari slate sampai rose. src/app/components/page.tsx:438-46122 Jumlah itu sepadan dengan jumlah blok kelas di colors.css: satu blok untuk setiap nama, ditutup .rose di baris 296. src/styles/colors.css:296-30817
⚠️
colors.cssadalah bahan demo, bukan bagian desain final. Impor di root layout ditandai!STARTERCONFuntuk dihapus. src/app/layout.tsx:4-64 Jika berkas itu dihapus tanpa menyalin palet pilihan ke@theme,selectpada halaman komponen tetap menampilkan 22 nama, tetapi kelas tersebut tidak lagi punya variabel sehingga 22 opsi itu tidak mengubah warna apa pun.
Tema gelap dan terang
Repository ini tidak memakai varian dark: Tailwind dan tidak membaca prefers-color-scheme. "Tema" di sini adalah state React pada halaman pratinjau: toggleMode membalik nilai mode antara 'dark' dan 'light'. src/app/components/page.tsx:25-2918 Saat mode bernilai 'dark', section memakai bg-dark dan Button pemanggil toggle memakai variant='light'; saat 'light', latarnya bg-white dan tombolnya variant='dark'. Karena bg-dark berasal dari --color-dark: #222222, warna gelap itu ikut menjadi bagian dari token di @theme. src/styles/globals.css:4-276
Pemilihan latar berada di satu tempat saja, yaitu halaman komponen. Komponen lain menerima informasi tema lewat prop isDarkBg untuk menyesuaikan hover pada variant outline dan ghost, seperti terlihat pada Button. src/components/buttons/Button.tsx:61-677 Pola layout dan metadata yang membungkus halaman ini dibahas di App Router, Layout, dan Metadata.