Matthias Nott
2026-03-08 dbb6bf09b013937b5903844f8aa567ef4ee69555
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import React, { createContext, useCallback, useContext, useEffect, useState } from "react";
import { useColorScheme } from "react-native";
import * as SecureStore from "expo-secure-store";
const THEME_KEY = "pailot_theme";
type ThemeMode = "light" | "dark" | "system";
export interface ThemeColors {
  bg: string;
  bgSecondary: string;
  bgTertiary: string;
  text: string;
  textSecondary: string;
  textMuted: string;
  border: string;
  accent: string;
  accentBg: string;
  danger: string;
}
const darkColors: ThemeColors = {
  bg: "#0A0A0F",
  bgSecondary: "#14141F",
  bgTertiary: "#1E1E2E",
  text: "#E8E8F0",
  textSecondary: "#9898B0",
  textMuted: "#5A5A78",
  border: "#2E2E45",
  accent: "#4A9EFF",
  accentBg: "#4A9EFF18",
  danger: "#FF3B30",
};
const lightColors: ThemeColors = {
  bg: "#FFFFFF",
  bgSecondary: "#F5F5F7",
  bgTertiary: "#EEEEF0",
  text: "#1C1C1E",
  textSecondary: "#636366",
  textMuted: "#AEAEB2",
  border: "#D1D1D6",
  accent: "#007AFF",
  accentBg: "#007AFF14",
  danger: "#FF3B30",
};
interface ThemeContextValue {
  mode: ThemeMode;
  isDark: boolean;
  colors: ThemeColors;
  setMode: (mode: ThemeMode) => void;
  cycleMode: () => void;
}
const ThemeContext = createContext<ThemeContextValue | null>(null);
export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const systemScheme = useColorScheme();
  const [mode, setModeState] = useState<ThemeMode>("dark");
  useEffect(() => {
    SecureStore.getItemAsync(THEME_KEY).then((stored) => {
      if (stored === "light" || stored === "dark" || stored === "system") {
        setModeState(stored);
      }
    });
  }, []);
  const setMode = useCallback((m: ThemeMode) => {
    setModeState(m);
    SecureStore.setItemAsync(THEME_KEY, m);
  }, []);
  const cycleMode = useCallback(() => {
    setModeState((prev) => {
      const next = prev === "dark" ? "light" : prev === "light" ? "system" : "dark";
      SecureStore.setItemAsync(THEME_KEY, next);
      return next;
    });
  }, []);
  const isDark = mode === "dark" || (mode === "system" && systemScheme !== "light");
  const colors = isDark ? darkColors : lightColors;
  return (
    <ThemeContext.Provider value={{ mode, isDark, colors, setMode, cycleMode }}>
      {children}
    </ThemeContext.Provider>
  );
}
export function useTheme() {
  const ctx = useContext(ThemeContext);
  if (!ctx) throw new Error("useTheme must be used within ThemeProvider");
  return ctx;
}