Files
SeaGateway-App/THEME_GUIDE.md
2025-11-17 17:01:42 +07:00

5.8 KiB

Theme System Documentation

Tổng quan

Hệ thống theme đã được cấu hình để hỗ trợ Light Mode, Dark Mode và System Mode (tự động theo hệ thống). Theme được lưu trữ trong AsyncStorage và sẽ được khôi phục khi khởi động lại ứng dụng.

Cấu trúc Theme

1. Colors Configuration (constants/theme.ts)

export const Colors = {
  light: {
    text: "#11181C",
    textSecondary: "#687076",
    background: "#fff",
    backgroundSecondary: "#f5f5f5",
    surface: "#ffffff",
    surfaceSecondary: "#f8f9fa",
    primary: "#007AFF",
    secondary: "#5AC8FA",
    success: "#34C759",
    warning: "#FF9500",
    error: "#FF3B30",
    // ... more colors
  },
  dark: {
    text: "#ECEDEE",
    textSecondary: "#8E8E93",
    background: "#000000",
    backgroundSecondary: "#1C1C1E",
    surface: "#1C1C1E",
    surfaceSecondary: "#2C2C2E",
    primary: "#0A84FF",
    secondary: "#64D2FF",
    success: "#30D158",
    warning: "#FF9F0A",
    error: "#FF453A",
    // ... more colors
  },
};

2. Theme Context (hooks/use-theme-context.tsx)

Cung cấp theme state và functions cho toàn bộ app:

interface ThemeContextType {
  themeMode: ThemeMode; // 'light' | 'dark' | 'system'
  colorScheme: ColorScheme; // 'light' | 'dark'
  colors: typeof Colors.light;
  setThemeMode: (mode: ThemeMode) => Promise<void>;
  getColor: (colorName: ColorName) => string;
}

Cách sử dụng Theme

1. Sử dụng Themed Components

import { ThemedText } from "@/components/themed-text";
import { ThemedView } from "@/components/themed-view";

function MyComponent() {
  return (
    <ThemedView>
      <ThemedText type="title">Title Text</ThemedText>
      <ThemedText type="default">Regular Text</ThemedText>
    </ThemedView>
  );
}

2. Sử dụng Theme Hook

import { useThemeContext } from "@/hooks/use-theme-context";

function MyComponent() {
  const { colors, colorScheme, setThemeMode } = useThemeContext();

  return (
    <View style={{ backgroundColor: colors.background }}>
      <Text style={{ color: colors.text }}>Current theme: {colorScheme}</Text>
    </View>
  );
}
import { useAppTheme } from "@/hooks/use-app-theme";

function MyComponent() {
  const { colors, styles, utils } = useAppTheme();

  return (
    <View style={styles.container}>
      <TouchableOpacity style={styles.primaryButton}>
        <Text style={styles.primaryButtonText}>Button</Text>
      </TouchableOpacity>

      <View
        style={[
          styles.surface,
          {
            backgroundColor: utils.getOpacityColor("primary", 0.1),
          },
        ]}
      >
        <Text style={{ color: colors.text }}>
          Theme is {utils.isDark ? "Dark" : "Light"}
        </Text>
      </View>
    </View>
  );
}

4. Sử dụng useThemeColor Hook

import { useThemeColor } from "@/hooks/use-theme-color";

function MyComponent() {
  // Override colors for specific themes
  const backgroundColor = useThemeColor(
    { light: "#ffffff", dark: "#1C1C1E" },
    "surface"
  );

  const textColor = useThemeColor({}, "text");

  return (
    <View style={{ backgroundColor }}>
      <Text style={{ color: textColor }}>Text</Text>
    </View>
  );
}

Theme Toggle Component

Sử dụng ThemeToggle component để cho phép user chọn theme:

import { ThemeToggle } from "@/components/theme-toggle";

function SettingsScreen() {
  return (
    <View>
      <ThemeToggle />
    </View>
  );
}

Available Styles từ useAppTheme

const { styles } = useAppTheme();

// Container styles
styles.container; // Flex 1 container với background
styles.surface; // Card surface với padding
styles.card; // Card với shadow và border radius

// Button styles
styles.primaryButton; // Primary button style
styles.secondaryButton; // Secondary button với border
styles.primaryButtonText; // White text cho primary button
styles.secondaryButtonText; // Theme text cho secondary button

// Input styles
styles.textInput; // Text input với border và padding

// Status styles
styles.successContainer; // Success status container
styles.warningContainer; // Warning status container
styles.errorContainer; // Error status container

// Utility
styles.separator; // Line separator

Theme Utilities

const { utils } = useAppTheme();

utils.isDark; // boolean - kiểm tra dark mode
utils.isLight; // boolean - kiểm tra light mode
utils.toggleTheme(); // function - toggle giữa light/dark
utils.getOpacityColor(colorName, opacity); // Tạo màu với opacity

Lưu trữ Theme Preference

Theme preference được tự động lưu trong AsyncStorage với key 'theme_mode'. Khi app khởi động, theme sẽ được khôi phục từ storage.

Best Practices

  1. Sử dụng useAppTheme thay vì access colors trực tiếp
  2. Sử dụng pre-defined styles từ useAppTheme().styles
  3. Kiểm tra theme bằng utils.isDark thay vì check colorScheme
  4. Sử dụng opacity colors cho backgrounds: utils.getOpacityColor('primary', 0.1)
  5. Tận dụng ThemedText và ThemedView cho các component đơn giản

Migration từ theme cũ

Nếu bạn đang sử dụng theme cũ:

// Cũ
const colorScheme = useColorScheme();
const backgroundColor = colorScheme === "dark" ? "#000" : "#fff";

// Mới
const { colors } = useAppTheme();
const backgroundColor = colors.background;

Troubleshooting

  1. Theme không được lưu: Kiểm tra AsyncStorage permissions
  2. Flash khi khởi động: ThemeProvider sẽ chờ load theme trước khi render
  3. Colors không đúng: Đảm bảo component được wrap trong ThemeProvider

Examples

Xem components/theme-example.tsx để biết các cách sử dụng theme khác nhau.