refactor: add CardBase and ModalBase components

- Add CardBase: reusable card with header, content, footer
  - Configurable via props: padding, border, text size, background
- Add ModalBase: modal wrapper using CardBase internally
  - Provides backdrop, click-outside-to-close, Android back button
- Refactor EventCardBase to use CardBase
- Refactor DeleteEventModal to use ModalBase
- Refactor EventOverlay (calendar.tsx) to use ModalBase
- Update CLAUDE.md with component documentation
This commit is contained in:
2026-01-25 21:50:19 +01:00
parent 2b999d9b0f
commit 726334c155
7 changed files with 366 additions and 265 deletions

View File

@@ -2,6 +2,7 @@ import { View, Text } from "react-native";
import { Feather } from "@expo/vector-icons";
import { ReactNode } from "react";
import { useThemeStore } from "../stores/ThemeStore";
import { CardBase } from "./CardBase";
type EventCardBaseProps = {
className?: string;
@@ -61,84 +62,59 @@ export const EventCardBase = ({
children,
}: EventCardBaseProps) => {
const { theme } = useThemeStore();
return (
<View
className={`rounded-xl overflow-hidden ${className}`}
style={{ borderWidth: 2, borderColor: theme.borderPrimary }}
>
{/* Header with title */}
<View
className="px-3 py-2"
style={{
backgroundColor: theme.chatBot,
borderBottomWidth: 2,
borderBottomColor: theme.borderPrimary,
}}
>
<Text
className="font-bold text-base"
style={{ color: theme.textPrimary }}
>
{title}
<CardBase title={title} className={className} borderWidth={2}>
{/* Date */}
<View className="flex-row items-center mb-1">
<Feather
name="calendar"
size={16}
color={theme.textPrimary}
style={{ marginRight: 8 }}
/>
<Text style={{ color: theme.textPrimary }}>
{formatDate(startTime)}
</Text>
</View>
{/* Content */}
<View
className="px-3 py-2"
style={{ backgroundColor: theme.secondaryBg }}
>
{/* Date */}
<View className="flex-row items-center mb-1">
<Feather
name="calendar"
size={16}
color={theme.textPrimary}
style={{ marginRight: 8 }}
/>
<Text style={{ color: theme.textPrimary }}>
{formatDate(startTime)}
</Text>
</View>
{/* Time with duration */}
<View className="flex-row items-center mb-1">
<Feather
name="clock"
size={16}
color={theme.textPrimary}
style={{ marginRight: 8 }}
/>
<Text style={{ color: theme.textPrimary }}>
{formatTime(startTime)} - {formatTime(endTime)} (
{formatDuration(startTime, endTime)})
</Text>
</View>
{/* Recurring indicator */}
{isRecurring && (
<View className="flex-row items-center mb-1">
<Feather
name="repeat"
size={16}
color={theme.textPrimary}
style={{ marginRight: 8 }}
/>
<Text style={{ color: theme.textPrimary }}>Wiederkehrend</Text>
</View>
)}
{/* Description */}
{description && (
<Text style={{ color: theme.textPrimary }} className="text-sm mt-1">
{description}
</Text>
)}
{/* Action buttons slot */}
{children}
{/* Time with duration */}
<View className="flex-row items-center mb-1">
<Feather
name="clock"
size={16}
color={theme.textPrimary}
style={{ marginRight: 8 }}
/>
<Text style={{ color: theme.textPrimary }}>
{formatTime(startTime)} - {formatTime(endTime)} (
{formatDuration(startTime, endTime)})
</Text>
</View>
</View>
{/* Recurring indicator */}
{isRecurring && (
<View className="flex-row items-center mb-1">
<Feather
name="repeat"
size={16}
color={theme.textPrimary}
style={{ marginRight: 8 }}
/>
<Text style={{ color: theme.textPrimary }}>Wiederkehrend</Text>
</View>
)}
{/* Description */}
{description && (
<Text style={{ color: theme.textPrimary }} className="text-sm mt-1">
{description}
</Text>
)}
{/* Action buttons slot */}
{children}
</CardBase>
);
};