Files
Story Crater Bot b9ae470bc1 feat: portfolio redesign with i18n, RBC project showcase, CI/CD
- 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
2026-08-31 13:59:46 -07:00

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
  • Dark Mode:

    • Background: gray-950, gray-900
    • Text Primary: white
    • Text Secondary: gray-400, gray-300
    • Borders: gray-800, gray-700

Status Colors

  • Live: green-100/900 bg, green-800/200 text
  • Building: blue-100/900 bg, blue-800/200 text
  • Planning: gray-100/800 bg, gray-800/200 text

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-bold or text-xl font-bold
  • Subtitle: text-xl font-medium or text-lg
  • Body: text-sm or text-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-20 or py-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 images
  • z-10: Content overlays (avatar, text)
  • z-20: Avatar + rotating text group
  • z-40: Terminal button
  • z-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 nav
  • Moon, Sun - Theme toggle
  • ExternalLink - External links
  • Network, Shield, Code, Sparkles, Zap, Cpu - Role icons
  • GitBranch, 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: Shows EN

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).