import React from 'react'; import { YStack, XStack } from '@tamagui/stacks'; import { SizableText as Text } from '@tamagui/text'; import { Pressable } from '@tamagui/react-native-web-lite'; import { ADMIN_GRADIENTS, useAdminTheme } from '../theme'; import { withAlpha } from './colors'; export function MobileCard({ children, className, style, ...rest }: React.ComponentProps) { const { surface, border, shadow, glassSurface, glassBorder, glassShadow } = useAdminTheme(); return ( {children} ); } export function PillBadge({ tone = 'muted', children, }: { tone?: 'success' | 'warning' | 'danger' | 'muted'; children: React.ReactNode; }) { const { theme } = useAdminTheme(); const palette: Record = { success: { bg: String(theme.backgroundStrong?.val ?? '#ecfdf3'), text: String(theme.green10?.val ?? '#047857'), border: String(theme.green6?.val ?? '#bbf7d0'), }, warning: { bg: String(theme.yellow3?.val ?? '#fffbeb'), text: String(theme.yellow11?.val ?? '#92400e'), border: String(theme.yellow6?.val ?? '#fef3c7'), }, danger: { bg: String(theme.red3?.val ?? '#FEE2E2'), text: String(theme.red11?.val ?? '#B91C1C'), border: String(theme.red6?.val ?? '#FCA5A5'), }, muted: { bg: String(theme.gray3?.val ?? '#f3f4f6'), text: String(theme.gray11?.val ?? '#374151'), border: String(theme.gray6?.val ?? '#e5e7eb'), }, }; const colors = palette[tone] ?? palette.muted; return ( {children} ); } export function CTAButton({ label, onPress, tone = 'primary', fullWidth = true, disabled = false, loading = false, style, iconLeft, iconRight, }: { label: string; onPress: () => void; tone?: 'primary' | 'ghost' | 'danger'; fullWidth?: boolean; disabled?: boolean; loading?: boolean; style?: any; iconLeft?: React.ReactNode; iconRight?: React.ReactNode; }) { const { primary, surface, border, text, danger, glassSurfaceStrong } = useAdminTheme(); const isPrimary = tone === 'primary'; const isDanger = tone === 'danger'; const isDisabled = disabled || loading; const backgroundColor = isDanger ? danger : isPrimary ? primary : glassSurfaceStrong ?? surface; const borderColor = isPrimary || isDanger ? 'transparent' : border; const labelColor = isPrimary || isDanger ? 'white' : text; const primaryStyle = isPrimary ? { boxShadow: `0 18px 28px ${withAlpha(primary, 0.4)}`, } : undefined; return ( {iconLeft} {label} {iconRight} ); } export function KpiTile({ icon: IconCmp, label, value, note, }: { icon: React.ComponentType<{ size?: number; color?: string }>; label: string; value: string | number; note?: string; }) { const { accentSoft, primary, text } = useAdminTheme(); return ( {label} {value} {note ? ( {note} ) : null} ); } export function SkeletonCard({ height = 80 }: { height?: number }) { return ( ); } export function ActionTile({ icon: IconCmp, label, note, noteTone = 'muted', color, onPress, disabled = false, variant = 'grid', delayMs = 0, }: { icon: React.ComponentType<{ size?: number; color?: string }>; label: string; note?: string; noteTone?: 'warning' | 'muted'; color: string; onPress?: () => void; disabled?: boolean; variant?: 'grid' | 'cluster'; delayMs?: number; }) { const { textStrong, glassSurface, muted, warningText } = useAdminTheme(); const noteColor = noteTone === 'warning' ? warningText : muted; const isCluster = variant === 'cluster'; const backgroundColor = withAlpha(color, 0.12); const borderColor = withAlpha(color, 0.4); const shadowColor = withAlpha(color, 0.35); const iconShadow = withAlpha(color, 0.5); const tileStyle = { ...(delayMs ? { animationDelay: `${delayMs}ms` } : {}), backgroundImage: `linear-gradient(135deg, ${backgroundColor}, ${withAlpha(color, 0.08)})`, boxShadow: isCluster ? `0 12px 18px ${shadowColor}` : `0 20px 30px ${shadowColor}`, }; return ( {label} {note ? ( {note} ) : null} ); } export function FloatingActionButton({ onPress, label, icon: IconCmp, }: { onPress: () => void; label: string; icon: React.ComponentType<{ size?: number; color?: string }>; }) { const { primary, shadow } = useAdminTheme(); const [pressed, setPressed] = React.useState(false); return ( setPressed(true)} onPressOut={() => setPressed(false)} onPointerLeave={() => setPressed(false)} style={{ position: 'fixed', right: 18, bottom: 'calc(env(safe-area-inset-bottom, 0px) + 96px)', zIndex: 60, transform: pressed ? 'scale(0.96)' : 'scale(1)', opacity: pressed ? 0.92 : 1, transition: 'transform 140ms ease, opacity 140ms ease', }} aria-label={label} > {label} ); }