feat: add theme system with light/dark mode support

- Add ThemeStore (Zustand) for reactive theme switching
- Add Themes.tsx with THEMES object (defaultLight, defaultDark)
- Add Settings screen with theme switcher and logout button
- Add BaseButton component for reusable themed buttons
- Migrate all components from static currentTheme to useThemeStore()
- Add shadowColor to theme (iOS only, Android uses elevation)
- All text elements now use theme colors (textPrimary, textSecondary, etc.)
- Update tab navigation to include Settings tab
- Move logout from Header to Settings screen
This commit is contained in:
2026-01-24 16:57:33 +01:00
parent 1dbca79edd
commit 43d40b46d7
23 changed files with 450 additions and 236 deletions

View File

@@ -7,7 +7,7 @@ import {
Platform,
Keyboard,
} from "react-native";
import currentTheme from "../../Themes";
import { useThemeStore } from "../../stores/ThemeStore";
import React, { useState, useRef, useEffect } from "react";
import Header from "../../components/Header";
import BaseBackground from "../../components/BaseBackground";
@@ -234,20 +234,21 @@ const Chat = () => {
};
const ChatHeader = () => {
const { theme } = useThemeStore();
return (
<Header className="flex flex-row items-center">
<View
className="ml-3 w-12 h-12 rounded-3xl border border-solid"
style={{
backgroundColor: currentTheme.placeholderBg,
borderColor: currentTheme.primeFg,
backgroundColor: theme.placeholderBg,
borderColor: theme.primeFg,
}}
></View>
<Text className="text-lg pl-3">CalChat</Text>
<Text className="text-lg pl-3" style={{ color: theme.textPrimary }}>CalChat</Text>
<View
className="h-2 bg-black"
style={{
shadowColor: "#000",
shadowColor: theme.shadowColor,
shadowOffset: {
width: 0,
height: 5,
@@ -266,6 +267,7 @@ const MIN_INPUT_HEIGHT = 40;
const MAX_INPUT_HEIGHT = 150;
const ChatInput = ({ onSend }: ChatInputProps) => {
const { theme } = useThemeStore();
const [text, setText] = useState("");
const handleSend = () => {
@@ -280,7 +282,7 @@ const ChatInput = ({ onSend }: ChatInputProps) => {
<TextInput
className="flex-1 border border-solid rounded-2xl px-3 py-2 mr-2"
style={{
backgroundColor: currentTheme.messageBorderBg,
backgroundColor: theme.messageBorderBg,
minHeight: MIN_INPUT_HEIGHT,
maxHeight: MAX_INPUT_HEIGHT,
textAlignVertical: "top",
@@ -288,14 +290,14 @@ const ChatInput = ({ onSend }: ChatInputProps) => {
onChangeText={setText}
value={text}
placeholder="Nachricht..."
placeholderTextColor="#999"
placeholderTextColor={theme.textMuted}
multiline
/>
<Pressable onPress={handleSend}>
<View
className="w-10 h-10 rounded-full items-center justify-center"
style={{
backgroundColor: currentTheme.placeholderBg,
backgroundColor: theme.placeholderBg,
}}
/>
</Pressable>
@@ -310,6 +312,7 @@ const ChatMessage = ({
onConfirm,
onReject,
}: ChatMessageProps) => {
const { theme } = useThemeStore();
const [currentIndex, setCurrentIndex] = useState(0);
const hasProposals = proposedChanges && proposedChanges.length > 0;
@@ -333,7 +336,7 @@ const ChatMessage = ({
minWidth: hasProposals ? "75%" : undefined,
}}
>
<Text className="p-2">{content}</Text>
<Text className="p-2" style={{ color: theme.textPrimary }}>{content}</Text>
{hasProposals && currentProposal && onConfirm && onReject && (
<View>
@@ -350,7 +353,7 @@ const ChatMessage = ({
<Ionicons
name="chevron-back"
size={24}
color={currentTheme.primeFg}
color={theme.primeFg}
/>
</Pressable>
)}
@@ -375,7 +378,7 @@ const ChatMessage = ({
<Ionicons
name="chevron-forward"
size={24}
color={currentTheme.primeFg}
color={theme.primeFg}
/>
</Pressable>
)}
@@ -385,7 +388,7 @@ const ChatMessage = ({
{hasMultiple && (
<Text
className="text-center text-sm pb-2"
style={{ color: currentTheme.textSecondary || "#666" }}
style={{ color: theme.textSecondary || "#666" }}
>
Event {currentIndex + 1} von {proposedChanges.length}
</Text>