- Published on
Hệ thống Theme: Từ Matrix đến Tím Cyber
- Authors
- Name
- Dan Tech
- @dan_0xff
Việc tạo một hệ thống theme cho Git Command Terminal phức tạp hơn là chỉ thay đổi vài màu sắc. Mình muốn người dùng có thể chuyển đổi giữa các phong cách thẩm mỹ hoàn toàn khác biệt - từ màu xanh lá Matrix đậm chất cyberpunk đến màu tím Cyber huyền bí.
Đây là cách mình đã xây dựng một hệ thống theme mạnh mẽ, không chỉ dừng lại ở việc đổi màu cơ bản.
Không Chỉ Là Màu Sắc
Một theme terminal cần truyền tải được cá tính và tâm trạng:
- Matrix: Phong cách hacker với màu xanh lá sáng trên nền đen
- Oceanic: Những sắc xanh dương dịu mát gợi cảm giác sâu thẳm của đại dương
- Sunset: Các tông màu cam và vàng ấm áp tạo cảm giác ấm cúng
- Midnight: Các sắc tím đậm cho những đêm code muộn
- Neon: Sự kết hợp giữa hồng và xanh cyan theo phong cách cyberpunk
- Light: Theme sáng truyền thống để dễ tiếp cận
Mỗi theme cần phải tạo cảm giác thống nhất trên toàn bộ ứng dụng, chứ không chỉ riêng khu vực terminal.
Yêu Cầu Hệ Thống Thiết Kế
Hệ thống theme cần hỗ trợ:
- Chuyển đổi theme lúc chạy mà không cần tải lại trang
- Mối quan hệ màu sắc nhất quán giữa các theme
- Các yếu tố về khả năng tiếp cận (tỷ lệ tương phản)
- Dễ dàng thêm theme mới
- Đảm bảo an toàn kiểu (type safety) cho các giá trị của theme
Tại Sao Chọn OKLCH Thay Vì HSL/RGB
Các không gian màu truyền thống có những hạn chế:
/* HSL - độ sáng cảm nhận không đồng đều */
hsl(240, 50%, 50%) /* Không có cùng độ sáng cảm nhận như */
hsl(60, 50%, 50%) /* màu vàng này */
/* RGB - không có mối quan hệ trực quan */
rgb(128, 128, 255) /* Khó tạo ra các biến thể hài hòa */
OKLCH (Oklch Lightness Chroma Hue) mang lại sự đồng nhất về mặt cảm nhận:
/* OKLCH - độ sáng cảm nhận đồng đều */
oklch(0.7 0.15 240) /* Cùng độ sáng cảm nhận như */
oklch(0.7 0.15 60) /* màu này, chỉ khác tông màu (hue) */
Lợi Ích Khi Tạo Theme
Độ Sáng Dễ Đoán: Độ sáng 0.7
trông như nhau ở mọi tông màu Điều Chỉnh Trực Quan: Chỉ cần thay đổi tông màu (hue) để tạo ra các biến thể màu sắc Gradient Tốt Hơn: Chuyển màu mượt mà hơn Khả Năng Tiếp Cận: Dễ dàng duy trì tỷ lệ tương phản
Bảng Màu Toàn Diện
Mỗi theme định nghĩa tất cả các màu sắc theo ngữ nghĩa:
export interface Theme {
id: string
name: string
colors: {
background: string
foreground: string
card: string
cardForeground: string
popover: string
popoverForeground: string
primary: string
primaryForeground: string
secondary: string
secondaryForeground: string
accent: string
accentForeground: string
destructive: string
destructiveForeground: string
muted: string
mutedForeground: string
border: string
input: string
ring: string
}
}
Ví Dụ Về Theme Matrix
Theme Matrix kinh điển sử dụng OKLCH:
{
id: 'matrix',
name: 'Matrix Terminal',
colors: {
background: 'oklch(0.15 0.02 240)', // Màu đen-xanh dương rất tối
foreground: 'oklch(0.7 0.15 145)', // Màu xanh lá matrix sáng
primary: 'oklch(0.7 0.15 145)', // Cùng màu xanh lá matrix
primaryForeground: 'oklch(0.15 0.02 240)', // Nền tối
accent: 'oklch(0.7 0.15 45)', // Màu vàng-xanh lá cảnh báo
destructive: 'oklch(0.65 0.2 25)', // Màu đỏ-cam báo lỗi
// ... các màu khác
}
}
Áp Dụng Theme Động
Việc chuyển đổi theme lúc chạy sẽ cập nhật các biến CSS:
export const applyTheme = (theme: Theme) => {
const root = document.documentElement
Object.entries(theme.colors).forEach(([key, value]) => {
// Chuyển đổi camelCase sang kebab-case
const cssVariable = key.replace(/([A-Z])/g, '-$1').toLowerCase()
root.style.setProperty(`--${cssVariable}`, value)
})
}
Lưu Trữ Theme
Lựa chọn theme của người dùng được lưu lại giữa các phiên làm việc:
export const getCurrentTheme = (): string => {
if (typeof window === 'undefined') return 'matrix'
return localStorage.getItem('git-terminal-theme') || 'matrix'
}
export const setCurrentTheme = (themeId: string) => {
if (typeof window === 'undefined') return
localStorage.setItem('git-terminal-theme', themeId)
}
Hook Xử Lý Theme
Một custom hook quản lý trạng thái và việc lưu trữ theme:
export function useThemeHandlers({ currentThemeId, setCurrentThemeId }: UseThemeHandlersProps) {
useEffect(() => {
const savedTheme = getCurrentTheme()
setCurrentThemeId(savedTheme)
const theme = themes.find((t) => t.id === savedTheme) || themes[0]
applyTheme(theme)
})
useEffect(() => {
const theme = themes.find((t) => t.id === currentThemeId) || themes[0]
applyTheme(theme)
}, [currentThemeId])
const handleThemeChange = (themeId: string) => {
setCurrentThemeId(themeId)
setCurrentTheme(themeId)
const theme = themes.find((t) => t.id === themeId)
if (theme) {
toast.success(strings.buildSuccessMessage('themeChanged', { themeName: theme.name }))
}
}
return {
handleThemeChange,
}
}
Lý Thuyết Màu Sắc Trong Thực Tế
Mỗi theme sử dụng các nguyên tắc của lý thuyết màu sắc:
- Theme Matrix: Đơn sắc xanh lá với độ tương phản cao
- Theme Oceanic: Các màu tương đồng (analogous) như xanh dương và xanh mòng két
- Theme Sunset: Các tông màu nóng như cam và vàng
- Theme Midnight: Các tông màu lạnh như tím và hồng cánh sen
- Theme Neon: Các màu bổ sung (complementary) như hồng và xanh cyan
Looking Forward
Việc xây dựng hệ thống theme này đã dạy mình rằng một theme tốt không chỉ là tập hợp các màu sắc - chúng là những ngôn ngữ thiết kế gắn kết, ảnh hưởng đến toàn bộ trải nghiệm người dùng. Việc đầu tư vào không gian màu OKLCH và các vai trò màu sắc theo ngữ nghĩa đã mang lại một hệ thống vừa mạnh mẽ cho lập trình viên, vừa thú vị cho người dùng.
Hệ thống theme hoàn chỉnh, với tất cả sáu theme và cơ sở hạ tầng hỗ trợ, có sẵn tại kho mã nguồn Git Command Terminal. Nó cho thấy cách thiết kế màu sắc có chủ đích có thể biến một terminal đơn giản thành một trải nghiệm cá nhân hóa và đắm chìm.