From e32d4395a3f92e22717e389c1fafda297b0e2e30 Mon Sep 17 00:00:00 2001 From: Nawaz Dhandala Date: Fri, 13 Feb 2026 21:24:31 +0000 Subject: [PATCH] refactor: update UI components for consistency and improved theming - Refactored IncidentsScreen to use theme colors for backgrounds and text. - Adjusted font sizes and styles across various components for better readability. - Updated SettingsScreen to enhance layout and visual hierarchy, including removing GlassCard and using View components with theme colors. - Modified LoginScreen and ServerUrlScreen to improve input field styling and overall layout. - Revised color tokens in theme/colors.ts for better contrast and accessibility. - Improved button labels for clarity and consistency. --- MobileApp/global.css | 154 +++++------ MobileApp/src/components/AddNoteModal.tsx | 38 +-- MobileApp/src/components/AlertCard.tsx | 158 ++++++------ MobileApp/src/components/EmptyState.tsx | 41 +-- MobileApp/src/components/EpisodeCard.tsx | 154 ++++++----- MobileApp/src/components/FeedTimeline.tsx | 30 +-- MobileApp/src/components/GlassCard.tsx | 5 - MobileApp/src/components/GradientButton.tsx | 32 +-- MobileApp/src/components/IncidentCard.tsx | 168 ++++++------ MobileApp/src/components/NotesSection.tsx | 68 +++-- MobileApp/src/components/ProjectBadge.tsx | 10 +- MobileApp/src/components/SectionHeader.tsx | 12 +- MobileApp/src/components/SegmentedControl.tsx | 10 +- MobileApp/src/components/SkeletonCard.tsx | 218 ++++++++-------- MobileApp/src/navigation/MainTabNavigator.tsx | 38 +-- MobileApp/src/screens/AlertDetailScreen.tsx | 165 ++++++------ .../src/screens/AlertEpisodeDetailScreen.tsx | 207 +++++---------- MobileApp/src/screens/AlertsScreen.tsx | 32 ++- MobileApp/src/screens/BiometricLockScreen.tsx | 44 ++-- MobileApp/src/screens/HomeScreen.tsx | 172 ++++++------ .../src/screens/IncidentDetailScreen.tsx | 177 +++++++------ .../screens/IncidentEpisodeDetailScreen.tsx | 210 ++++++--------- MobileApp/src/screens/IncidentsScreen.tsx | 32 ++- MobileApp/src/screens/SettingsScreen.tsx | 220 ++++++++++------ MobileApp/src/screens/auth/LoginScreen.tsx | 85 +++--- .../src/screens/auth/ServerUrlScreen.tsx | 68 +++-- MobileApp/src/theme/colors.ts | 244 +++++++++--------- 27 files changed, 1391 insertions(+), 1401 deletions(-) diff --git a/MobileApp/global.css b/MobileApp/global.css index 5e5eaccc47..ed7b19ee9b 100644 --- a/MobileApp/global.css +++ b/MobileApp/global.css @@ -4,86 +4,86 @@ :root { --color-bg-primary: #FFFFFF; - --color-bg-secondary: #F8F8FA; - --color-bg-tertiary: #F0F0F2; + --color-bg-secondary: #F9FAFB; + --color-bg-tertiary: #F3F4F6; --color-bg-elevated: #FFFFFF; - --color-card-accent: rgba(0, 0, 0, 0.04); - --color-bg-glass: rgba(255, 255, 255, 0.85); - --color-icon-bg: rgba(0, 0, 0, 0.05); - --color-border-default: #E5E5EA; - --color-border-subtle: #F0F0F2; - --color-text-primary: #111111; - --color-text-secondary: #6B6B6B; - --color-text-tertiary: #9A9A9A; + --color-card-accent: rgba(0, 0, 0, 0.02); + --color-bg-glass: rgba(255, 255, 255, 0.80); + --color-icon-bg: rgba(99, 102, 241, 0.08); + --color-border-default: #E5E7EB; + --color-border-subtle: #F3F4F6; + --color-text-primary: #111827; + --color-text-secondary: #6B7280; + --color-text-tertiary: #9CA3AF; --color-text-inverse: #FFFFFF; - --color-severity-critical: #CF222E; - --color-severity-critical-bg: #CF222E1A; - --color-severity-major: #BC4C00; - --color-severity-major-bg: #BC4C001A; - --color-severity-minor: #9A6700; - --color-severity-minor-bg: #9A67001A; - --color-severity-warning: #BF8700; - --color-severity-warning-bg: #BF87001A; - --color-severity-info: #0969DA; - --color-severity-info-bg: #0969DA1A; - --color-state-created: #CF222E; - --color-state-acknowledged: #9A6700; - --color-state-resolved: #1A7F37; - --color-state-investigating: #BC4C00; - --color-state-muted: #8C959F; - --color-oncall-active: #1A7F37; - --color-oncall-active-bg: #1A7F371A; - --color-oncall-inactive: #8C959F; - --color-oncall-inactive-bg: #8C959F1A; - --color-action-primary: #1A1A1A; - --color-action-primary-pressed: #333333; - --color-action-destructive: #CF222E; - --color-action-destructive-pressed: #A40E26; - --color-status-success: #1A7F37; - --color-status-success-bg: #1A7F371A; - --color-status-error: #CF222E; - --color-status-error-bg: #CF222E1A; + --color-severity-critical: #DC2626; + --color-severity-critical-bg: rgba(220, 38, 38, 0.08); + --color-severity-major: #EA580C; + --color-severity-major-bg: rgba(234, 88, 12, 0.08); + --color-severity-minor: #CA8A04; + --color-severity-minor-bg: rgba(202, 138, 4, 0.08); + --color-severity-warning: #D97706; + --color-severity-warning-bg: rgba(217, 119, 6, 0.08); + --color-severity-info: #2563EB; + --color-severity-info-bg: rgba(37, 99, 235, 0.08); + --color-state-created: #DC2626; + --color-state-acknowledged: #D97706; + --color-state-resolved: #16A34A; + --color-state-investigating: #EA580C; + --color-state-muted: #9CA3AF; + --color-oncall-active: #16A34A; + --color-oncall-active-bg: rgba(22, 163, 74, 0.08); + --color-oncall-inactive: #9CA3AF; + --color-oncall-inactive-bg: rgba(156, 163, 175, 0.08); + --color-action-primary: #4F46E5; + --color-action-primary-pressed: #4338CA; + --color-action-destructive: #DC2626; + --color-action-destructive-pressed: #B91C1C; + --color-status-success: #16A34A; + --color-status-success-bg: rgba(22, 163, 74, 0.08); + --color-status-error: #DC2626; + --color-status-error-bg: rgba(220, 38, 38, 0.08); } .dark { - --color-bg-primary: #000000; - --color-bg-secondary: #0A0A0A; - --color-bg-tertiary: #161616; - --color-bg-elevated: #0F0F0F; - --color-card-accent: rgba(255, 255, 255, 0.07); - --color-bg-glass: rgba(255, 255, 255, 0.05); - --color-icon-bg: rgba(255, 255, 255, 0.07); - --color-border-default: #1C1C1E; - --color-border-subtle: #141414; - --color-text-primary: #F0F0F0; - --color-text-secondary: #8E8E93; - --color-text-tertiary: #636366; - --color-text-inverse: #000000; - --color-severity-critical: #F85149; - --color-severity-critical-bg: #F8514926; - --color-severity-major: #F0883E; - --color-severity-major-bg: #F0883E26; - --color-severity-minor: #D29922; - --color-severity-minor-bg: #D2992226; - --color-severity-warning: #E3B341; - --color-severity-warning-bg: #E3B34126; - --color-severity-info: #58A6FF; - --color-severity-info-bg: #58A6FF26; - --color-state-created: #F85149; - --color-state-acknowledged: #D29922; - --color-state-resolved: #3FB950; - --color-state-investigating: #F0883E; - --color-state-muted: #636366; - --color-oncall-active: #3FB950; - --color-oncall-active-bg: #3FB95026; - --color-oncall-inactive: #636366; - --color-oncall-inactive-bg: #63636626; - --color-action-primary: #FFFFFF; - --color-action-primary-pressed: #D4D4D4; - --color-action-destructive: #F85149; - --color-action-destructive-pressed: #DA3633; - --color-status-success: #3FB950; - --color-status-success-bg: #3FB95026; - --color-status-error: #F85149; - --color-status-error-bg: #F8514926; + --color-bg-primary: #09090B; + --color-bg-secondary: #0F0F12; + --color-bg-tertiary: #18181F; + --color-bg-elevated: #141418; + --color-card-accent: rgba(255, 255, 255, 0.04); + --color-bg-glass: rgba(255, 255, 255, 0.03); + --color-icon-bg: rgba(99, 102, 241, 0.12); + --color-border-default: rgba(255, 255, 255, 0.06); + --color-border-subtle: rgba(255, 255, 255, 0.04); + --color-text-primary: #FAFAFA; + --color-text-secondary: #A1A1AA; + --color-text-tertiary: #52525B; + --color-text-inverse: #FFFFFF; + --color-severity-critical: #EF4444; + --color-severity-critical-bg: rgba(239, 68, 68, 0.12); + --color-severity-major: #F97316; + --color-severity-major-bg: rgba(249, 115, 22, 0.12); + --color-severity-minor: #EAB308; + --color-severity-minor-bg: rgba(234, 179, 8, 0.12); + --color-severity-warning: #F59E0B; + --color-severity-warning-bg: rgba(245, 158, 11, 0.12); + --color-severity-info: #3B82F6; + --color-severity-info-bg: rgba(59, 130, 246, 0.12); + --color-state-created: #EF4444; + --color-state-acknowledged: #F59E0B; + --color-state-resolved: #22C55E; + --color-state-investigating: #F97316; + --color-state-muted: #52525B; + --color-oncall-active: #22C55E; + --color-oncall-active-bg: rgba(34, 197, 94, 0.12); + --color-oncall-inactive: #52525B; + --color-oncall-inactive-bg: rgba(82, 82, 91, 0.12); + --color-action-primary: #6366F1; + --color-action-primary-pressed: #4F46E5; + --color-action-destructive: #EF4444; + --color-action-destructive-pressed: #DC2626; + --color-status-success: #22C55E; + --color-status-success-bg: rgba(34, 197, 94, 0.12); + --color-status-error: #EF4444; + --color-status-error-bg: rgba(239, 68, 68, 0.12); } diff --git a/MobileApp/src/components/AddNoteModal.tsx b/MobileApp/src/components/AddNoteModal.tsx index a509b06060..4ef2ebd787 100644 --- a/MobileApp/src/components/AddNoteModal.tsx +++ b/MobileApp/src/components/AddNoteModal.tsx @@ -54,7 +54,7 @@ export default function AddNoteModal({ behavior={Platform.OS === "ios" ? "padding" : "height"} > - {/* Drag Handle */} Add Note - + Cancel diff --git a/MobileApp/src/components/AlertCard.tsx b/MobileApp/src/components/AlertCard.tsx index 7fac90e065..e17058f9af 100644 --- a/MobileApp/src/components/AlertCard.tsx +++ b/MobileApp/src/components/AlertCard.tsx @@ -1,12 +1,10 @@ import React from "react"; import { View, Text, TouchableOpacity } from "react-native"; import { Ionicons } from "@expo/vector-icons"; -import { LinearGradient } from "expo-linear-gradient"; import { useTheme } from "../theme"; import { rgbToHex } from "../utils/color"; import { formatRelativeTime } from "../utils/date"; import ProjectBadge from "./ProjectBadge"; -import GlassCard from "./GlassCard"; import type { AlertItem } from "../api/types"; interface AlertCardProps { @@ -38,100 +36,114 @@ export default function AlertCard({ - - - - - {projectName ? ( - + + + + + + {projectName ? ( - - ) : null} - - - - {alert.alertNumberWithPrefix || `#${alert.alertNumber}`} - - - - {timeString} + {alert.alertNumberWithPrefix || `#${alert.alertNumber}`} - - {alert.title} + {timeString} + - - {alert.currentAlertState ? ( + + {alert.title} + + + + {alert.currentAlertState ? ( + - - - {alert.currentAlertState.name} - - - ) : null} - - {alert.alertSeverity ? ( - - - {alert.alertSeverity.name} - - - ) : null} - - - {alert.monitor ? ( - - - {alert.monitor.name} + {alert.currentAlertState.name} + + + ) : null} + + {alert.alertSeverity ? ( + + + {alert.alertSeverity.name} ) : null} + + {alert.monitor ? ( + + + + {alert.monitor.name} + + + ) : null} - + ); } diff --git a/MobileApp/src/components/EmptyState.tsx b/MobileApp/src/components/EmptyState.tsx index 4243b87b82..f68ea683d3 100644 --- a/MobileApp/src/components/EmptyState.tsx +++ b/MobileApp/src/components/EmptyState.tsx @@ -33,49 +33,34 @@ export default function EmptyState({ return ( - {/* Outer gradient glow ring */} - - + - {/* Inner icon container */} - - - {title} {subtitle ? ( - + {subtitle} ) : null} {actionLabel && onAction ? ( - + ) : null} diff --git a/MobileApp/src/components/EpisodeCard.tsx b/MobileApp/src/components/EpisodeCard.tsx index 9cb6e8be69..ddfbb29d58 100644 --- a/MobileApp/src/components/EpisodeCard.tsx +++ b/MobileApp/src/components/EpisodeCard.tsx @@ -1,11 +1,9 @@ import React from "react"; import { View, Text, TouchableOpacity } from "react-native"; -import { LinearGradient } from "expo-linear-gradient"; import { useTheme } from "../theme"; import { rgbToHex } from "../utils/color"; import { formatRelativeTime } from "../utils/date"; import ProjectBadge from "./ProjectBadge"; -import GlassCard from "./GlassCard"; import type { IncidentEpisodeItem, AlertEpisodeItem, @@ -65,94 +63,108 @@ export default function EpisodeCard( - - - - - {projectName ? ( - + + + + + + {projectName ? ( - - ) : null} - - - - {episode.episodeNumberWithPrefix || - `#${episode.episodeNumber}`} - - - - {timeString} + {episode.episodeNumberWithPrefix || + `#${episode.episodeNumber}`} - - {episode.title} + {timeString} + - - {state ? ( - - - - {state.name} - - - ) : null} + + {episode.title} + - {severity ? ( + + {state ? ( + + - - {severity.name} - - - ) : null} + {state.name} + + + ) : null} - {childCount > 0 ? ( - + - - {childCount} {type === "incident" ? "incident" : "alert"} - {childCount !== 1 ? "s" : ""} - - - ) : null} - + {severity.name} + + + ) : null} + + {childCount > 0 ? ( + + + {childCount} {type === "incident" ? "incident" : "alert"} + {childCount !== 1 ? "s" : ""} + + + ) : null} - + ); } diff --git a/MobileApp/src/components/FeedTimeline.tsx b/MobileApp/src/components/FeedTimeline.tsx index 6d27f16372..6bbc76f5b8 100644 --- a/MobileApp/src/components/FeedTimeline.tsx +++ b/MobileApp/src/components/FeedTimeline.tsx @@ -30,7 +30,7 @@ export default function FeedTimeline({ {feed.map((entry: FeedItem, index: number) => { const entryColor: string = entry.displayColor ? rgbToHex(entry.displayColor) - : theme.colors.textTertiary; + : theme.colors.actionPrimary; const isLast: boolean = index === feed.length - 1; const timeString: string = formatDateTime( entry.postedAt || entry.createdAt, @@ -42,42 +42,40 @@ export default function FeedTimeline({ return ( - {/* Timeline connector */} {!isLast ? ( ) : null} - {/* Content */} - + {mainText} {moreText ? ( {moreText} ) : null} - + {timeString} diff --git a/MobileApp/src/components/GlassCard.tsx b/MobileApp/src/components/GlassCard.tsx index 56b6c1fccd..614d460a11 100644 --- a/MobileApp/src/components/GlassCard.tsx +++ b/MobileApp/src/components/GlassCard.tsx @@ -25,11 +25,6 @@ export default function GlassCard({ : theme.colors.backgroundGlass, borderWidth: 1, borderColor: theme.colors.borderGlass, - shadowColor: "#000000", - shadowOpacity: theme.isDark ? 0.3 : 0.08, - shadowOffset: { width: 0, height: 2 }, - shadowRadius: 12, - elevation: 3, }, style, ]} diff --git a/MobileApp/src/components/GradientButton.tsx b/MobileApp/src/components/GradientButton.tsx index 77a53e197d..3ab96b5a85 100644 --- a/MobileApp/src/components/GradientButton.tsx +++ b/MobileApp/src/components/GradientButton.tsx @@ -34,13 +34,13 @@ export default function GradientButton({ if (variant === "secondary") { return ( {loading ? ( - + ) : ( <> {icon ? ( ) : null} {label} @@ -76,12 +76,12 @@ export default function GradientButton({ return ( {loading ? ( - + ) : ( <> {icon ? ( ) : null} {label} diff --git a/MobileApp/src/components/IncidentCard.tsx b/MobileApp/src/components/IncidentCard.tsx index 1fe3dfa508..7d27ee4814 100644 --- a/MobileApp/src/components/IncidentCard.tsx +++ b/MobileApp/src/components/IncidentCard.tsx @@ -1,12 +1,10 @@ import React from "react"; import { View, Text, TouchableOpacity } from "react-native"; import { Ionicons } from "@expo/vector-icons"; -import { LinearGradient } from "expo-linear-gradient"; import { useTheme } from "../theme"; import { rgbToHex } from "../utils/color"; import { formatRelativeTime } from "../utils/date"; import ProjectBadge from "./ProjectBadge"; -import GlassCard from "./GlassCard"; import type { IncidentItem, NamedEntity } from "../api/types"; interface IncidentCardProps { @@ -41,105 +39,119 @@ export default function IncidentCard({ - - - - - {projectName ? ( - + + + + + + {projectName ? ( - - ) : null} - - - - {incident.incidentNumberWithPrefix || - `#${incident.incidentNumber}`} - - - - {timeString} + {incident.incidentNumberWithPrefix || + `#${incident.incidentNumber}`} - - {incident.title} + {timeString} + - - {incident.currentIncidentState ? ( + + {incident.title} + + + + {incident.currentIncidentState ? ( + - - - {incident.currentIncidentState.name} - - - ) : null} - - {incident.incidentSeverity ? ( - - - {incident.incidentSeverity.name} - - - ) : null} - - - {monitorCount > 0 ? ( - - - {incident.monitors - .map((m: NamedEntity) => { - return m.name; - }) - .join(", ")} + {incident.currentIncidentState.name} + + + ) : null} + + {incident.incidentSeverity ? ( + + + {incident.incidentSeverity.name} ) : null} + + {monitorCount > 0 ? ( + + + + {incident.monitors + .map((m: NamedEntity) => { + return m.name; + }) + .join(", ")} + + + ) : null} - + ); } diff --git a/MobileApp/src/components/NotesSection.tsx b/MobileApp/src/components/NotesSection.tsx index 3db7ac5826..5f6d98f6a4 100644 --- a/MobileApp/src/components/NotesSection.tsx +++ b/MobileApp/src/components/NotesSection.tsx @@ -4,7 +4,6 @@ import { Ionicons } from "@expo/vector-icons"; import { LinearGradient } from "expo-linear-gradient"; import { useTheme } from "../theme"; import { formatDateTime } from "../utils/date"; -import GlassCard from "./GlassCard"; import type { NoteItem } from "../api/types"; interface NotesSectionProps { @@ -24,11 +23,14 @@ export default function NotesSection({ - + Internal Notes @@ -46,17 +48,17 @@ export default function NotesSection({ ]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 1 }} - className="flex-row items-center px-3.5 py-2" + className="flex-row items-center px-3 py-1.5" > Add Note @@ -67,42 +69,60 @@ export default function NotesSection({ {notes && notes.length > 0 ? notes.map((note: NoteItem) => { return ( - - + {note.note} {note.createdByUser ? ( - + {note.createdByUser.name} ) : null} - + {formatDateTime(note.createdAt)} - + ); }) : null} {notes && notes.length === 0 ? ( - - - - No notes yet. - - - + + + No notes yet. + + ) : null} ); diff --git a/MobileApp/src/components/ProjectBadge.tsx b/MobileApp/src/components/ProjectBadge.tsx index 7513f3ea56..4140e88822 100644 --- a/MobileApp/src/components/ProjectBadge.tsx +++ b/MobileApp/src/components/ProjectBadge.tsx @@ -1,5 +1,6 @@ import React from "react"; import { View, Text } from "react-native"; +import { useTheme } from "../theme"; interface ProjectBadgeProps { name: string; @@ -10,13 +11,18 @@ export default function ProjectBadge({ name, color, }: ProjectBadgeProps): React.JSX.Element { + const { theme } = useTheme(); return ( - + {name} diff --git a/MobileApp/src/components/SectionHeader.tsx b/MobileApp/src/components/SectionHeader.tsx index 9c7ac3f271..c490c3ecf3 100644 --- a/MobileApp/src/components/SectionHeader.tsx +++ b/MobileApp/src/components/SectionHeader.tsx @@ -17,11 +17,17 @@ export default function SectionHeader({ - + {title} diff --git a/MobileApp/src/components/SegmentedControl.tsx b/MobileApp/src/components/SegmentedControl.tsx index 730ae7c45e..a2123b3af6 100644 --- a/MobileApp/src/components/SegmentedControl.tsx +++ b/MobileApp/src/components/SegmentedControl.tsx @@ -24,7 +24,7 @@ export default function SegmentedControl({ return ( {segments.map((segment: Segment) => { const isActive: boolean = segment.key === selected; @@ -35,8 +35,8 @@ export default function SegmentedControl({ style={ isActive ? { - shadowColor: "#000000", - shadowOpacity: theme.isDark ? 0.4 : 0.15, + shadowColor: theme.colors.accentGradientMid, + shadowOpacity: 0.3, shadowOffset: { width: 0, height: 2 }, shadowRadius: 6, elevation: 3, @@ -68,9 +68,7 @@ export default function SegmentedControl({ {segment.label} diff --git a/MobileApp/src/components/SkeletonCard.tsx b/MobileApp/src/components/SkeletonCard.tsx index fe1eb57d36..b649729dfd 100644 --- a/MobileApp/src/components/SkeletonCard.tsx +++ b/MobileApp/src/components/SkeletonCard.tsx @@ -63,33 +63,33 @@ export default function SkeletonCard({ style={{ backgroundColor: theme.colors.backgroundElevated, borderWidth: 1, - borderColor: theme.colors.borderSubtle, + borderColor: theme.colors.borderGlass, opacity, }} accessibilityLabel="Loading content" accessibilityRole="progressbar" > - - - - - - - + + + + + ); @@ -103,55 +103,67 @@ export default function SkeletonCard({ accessibilityLabel="Loading content" accessibilityRole="progressbar" > - {/* Header area */} - - - - - - - - - - {/* Details card */} - - {Array.from({ length: 3 }).map((_: unknown, index: number) => { - return ( - - - - - ); - })} + + + + + + + + + + + + + {Array.from({ length: 3 }).map((_: unknown, index: number) => { + return ( + + + + + ); + })} + ); @@ -163,57 +175,57 @@ export default function SkeletonCard({ style={{ backgroundColor: theme.colors.backgroundElevated, borderWidth: 1, - borderColor: theme.colors.borderSubtle, + borderColor: theme.colors.borderGlass, opacity, }} accessibilityLabel="Loading content" accessibilityRole="progressbar" > - - - - - - - + + + + - - - - - {Array.from({ length: Math.max(lines - 1, 1) }).map( - (_: unknown, index: number) => { - return ( - - ); - }, - )} + + + + + + {Array.from({ length: Math.max(lines - 1, 1) }).map( + (_: unknown, index: number) => { + return ( + + ); + }, + )} ); diff --git a/MobileApp/src/navigation/MainTabNavigator.tsx b/MobileApp/src/navigation/MainTabNavigator.tsx index eef449b787..f7953b04d9 100644 --- a/MobileApp/src/navigation/MainTabNavigator.tsx +++ b/MobileApp/src/navigation/MainTabNavigator.tsx @@ -1,5 +1,5 @@ import React from "react"; -import { View, StyleSheet, Platform } from "react-native"; +import { View, Platform } from "react-native"; import { createBottomTabNavigator } from "@react-navigation/bottom-tabs"; import { Ionicons } from "@expo/vector-icons"; import { MainTabParamList } from "./types"; @@ -27,17 +27,12 @@ function TabIcon({ }): React.JSX.Element { return ( - + {focused ? ( ) : null} @@ -53,42 +48,23 @@ export default function MainTabNavigator(): React.JSX.Element { screenOptions={{ headerStyle: { backgroundColor: theme.colors.backgroundPrimary, - borderBottomWidth: StyleSheet.hairlineWidth, + borderBottomWidth: 1, borderBottomColor: theme.colors.borderSubtle, - ...Platform.select({ - ios: { - shadowColor: "#000", - shadowOpacity: 0.04, - shadowOffset: { width: 0, height: 1 }, - shadowRadius: 6, - }, - default: { elevation: 2 }, - }), }, headerShadowVisible: false, headerTintColor: theme.colors.textPrimary, headerTitleStyle: { fontWeight: "700", + fontSize: 17, letterSpacing: -0.3, }, tabBarStyle: { - backgroundColor: theme.isDark - ? theme.colors.backgroundGlass - : theme.colors.backgroundPrimary, - borderTopColor: theme.colors.borderGlass, - borderTopWidth: StyleSheet.hairlineWidth, + backgroundColor: theme.colors.backgroundPrimary, + borderTopColor: theme.colors.borderSubtle, + borderTopWidth: 1, height: Platform.OS === "ios" ? 88 : 64, paddingBottom: Platform.OS === "ios" ? 28 : 8, paddingTop: 8, - ...Platform.select({ - ios: { - shadowColor: "#000", - shadowOpacity: 0.08, - shadowOffset: { width: 0, height: -4 }, - shadowRadius: 12, - }, - default: { elevation: 8 }, - }), }, tabBarActiveTintColor: theme.colors.actionPrimary, tabBarInactiveTintColor: theme.colors.textTertiary, diff --git a/MobileApp/src/screens/AlertDetailScreen.tsx b/MobileApp/src/screens/AlertDetailScreen.tsx index 9feca34753..24cb4f917f 100644 --- a/MobileApp/src/screens/AlertDetailScreen.tsx +++ b/MobileApp/src/screens/AlertDetailScreen.tsx @@ -9,7 +9,6 @@ import { Alert, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; -import { LinearGradient } from "expo-linear-gradient"; import type { NativeStackScreenProps } from "@react-navigation/native-stack"; import { useTheme } from "../theme"; import { @@ -31,7 +30,6 @@ import FeedTimeline from "../components/FeedTimeline"; import SkeletonCard from "../components/SkeletonCard"; import SectionHeader from "../components/SectionHeader"; import NotesSection from "../components/NotesSection"; -import GlassCard from "../components/GlassCard"; import { useHaptics } from "../hooks/useHaptics"; type Props = NativeStackScreenProps; @@ -138,7 +136,10 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { if (isLoading) { return ( - + ); @@ -146,8 +147,14 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { if (!alert) { return ( - - + + Alert not found. @@ -177,35 +184,41 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { return ( } > - {/* Header with glass card */} - - - + + + - - {alert.alertNumberWithPrefix || `#${alert.alertNumber}`} - - + {alert.alertNumberWithPrefix || `#${alert.alertNumber}`} + {alert.title} @@ -213,18 +226,17 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { {alert.currentAlertState ? ( - + {alert.currentAlertState.name} @@ -232,11 +244,11 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { {alert.alertSeverity ? ( {alert.alertSeverity.name} @@ -244,14 +256,17 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { ) : null} - - + + {/* Description */} {alert.description ? ( - + {alert.description} @@ -260,34 +275,50 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { {/* Details */} - - + Created - + {formatDateTime(alert.createdAt)} {alert.monitor ? ( - + Monitor - + {alert.monitor.name} ) : null} - + {/* State Change Actions */} @@ -297,14 +328,9 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { {!isAcknowledged && !isResolved && acknowledgeState ? ( { return handleStateChange( @@ -318,19 +344,19 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { accessibilityLabel="Acknowledge alert" > {changingState ? ( - + ) : ( <> - + Acknowledge @@ -340,14 +366,9 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { {resolveState ? ( { return handleStateChange(resolveState._id, resolveState.name); @@ -358,19 +379,19 @@ export default function AlertDetailScreen({ route }: Props): React.JSX.Element { accessibilityLabel="Resolve alert" > {changingState ? ( - + ) : ( <> - + Resolve diff --git a/MobileApp/src/screens/AlertEpisodeDetailScreen.tsx b/MobileApp/src/screens/AlertEpisodeDetailScreen.tsx index 46abdf1984..31139b2736 100644 --- a/MobileApp/src/screens/AlertEpisodeDetailScreen.tsx +++ b/MobileApp/src/screens/AlertEpisodeDetailScreen.tsx @@ -9,7 +9,6 @@ import { Alert, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; -import { LinearGradient } from "expo-linear-gradient"; import type { NativeStackScreenProps } from "@react-navigation/native-stack"; import { useTheme } from "../theme"; import { @@ -33,7 +32,6 @@ import FeedTimeline from "../components/FeedTimeline"; import SkeletonCard from "../components/SkeletonCard"; import SectionHeader from "../components/SectionHeader"; import NotesSection from "../components/NotesSection"; -import GlassCard from "../components/GlassCard"; import { useHaptics } from "../hooks/useHaptics"; type Props = NativeStackScreenProps; @@ -147,7 +145,10 @@ export default function AlertEpisodeDetailScreen({ if (isLoading) { return ( - + ); @@ -155,8 +156,14 @@ export default function AlertEpisodeDetailScreen({ if (!episode) { return ( - - + + Episode not found. @@ -186,194 +193,118 @@ export default function AlertEpisodeDetailScreen({ return ( } > - {/* Header with glass card */} - - - - - {episode.episodeNumberWithPrefix || `#${episode.episodeNumber}`} - - - + + + + {episode.episodeNumberWithPrefix || `#${episode.episodeNumber}`} + + {episode.title} - {episode.currentAlertState ? ( - - - {episode.currentAlertState.name} - + + {episode.currentAlertState.name} ) : null} - {episode.alertSeverity ? ( - - {episode.alertSeverity.name} - + {episode.alertSeverity.name} ) : null} - - + + - {/* Description */} {episode.description ? ( - - {episode.description} - + {episode.description} ) : null} - {/* Details */} - - - Created - - - {formatDateTime(episode.createdAt)} - + Created + {formatDateTime(episode.createdAt)} - - - Alerts - - - {episode.alertCount ?? 0} - + Alerts + {episode.alertCount ?? 0} - + - {/* State Change Actions */} {!isResolved ? ( {!isAcknowledged && !isResolved && acknowledgeState ? ( { - return handleStateChange( - acknowledgeState._id, - acknowledgeState.name, - ); - }} + className="flex-1 flex-row py-3 rounded-xl items-center justify-center min-h-[48px]" + style={{ backgroundColor: theme.colors.stateAcknowledged }} + onPress={() => { return handleStateChange(acknowledgeState._id, acknowledgeState.name); }} disabled={changingState} > - {changingState ? ( - - ) : ( + {changingState ? () : ( <> - - - Acknowledge - + + Acknowledge )} ) : null} - {resolveState ? ( { - return handleStateChange(resolveState._id, resolveState.name); - }} + className="flex-1 flex-row py-3 rounded-xl items-center justify-center min-h-[48px]" + style={{ backgroundColor: theme.colors.stateResolved }} + onPress={() => { return handleStateChange(resolveState._id, resolveState.name); }} disabled={changingState} > - {changingState ? ( - - ) : ( + {changingState ? () : ( <> - - - Resolve - + + Resolve )} @@ -382,7 +313,6 @@ export default function AlertEpisodeDetailScreen({ ) : null} - {/* Activity Feed */} {feed && feed.length > 0 ? ( @@ -390,17 +320,8 @@ export default function AlertEpisodeDetailScreen({ ) : null} - {/* Internal Notes */} - - { - return setNoteModalVisible(false); - }} - onSubmit={handleAddNote} - isSubmitting={submittingNote} - /> + { return setNoteModalVisible(false); }} onSubmit={handleAddNote} isSubmitting={submittingNote} /> ); } diff --git a/MobileApp/src/screens/AlertsScreen.tsx b/MobileApp/src/screens/AlertsScreen.tsx index 92d9c04a1d..a77e140506 100644 --- a/MobileApp/src/screens/AlertsScreen.tsx +++ b/MobileApp/src/screens/AlertsScreen.tsx @@ -59,30 +59,34 @@ function SectionHeader({ }): React.JSX.Element { const { theme } = useTheme(); return ( - + {title} @@ -102,6 +106,7 @@ function SectionHeader({ } export default function AlertsScreen(): React.JSX.Element { + const { theme } = useTheme(); const navigation: NavProp = useNavigation(); const [segment, setSegment] = useState("alerts"); @@ -288,7 +293,10 @@ export default function AlertsScreen(): React.JSX.Element { if (showLoading) { return ( - + + + { return handleAcknowledge(wrapped); }, diff --git a/MobileApp/src/screens/BiometricLockScreen.tsx b/MobileApp/src/screens/BiometricLockScreen.tsx index e1718a22f6..4082075ab2 100644 --- a/MobileApp/src/screens/BiometricLockScreen.tsx +++ b/MobileApp/src/screens/BiometricLockScreen.tsx @@ -3,7 +3,6 @@ import { View, Text } from "react-native"; import { useTheme } from "../theme"; import * as LocalAuthentication from "expo-local-authentication"; import Logo from "../components/Logo"; -import GradientHeader from "../components/GradientHeader"; import GradientButton from "../components/GradientButton"; interface BiometricLockScreenProps { @@ -34,42 +33,37 @@ export default function BiometricLockScreen({ }, []); return ( - - - - {/* Outer glow ring */} + - {/* Inner icon container */} - - - + OneUptime is Locked - + Use {biometricType.toLowerCase()} to unlock - + ; @@ -50,57 +47,55 @@ function StatCard({ return ( - - - - - - - - - - - - {isLoading ? "--" : count ?? 0} - - - {label} - + + + + + - + + {isLoading ? "--" : count ?? 0} + + + {label} + + ); } @@ -137,11 +132,10 @@ export default function HomeScreen(): React.JSX.Element { await Promise.all([refetch(), refreshProjects()]); }; - // No projects state if (!isLoadingProjects && projectList.length === 0) { return ( } > - - - - + No Projects Found - + You don't have access to any projects. Contact your administrator or pull to refresh. @@ -195,11 +184,12 @@ export default function HomeScreen(): React.JSX.Element { ); } - // Loading state if (isLoadingProjects) { return ( - - + ); @@ -212,7 +202,7 @@ export default function HomeScreen(): React.JSX.Element { return ( } > - {/* Header area with gradient background */} - - + + - + {getGreeting()} {subtitle} - - OneUptime - - + - {/* Stat Cards - 2x2 Grid */} - + + ); @@ -158,8 +159,14 @@ export default function IncidentDetailScreen({ if (!incident) { return ( - - + + Incident not found. @@ -191,36 +198,42 @@ export default function IncidentDetailScreen({ return ( } > - {/* Header with glass card */} - - - + + + - - {incident.incidentNumberWithPrefix || - `#${incident.incidentNumber}`} - - + {incident.incidentNumberWithPrefix || + `#${incident.incidentNumber}`} + {incident.title} @@ -228,18 +241,17 @@ export default function IncidentDetailScreen({ {incident.currentIncidentState ? ( - + {incident.currentIncidentState.name} @@ -247,11 +259,11 @@ export default function IncidentDetailScreen({ {incident.incidentSeverity ? ( {incident.incidentSeverity.name} @@ -259,14 +271,17 @@ export default function IncidentDetailScreen({ ) : null} - - + + {/* Description */} {incident.description ? ( - + {incident.description} @@ -275,8 +290,12 @@ export default function IncidentDetailScreen({ {/* Details */} - {incident.declaredAt ? ( - + Declared - + {formatDateTime(incident.declaredAt)} ) : null} - + Created - + {formatDateTime(incident.createdAt)} {incident.monitors?.length > 0 ? ( - + Monitors - + {incident.monitors .map((m: NamedEntity) => { return m.name; @@ -317,7 +354,7 @@ export default function IncidentDetailScreen({ ) : null} - + {/* State Change Actions */} @@ -327,14 +364,9 @@ export default function IncidentDetailScreen({ {!isAcknowledged && !isResolved && acknowledgeState ? ( { return handleStateChange( @@ -348,19 +380,19 @@ export default function IncidentDetailScreen({ accessibilityLabel="Acknowledge incident" > {changingState ? ( - + ) : ( <> - + Acknowledge @@ -370,14 +402,9 @@ export default function IncidentDetailScreen({ {resolveState ? ( { return handleStateChange(resolveState._id, resolveState.name); @@ -388,19 +415,19 @@ export default function IncidentDetailScreen({ accessibilityLabel="Resolve incident" > {changingState ? ( - + ) : ( <> - + Resolve diff --git a/MobileApp/src/screens/IncidentEpisodeDetailScreen.tsx b/MobileApp/src/screens/IncidentEpisodeDetailScreen.tsx index 5ec57e9fa5..e5a38d5e31 100644 --- a/MobileApp/src/screens/IncidentEpisodeDetailScreen.tsx +++ b/MobileApp/src/screens/IncidentEpisodeDetailScreen.tsx @@ -9,7 +9,6 @@ import { Alert, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; -import { LinearGradient } from "expo-linear-gradient"; import type { NativeStackScreenProps } from "@react-navigation/native-stack"; import { useTheme } from "../theme"; import { @@ -33,7 +32,6 @@ import FeedTimeline from "../components/FeedTimeline"; import SkeletonCard from "../components/SkeletonCard"; import SectionHeader from "../components/SectionHeader"; import NotesSection from "../components/NotesSection"; -import GlassCard from "../components/GlassCard"; import { useHaptics } from "../hooks/useHaptics"; type Props = NativeStackScreenProps< @@ -153,7 +151,10 @@ export default function IncidentEpisodeDetailScreen({ if (isLoading) { return ( - + ); @@ -161,8 +162,14 @@ export default function IncidentEpisodeDetailScreen({ if (!episode) { return ( - - + + Episode not found. @@ -194,66 +201,59 @@ export default function IncidentEpisodeDetailScreen({ return ( } > - {/* Header with glass card */} - - - - - {episode.episodeNumberWithPrefix || `#${episode.episodeNumber}`} - - - + + + + {episode.episodeNumberWithPrefix || `#${episode.episodeNumber}`} + + {episode.title} - {episode.currentIncidentState ? ( - + {episode.currentIncidentState.name} ) : null} - {episode.incidentSeverity ? ( {episode.incidentSeverity.name} @@ -261,24 +261,29 @@ export default function IncidentEpisodeDetailScreen({ ) : null} - - + + - {/* Description */} {episode.description ? ( - + {episode.description} ) : null} - {/* Details */} - {episode.declaredAt ? ( - - Declared - - - {formatDateTime(episode.declaredAt)} - + Declared + {formatDateTime(episode.declaredAt)} ) : null} - - - Created - - - {formatDateTime(episode.createdAt)} - + Created + {formatDateTime(episode.createdAt)} - - - Incidents - - - {episode.incidentCount ?? 0} - + Incidents + {episode.incidentCount ?? 0} - + - {/* State Change Actions */} {!isResolved ? ( {!isAcknowledged && !isResolved && acknowledgeState ? ( { - return handleStateChange( - acknowledgeState._id, - acknowledgeState.name, - ); - }} + className="flex-1 flex-row py-3 rounded-xl items-center justify-center min-h-[48px]" + style={{ backgroundColor: theme.colors.stateAcknowledged }} + onPress={() => { return handleStateChange(acknowledgeState._id, acknowledgeState.name); }} disabled={changingState} > - {changingState ? ( - - ) : ( + {changingState ? () : ( <> - - - Acknowledge - + + Acknowledge )} ) : null} - {resolveState ? ( { - return handleStateChange(resolveState._id, resolveState.name); - }} + className="flex-1 flex-row py-3 rounded-xl items-center justify-center min-h-[48px]" + style={{ backgroundColor: theme.colors.stateResolved }} + onPress={() => { return handleStateChange(resolveState._id, resolveState.name); }} disabled={changingState} > - {changingState ? ( - - ) : ( + {changingState ? () : ( <> - - - Resolve - + + Resolve )} @@ -401,7 +345,6 @@ export default function IncidentEpisodeDetailScreen({ ) : null} - {/* Activity Feed */} {feed && feed.length > 0 ? ( @@ -409,17 +352,8 @@ export default function IncidentEpisodeDetailScreen({ ) : null} - {/* Internal Notes */} - - { - return setNoteModalVisible(false); - }} - onSubmit={handleAddNote} - isSubmitting={submittingNote} - /> + { return setNoteModalVisible(false); }} onSubmit={handleAddNote} isSubmitting={submittingNote} /> ); } diff --git a/MobileApp/src/screens/IncidentsScreen.tsx b/MobileApp/src/screens/IncidentsScreen.tsx index 14c66ce095..a0ff398fae 100644 --- a/MobileApp/src/screens/IncidentsScreen.tsx +++ b/MobileApp/src/screens/IncidentsScreen.tsx @@ -62,30 +62,34 @@ function SectionHeader({ }): React.JSX.Element { const { theme } = useTheme(); return ( - + {title} @@ -105,6 +109,7 @@ function SectionHeader({ } export default function IncidentsScreen(): React.JSX.Element { + const { theme } = useTheme(); const navigation: NavProp = useNavigation(); const [segment, setSegment] = useState("incidents"); @@ -293,7 +298,10 @@ export default function IncidentsScreen(): React.JSX.Element { if (showLoading) { return ( - + + + { return handleAcknowledge(wrapped); }, diff --git a/MobileApp/src/screens/SettingsScreen.tsx b/MobileApp/src/screens/SettingsScreen.tsx index f9cb128126..16a5c4b26c 100644 --- a/MobileApp/src/screens/SettingsScreen.tsx +++ b/MobileApp/src/screens/SettingsScreen.tsx @@ -8,7 +8,6 @@ import { useBiometric } from "../hooks/useBiometric"; import { useHaptics } from "../hooks/useHaptics"; import { getServerUrl } from "../storage/serverUrl"; import Logo from "../components/Logo"; -import GlassCard from "../components/GlassCard"; const APP_VERSION: string = "1.0.0"; @@ -35,7 +34,7 @@ function SettingsRow({ const content: React.JSX.Element = ( {iconName ? ( - + + + ) : null} {rightElement ?? (value ? ( - {value} + + {value} + ) : onPress ? ( ) : null)} @@ -122,43 +134,46 @@ export default function SettingsScreen(): React.JSX.Element { return ( - {/* Profile Header */} - - + - - - - - Settings - - - {serverUrl || "oneuptime.com"} - - - + + + + {serverUrl || "oneuptime.com"} + + {/* Appearance */} - - + + Appearance - + {(["dark", "light", "system"] as ThemeMode[]).map( @@ -169,15 +184,15 @@ export default function SettingsScreen(): React.JSX.Element { key={mode} className="flex-1 flex-row items-center justify-center py-2.5 rounded-[10px] gap-1.5 overflow-hidden" style={ - !isActive - ? undefined - : { - shadowColor: "#000000", - shadowOpacity: theme.isDark ? 0.4 : 0.15, + isActive + ? { + shadowColor: theme.colors.accentGradientMid, + shadowOpacity: 0.3, shadowOffset: { width: 0, height: 2 }, shadowRadius: 6, elevation: 3, } + : undefined } onPress={() => { return handleThemeChange(mode); @@ -209,18 +224,16 @@ export default function SettingsScreen(): React.JSX.Element { ? "sunny-outline" : "phone-portrait-outline" } - size={16} + size={15} color={ - isActive - ? theme.colors.textInverse - : theme.colors.textSecondary + isActive ? "#FFFFFF" : theme.colors.textSecondary } /> @@ -232,16 +245,26 @@ export default function SettingsScreen(): React.JSX.Element { )} - + {/* Security */} {biometric.isAvailable ? ( - - + + Security - + } /> - - + + Require biometrics to unlock the app ) : null} {/* Server */} - - + + Server - + - + {/* Account */} - - + + Account - + - + {/* About */} - - + + About - + - + - {/* Footer branding */} + {/* Footer */} - - - - OneUptime - - On-Call Management - ); diff --git a/MobileApp/src/screens/auth/LoginScreen.tsx b/MobileApp/src/screens/auth/LoginScreen.tsx index cc38383a7b..f64366552b 100644 --- a/MobileApp/src/screens/auth/LoginScreen.tsx +++ b/MobileApp/src/screens/auth/LoginScreen.tsx @@ -16,8 +16,6 @@ import { NativeStackNavigationProp } from "@react-navigation/native-stack"; import { useNavigation } from "@react-navigation/native"; import { AuthStackParamList } from "../../navigation/types"; import Logo from "../../components/Logo"; -import GradientHeader from "../../components/GradientHeader"; -import GlassCard from "../../components/GlassCard"; import GradientButton from "../../components/GradientButton"; type LoginNavigationProp = NativeStackNavigationProp< @@ -76,11 +74,10 @@ export default function LoginScreen(): React.JSX.Element { return ( - - - + OneUptime - - On-Call Management + + Sign in to continue {serverUrl ? ( - + {serverUrl} ) : null} - - + + Email { setEmail(text); @@ -174,13 +177,16 @@ export default function LoginScreen(): React.JSX.Element { /> - + Password { setPassword(text); @@ -220,7 +227,7 @@ export default function LoginScreen(): React.JSX.Element { {error ? ( - + {error} @@ -236,17 +243,17 @@ export default function LoginScreen(): React.JSX.Element { ) : null} - + - + - + - - - + OneUptime - + Connect to your OneUptime instance - - + + Server URL { setUrl(text); @@ -153,7 +155,7 @@ export default function ServerUrlScreen(): React.JSX.Element { {error ? ( - + {error} @@ -169,7 +171,7 @@ export default function ServerUrlScreen(): React.JSX.Element { ) : null} - + - + - + Self-hosting? Enter your OneUptime server URL above. - - - - - - Powered by OneUptime - - - diff --git a/MobileApp/src/theme/colors.ts b/MobileApp/src/theme/colors.ts index a5dc7af680..8fc7ffd991 100644 --- a/MobileApp/src/theme/colors.ts +++ b/MobileApp/src/theme/colors.ts @@ -71,145 +71,145 @@ export interface ColorTokens { } export const darkColors: ColorTokens = { - // Background - backgroundPrimary: "#000000", - backgroundSecondary: "#0A0A0A", - backgroundTertiary: "#161616", - backgroundElevated: "#0F0F0F", + // Background — rich near-black, not pure black + backgroundPrimary: "#09090B", + backgroundSecondary: "#0F0F12", + backgroundTertiary: "#18181F", + backgroundElevated: "#141418", // Accent - cardAccent: "rgba(255, 255, 255, 0.07)", - backgroundGlass: "rgba(255, 255, 255, 0.05)", - iconBackground: "rgba(255, 255, 255, 0.07)", + cardAccent: "rgba(255, 255, 255, 0.04)", + backgroundGlass: "rgba(255, 255, 255, 0.03)", + iconBackground: "rgba(99, 102, 241, 0.12)", - // Gradient - accentGradientStart: "#FFFFFF", - accentGradientMid: "#E0E0E0", - accentGradientEnd: "#C8C8C8", + // Gradient — indigo-based brand accent + accentGradientStart: "#818CF8", + accentGradientMid: "#6366F1", + accentGradientEnd: "#4F46E5", accentCyan: "#06B6D4", - accentCyanBg: "rgba(6, 182, 212, 0.12)", - surfaceGlow: "rgba(255, 255, 255, 0.04)", - headerGradient: "rgba(255, 255, 255, 0.03)", - gradientStart: "rgba(255, 255, 255, 0.05)", + accentCyanBg: "rgba(6, 182, 212, 0.10)", + surfaceGlow: "rgba(99, 102, 241, 0.06)", + headerGradient: "rgba(99, 102, 241, 0.04)", + gradientStart: "rgba(99, 102, 241, 0.08)", gradientEnd: "transparent", // Border - borderDefault: "#1C1C1E", - borderSubtle: "#141414", - borderGlass: "rgba(255, 255, 255, 0.08)", + borderDefault: "rgba(255, 255, 255, 0.06)", + borderSubtle: "rgba(255, 255, 255, 0.04)", + borderGlass: "rgba(255, 255, 255, 0.06)", // Text - textPrimary: "#F0F0F0", - textSecondary: "#8E8E93", - textTertiary: "#636366", - textInverse: "#000000", - - // Severity - severityCritical: "#F85149", - severityCriticalBg: "#F8514926", - severityMajor: "#F0883E", - severityMajorBg: "#F0883E26", - severityMinor: "#D29922", - severityMinorBg: "#D2992226", - severityWarning: "#E3B341", - severityWarningBg: "#E3B34126", - severityInfo: "#58A6FF", - severityInfoBg: "#58A6FF26", - - // State - stateCreated: "#F85149", - stateAcknowledged: "#D29922", - stateResolved: "#3FB950", - stateInvestigating: "#F0883E", - stateMuted: "#636366", - - // On-Call - oncallActive: "#3FB950", - oncallActiveBg: "#3FB95026", - oncallInactive: "#636366", - oncallInactiveBg: "#63636626", - - // Action - actionPrimary: "#FFFFFF", - actionPrimaryPressed: "#D4D4D4", - actionDestructive: "#F85149", - actionDestructivePressed: "#DA3633", - - // Status - statusSuccess: "#3FB950", - statusSuccessBg: "#3FB95026", - statusError: "#F85149", - statusErrorBg: "#F8514926", -}; - -export const lightColors: ColorTokens = { - // Background - backgroundPrimary: "#FFFFFF", - backgroundSecondary: "#F8F8FA", - backgroundTertiary: "#F0F0F2", - backgroundElevated: "#FFFFFF", - - // Accent - cardAccent: "rgba(0, 0, 0, 0.04)", - backgroundGlass: "rgba(255, 255, 255, 0.85)", - iconBackground: "rgba(0, 0, 0, 0.05)", - - // Gradient - accentGradientStart: "#1A1A1A", - accentGradientMid: "#2D2D2D", - accentGradientEnd: "#3A3A3A", - accentCyan: "#0891B2", - accentCyanBg: "rgba(8, 145, 178, 0.08)", - surfaceGlow: "rgba(0, 0, 0, 0.03)", - headerGradient: "rgba(0, 0, 0, 0.02)", - gradientStart: "rgba(0, 0, 0, 0.03)", - gradientEnd: "transparent", - - // Border - borderDefault: "#E5E5EA", - borderSubtle: "#F0F0F2", - borderGlass: "rgba(0, 0, 0, 0.06)", - - // Text - textPrimary: "#111111", - textSecondary: "#6B6B6B", - textTertiary: "#9A9A9A", + textPrimary: "#FAFAFA", + textSecondary: "#A1A1AA", + textTertiary: "#52525B", textInverse: "#FFFFFF", // Severity - severityCritical: "#CF222E", - severityCriticalBg: "#CF222E1A", - severityMajor: "#BC4C00", - severityMajorBg: "#BC4C001A", - severityMinor: "#9A6700", - severityMinorBg: "#9A67001A", - severityWarning: "#BF8700", - severityWarningBg: "#BF87001A", - severityInfo: "#0969DA", - severityInfoBg: "#0969DA1A", + severityCritical: "#EF4444", + severityCriticalBg: "rgba(239, 68, 68, 0.12)", + severityMajor: "#F97316", + severityMajorBg: "rgba(249, 115, 22, 0.12)", + severityMinor: "#EAB308", + severityMinorBg: "rgba(234, 179, 8, 0.12)", + severityWarning: "#F59E0B", + severityWarningBg: "rgba(245, 158, 11, 0.12)", + severityInfo: "#3B82F6", + severityInfoBg: "rgba(59, 130, 246, 0.12)", // State - stateCreated: "#CF222E", - stateAcknowledged: "#9A6700", - stateResolved: "#1A7F37", - stateInvestigating: "#BC4C00", - stateMuted: "#8C959F", + stateCreated: "#EF4444", + stateAcknowledged: "#F59E0B", + stateResolved: "#22C55E", + stateInvestigating: "#F97316", + stateMuted: "#52525B", // On-Call - oncallActive: "#1A7F37", - oncallActiveBg: "#1A7F371A", - oncallInactive: "#8C959F", - oncallInactiveBg: "#8C959F1A", + oncallActive: "#22C55E", + oncallActiveBg: "rgba(34, 197, 94, 0.12)", + oncallInactive: "#52525B", + oncallInactiveBg: "rgba(82, 82, 91, 0.12)", - // Action - actionPrimary: "#1A1A1A", - actionPrimaryPressed: "#333333", - actionDestructive: "#CF222E", - actionDestructivePressed: "#A40E26", + // Action — indigo accent is the signature change + actionPrimary: "#6366F1", + actionPrimaryPressed: "#4F46E5", + actionDestructive: "#EF4444", + actionDestructivePressed: "#DC2626", // Status - statusSuccess: "#1A7F37", - statusSuccessBg: "#1A7F371A", - statusError: "#CF222E", - statusErrorBg: "#CF222E1A", + statusSuccess: "#22C55E", + statusSuccessBg: "rgba(34, 197, 94, 0.12)", + statusError: "#EF4444", + statusErrorBg: "rgba(239, 68, 68, 0.12)", +}; + +export const lightColors: ColorTokens = { + // Background — clean white with warm gray tones + backgroundPrimary: "#FFFFFF", + backgroundSecondary: "#F9FAFB", + backgroundTertiary: "#F3F4F6", + backgroundElevated: "#FFFFFF", + + // Accent + cardAccent: "rgba(0, 0, 0, 0.02)", + backgroundGlass: "rgba(255, 255, 255, 0.80)", + iconBackground: "rgba(99, 102, 241, 0.08)", + + // Gradient — indigo-based brand accent + accentGradientStart: "#6366F1", + accentGradientMid: "#4F46E5", + accentGradientEnd: "#4338CA", + accentCyan: "#0891B2", + accentCyanBg: "rgba(8, 145, 178, 0.06)", + surfaceGlow: "rgba(99, 102, 241, 0.04)", + headerGradient: "rgba(99, 102, 241, 0.03)", + gradientStart: "rgba(99, 102, 241, 0.04)", + gradientEnd: "transparent", + + // Border + borderDefault: "#E5E7EB", + borderSubtle: "#F3F4F6", + borderGlass: "rgba(0, 0, 0, 0.05)", + + // Text + textPrimary: "#111827", + textSecondary: "#6B7280", + textTertiary: "#9CA3AF", + textInverse: "#FFFFFF", + + // Severity + severityCritical: "#DC2626", + severityCriticalBg: "rgba(220, 38, 38, 0.08)", + severityMajor: "#EA580C", + severityMajorBg: "rgba(234, 88, 12, 0.08)", + severityMinor: "#CA8A04", + severityMinorBg: "rgba(202, 138, 4, 0.08)", + severityWarning: "#D97706", + severityWarningBg: "rgba(217, 119, 6, 0.08)", + severityInfo: "#2563EB", + severityInfoBg: "rgba(37, 99, 235, 0.08)", + + // State + stateCreated: "#DC2626", + stateAcknowledged: "#D97706", + stateResolved: "#16A34A", + stateInvestigating: "#EA580C", + stateMuted: "#9CA3AF", + + // On-Call + oncallActive: "#16A34A", + oncallActiveBg: "rgba(22, 163, 74, 0.08)", + oncallInactive: "#9CA3AF", + oncallInactiveBg: "rgba(156, 163, 175, 0.08)", + + // Action — indigo accent + actionPrimary: "#4F46E5", + actionPrimaryPressed: "#4338CA", + actionDestructive: "#DC2626", + actionDestructivePressed: "#B91C1C", + + // Status + statusSuccess: "#16A34A", + statusSuccessBg: "rgba(22, 163, 74, 0.08)", + statusError: "#DC2626", + statusErrorBg: "rgba(220, 38, 38, 0.08)", };