--- name: ui-design description: Panduan design system, CSS variables, layout, dan visual styling untuk Tour Planner App. Gunakan skill ini ketika menulis CSS, membangun layout, atau memastikan konsistensi visual antar halaman. --- # Skill: UI Design — Tour Planner App ## Design System Lengkap Semua token harus didefinisikan di `src/index.css` di dalam `:root`. ```css /* === src/index.css === */ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700;800&family=Playfair+Display:ital,wght@0,600;1,600&display=swap'); :root { /* Colors */ --color-primary: hsl(220, 90%, 56%); --color-primary-dark: hsl(220, 90%, 42%); --color-primary-light: hsl(220, 90%, 70%); --color-primary-glow: hsl(220, 90%, 56%, 0.3); --color-accent: hsl(38, 95%, 55%); --color-accent-dark: hsl(38, 95%, 40%); --color-accent-light: hsl(38, 95%, 70%); --color-bg-base: hsl(222, 28%, 8%); --color-bg-surface: hsl(222, 22%, 13%); --color-bg-elevated: hsl(222, 18%, 18%); --color-bg-overlay: hsla(222, 28%, 5%, 0.8); --color-text-primary: hsl(210, 40%, 96%); --color-text-secondary: hsl(210, 20%, 65%); --color-text-muted: hsl(210, 15%, 45%); --color-border: hsl(220, 15%, 22%); --color-border-light: hsl(220, 15%, 28%); --color-success: hsl(142, 70%, 45%); --color-success-bg: hsl(142, 70%, 45%, 0.15); --color-warning: hsl(38, 95%, 55%); --color-warning-bg: hsl(38, 95%, 55%, 0.15); --color-danger: hsl(0, 75%, 55%); --color-danger-bg: hsl(0, 75%, 55%, 0.15); /* Typography */ --font-body: 'Inter', -apple-system, sans-serif; --font-display: 'Outfit', sans-serif; --font-hero: 'Playfair Display', serif; --text-xs: 0.75rem; --text-sm: 0.875rem; --text-base: 1rem; --text-lg: 1.125rem; --text-xl: 1.25rem; --text-2xl: 1.5rem; --text-3xl: 1.875rem; --text-4xl: 2.25rem; --text-5xl: 3rem; /* Spacing */ --space-1: 0.25rem; --space-2: 0.5rem; --space-3: 0.75rem; --space-4: 1rem; --space-5: 1.25rem; --space-6: 1.5rem; --space-8: 2rem; --space-10: 2.5rem; --space-12: 3rem; --space-16: 4rem; --space-20: 5rem; /* Border Radius */ --radius-sm: 0.375rem; --radius-md: 0.5rem; --radius-lg: 0.75rem; --radius-xl: 1rem; --radius-2xl: 1.5rem; --radius-full: 9999px; /* Shadows */ --shadow-sm: 0 1px 3px hsla(0,0%,0%,0.3); --shadow-md: 0 4px 16px hsla(0,0%,0%,0.35); --shadow-lg: 0 8px 32px hsla(0,0%,0%,0.4); --shadow-glow: 0 0 24px var(--color-primary-glow); /* Transitions */ --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1); --transition-base: 300ms cubic-bezier(0.4, 0, 0.2, 1); --transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1); /* Z-Index */ --z-dropdown: 100; --z-modal: 200; --z-toast: 300; --z-tooltip: 400; } ``` ## CSS Utility Classes Wajib ```css /* Base reset */ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: var(--font-body); background-color: var(--color-bg-base); color: var(--color-text-primary); line-height: 1.6; } /* Glassmorphism */ .glass { background: hsla(222, 22%, 18%, 0.7); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid var(--color-border); border-radius: var(--radius-xl); } /* Gradient text */ .text-gradient { background: linear-gradient(135deg, var(--color-primary-light), var(--color-accent)); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; } /* Layout container */ .container { width: 100%; max-width: 1280px; margin: 0 auto; padding: 0 var(--space-4); } /* Grid layouts */ .grid-2 { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); } .grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--space-4); } .grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-4); } /* Responsive grid */ @media (max-width: 1024px) { .grid-4 { grid-template-columns: repeat(2, 1fr); } .grid-3 { grid-template-columns: repeat(2, 1fr); } } @media (max-width: 640px) { .grid-4, .grid-3, .grid-2 { grid-template-columns: 1fr; } } ``` ## Pola Layout Halaman ```jsx // Setiap page menggunakan struktur ini:

Judul

Deskripsi

{/* konten */}
``` ## Komponen Hero (Home Page) ```css .hero { min-height: 100vh; background: radial-gradient(ellipse at 20% 50%, hsl(220, 90%, 20%, 0.4) 0%, transparent 60%), radial-gradient(ellipse at 80% 20%, hsl(38, 95%, 20%, 0.3) 0%, transparent 60%), var(--color-bg-base); display: flex; align-items: center; position: relative; overflow: hidden; } .hero::before { content: ''; position: absolute; inset: 0; background-image: url("data:image/svg+xml,..."); /* subtle grid pattern */ opacity: 0.03; } ``` ## Warna Kategori Aktivitas ```javascript export const CATEGORY_COLORS = { wisata: 'hsl(220, 90%, 56%)', makan: 'hsl(142, 70%, 45%)', transportasi: 'hsl(280, 70%, 60%)', 'check-in': 'hsl(38, 95%, 55%)', lainnya: 'hsl(210, 20%, 55%)', }; ``` ## Warna Kategori Budget ```javascript export const BUDGET_CATEGORY_COLORS = { transportasi: '#4f8ef7', akomodasi: '#a78bfa', makan: '#34d399', aktivitas: '#fbbf24', 'oleh-oleh': '#f87171', lainnya: '#94a3b8', }; ``` ## Breakpoints ```css /* Mobile first */ /* xs: 0+ (default) */ /* sm: 640+ */ @media (min-width: 640px) { } /* md: 768+ */ @media (min-width: 768px) { } /* lg: 1024+ */ @media (min-width: 1024px) { } /* xl: 1280+ */ @media (min-width: 1280px) { } ``` ## Animasi Framer Motion Standar ```javascript // Import di setiap komponen yang butuh animasi import { motion, AnimatePresence } from 'framer-motion'; // Fade in dari bawah (item list, card) export const fadeInUp = { initial: { opacity: 0, y: 24 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -12 }, transition: { duration: 0.3 } }; // Stagger container export const staggerContainer = { animate: { transition: { staggerChildren: 0.08, delayChildren: 0.1 } } }; // Scale pop (modal, tooltip) export const scalePop = { initial: { opacity: 0, scale: 0.92 }, animate: { opacity: 1, scale: 1 }, exit: { opacity: 0, scale: 0.92 }, transition: { type: 'spring', stiffness: 300, damping: 24 } }; // Slide in dari kiri (sidebar) export const slideInLeft = { initial: { x: -300, opacity: 0 }, animate: { x: 0, opacity: 1 }, exit: { x: -300, opacity: 0 }, transition: { type: 'spring', stiffness: 260, damping: 28 } }; ```