- Add i18n support (EN/ZH) with language toggle - Redesign header with education dropdown, contact copy buttons - Add RBC project showcase with bullet points, skills highlighting - Create terraform-drift placeholder page - Add ProjectShowcase component with media toggle (image/video) - Update experience timeline with action-driven descriptions - Add Docker + Forgejo CI workflow for image builds - Update K8s manifests for riotpiao.com ingress - Add DESIGN.md documenting design system patterns
7.7 KiB
7.7 KiB
Portfolio Design System
Color Palette
Primary Colors
- Blue:
blue-600(primary actions, links, accents) - Purple:
purple-600(gradients, secondary accents) - Green:
green-500(live status, success)
Neutral Colors
-
Light Mode:
- Background:
white,gray-50 - Text Primary:
gray-900 - Text Secondary:
gray-600,gray-700 - Borders:
gray-200,gray-300
- Background:
-
Dark Mode:
- Background:
gray-950,gray-900 - Text Primary:
white - Text Secondary:
gray-400,gray-300 - Borders:
gray-800,gray-700
- Background:
Status Colors
- Live:
green-100/900bg,green-800/200text - Building:
blue-100/900bg,blue-800/200text - Planning:
gray-100/800bg,gray-800/200text
Timeline Colors (gradients)
- riotpiao.com:
from-green-500 to-green-600 - RBC:
from-red-500 to-red-600 - AWS:
from-orange-500 to-orange-600 - Titus:
from-cyan-500 to-cyan-600 - NAV Canada:
from-blue-500 to-blue-600
Typography
Font Sizes
- Hero Title:
text-4xl md:text-5xl font-bold - Section Title:
text-4xl font-bold - Card Title:
text-2xl font-boldortext-xl font-bold - Subtitle:
text-xl font-mediumortext-lg - Body:
text-smortext-base - Caption:
text-xs - Mono/Code:
font-mono text-xs
Font Weights
- Bold:
font-bold(titles, emphasis) - Semibold:
font-semibold(subtitles, labels) - Medium:
font-medium(secondary text)
Spacing
Layout
- Max Width:
max-w-6xl(main container),max-w-4xl(content),max-w-3xl(cards),max-w-5xl(hero image) - Padding:
px-6(horizontal),py-20orpy-24(section vertical) - Gap:
gap-8(cards),gap-6(nav items),gap-4(buttons),gap-2(tags)
Component Spacing
- Section margin bottom:
mb-16 - Card padding:
p-6 - Button padding:
px-8 py-3(large),px-4 py-2(medium),px-3 py-1(small)
Components
Buttons
Primary Button
className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-3 rounded-lg font-semibold transition"
Secondary/Outline Button
className="border-2 border-gray-300 dark:border-gray-600 text-gray-900 dark:text-white hover:bg-gray-100 dark:hover:bg-gray-800 px-4 py-2 rounded-lg font-semibold transition"
Language Toggle
className="px-3 py-1 text-sm font-semibold rounded border border-gray-300 dark:border-gray-600 hover:bg-gray-100 dark:hover:bg-gray-800"
Icon Button
className="p-2 hover:bg-gray-100 dark:hover:bg-gray-800 rounded"
Cards
Standard Card
className="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 p-6 hover:shadow-lg transition-shadow"
Project Showcase Card
className="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden hover:shadow-lg transition-shadow"
Tags/Pills
Skill Tag
className="text-xs px-3 py-1 rounded-full bg-gray-100 dark:bg-gray-800 text-gray-700 dark:text-gray-300"
Status Badge
// Live
className="px-3 py-1 rounded-full text-xs font-semibold bg-green-100 dark:bg-green-900 text-green-800 dark:text-green-200"
// Building
className="px-3 py-1 rounded-full text-xs font-semibold bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200"
Dropdowns
Dropdown Container
className="absolute right-0 mt-2 w-64 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 rounded-lg shadow-lg p-4 space-y-3"
Modals
Modal Overlay
className="fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4"
Modal Content
className="bg-white dark:bg-gray-900 rounded-lg shadow-2xl max-w-2xl w-full max-h-96 overflow-y-auto"
Modal Header (Gradient)
className="sticky top-0 bg-gradient-to-r from-blue-600 to-purple-600 px-6 py-6 flex justify-between items-center"
Animations (Framer Motion)
Fade In Up
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8, delay: 0.2 }}
Scale In
initial={{ scale: 0, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ duration: 0.8, delay: 0.2 }}
Stagger Children
variants={{
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.15 },
},
}}
Role Text Rotation
initial={{ opacity: 0, y: 20, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: -20, scale: 0.95 }}
transition={{ duration: 0.6, ease: 'easeInOut' }}
Background Pulse
animate={{
scale: [1, 1.15, 1],
opacity: [0.25, 0.4, 0.25],
}}
transition={{
duration: 6,
repeat: Infinity,
ease: 'easeInOut',
}}
Gradients
Hero Background
className="bg-gradient-to-br from-blue-50 to-purple-50 dark:from-gray-950 dark:to-gray-900"
Timeline Line
className="bg-gradient-to-b from-blue-500 via-purple-500 to-green-500"
Stat Highlight
className="bg-gradient-to-r from-blue-50 to-purple-50 dark:from-gray-800 dark:to-gray-800"
Modal Header
className="bg-gradient-to-r from-blue-600 to-purple-600"
Z-Index Layers
z-0: Background imagesz-10: Content overlays (avatar, text)z-20: Avatar + rotating text groupz-40: Terminal buttonz-50: Header, Modals
Responsive Breakpoints
- Mobile: Default (no prefix)
- Tablet/Desktop:
md:(768px+) - Large Desktop:
lg:(1024px+)
Common Patterns
// Hide on mobile, show on desktop
className="hidden md:flex"
// Show on mobile, hide on desktop
className="md:hidden"
// Responsive grid
className="grid grid-cols-1 md:grid-cols-2 gap-8"
// Responsive text
className="text-4xl md:text-5xl"
// Responsive padding
className="px-4 md:px-6"
Icons (Lucide React)
Sizes
- Navigation:
size={20} - Buttons:
size={16} - Cards:
size={24} - Hero:
size={32} - Close:
size={24}
Common Icons
Menu,X- Mobile navMoon,Sun- Theme toggleExternalLink- External linksNetwork,Shield,Code,Sparkles,Zap,Cpu- Role iconsGitBranch,Database,MessageSquare,Layers,BarChart3- Feature icons
Internationalization (i18n)
Structure
lib/
translations.json # All translations
LanguageContext.tsx # React context provider
Usage
import { useLanguage } from '@/lib/LanguageContext'
const { lang, setLang, t } = useLanguage()
// Access translations
<h1>{t.hero.title}</h1>
Language Toggle Button
Shows opposite language:
- When
en: Shows中文 - When
zh: ShowsEN
File Structure
components/
Header.tsx # Navigation, dropdowns, language toggle
HeroBlobFlow.tsx # Hero with avatar, rotating roles
ExperienceTimeline.tsx # Work history timeline
ProjectShowcase.tsx # Project cards
InteractiveTerminal.tsx # Cmd+K terminal
TypewriterText.tsx # Typewriter effect
lib/
TerminalContext.tsx # Terminal open/close state
LanguageContext.tsx # Language state + translations
translations.json # EN/ZH translations
app/
page.tsx # Main page
layout.tsx # Root layout with providers
globals.css # Tailwind + global styles
public/
avatar.jpeg # Profile photo
hire-me.png # Dark mode hero background
hire-me-light.png # Light mode hero background
Dark Mode
Implemented via Tailwind's dark: prefix. Toggle class on <html> element.
// Toggle
document.documentElement.classList.toggle('dark')
// Check
document.documentElement.classList.contains('dark')
Observe changes via MutationObserver for components that need to react to theme changes (e.g., background image swap).