feat: persist draft messages and UI refinements

- Add dedicated draft-store with AsyncStorage persistence for drafts
  that survive app refresh/crash
- Reduce markdown bold weight from bold to medium (500)
- Various theme and component style updates
- Server bootstrap and config improvements

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
Mohamed Boudra
2026-01-14 10:07:54 +07:00
parent 34a49c147f
commit 70e2d66dd5
65 changed files with 2466 additions and 570 deletions
+19 -7
View File
@@ -7,6 +7,7 @@ import { RealtimeProvider } from "@/contexts/realtime-context";
import { useAppSettings } from "@/hooks/use-settings";
import { View, ActivityIndicator, Text } from "react-native";
import { UnistylesRuntime, useUnistyles } from "react-native-unistyles";
import { darkTheme } from "@/styles/theme";
import { DaemonRegistryProvider, useDaemonRegistry } from "@/contexts/daemon-registry-context";
import { DaemonConnectionsProvider } from "@/contexts/daemon-connections-context";
import { MultiDaemonSessionHost } from "@/components/multi-daemon-session-host";
@@ -144,7 +145,7 @@ function AppContainer({ children, selectedAgentId }: AppContainerProps) {
);
const content = (
<View style={{ flex: 1, backgroundColor: theme.colors.background }}>
<View style={{ flex: 1, backgroundColor: theme.colors.surface0 }}>
<View style={{ flex: 1, flexDirection: "row" }}>
{!isMobile && <SlidingSidebar selectedAgentId={selectedAgentId} />}
<View style={{ flex: 1 }}>{children}</View>
@@ -165,10 +166,21 @@ function AppContainer({ children, selectedAgentId }: AppContainerProps) {
}
function ProvidersWrapper({ children }: { children: ReactNode }) {
const { isLoading: settingsLoading } = useAppSettings();
const { settings, isLoading: settingsLoading } = useAppSettings();
const { daemons, isLoading: registryLoading } = useDaemonRegistry();
const isLoading = settingsLoading || registryLoading;
// Apply theme setting on mount and when it changes
useEffect(() => {
if (isLoading) return;
if (settings.theme === "auto") {
UnistylesRuntime.setAdaptiveThemes(true);
} else {
UnistylesRuntime.setAdaptiveThemes(false);
UnistylesRuntime.setTheme(settings.theme);
}
}, [isLoading, settings.theme]);
if (isLoading) {
return <LoadingView />;
}
@@ -207,10 +219,10 @@ function LoadingView() {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#09090b",
backgroundColor: darkTheme.colors.surface0,
}}
>
<ActivityIndicator size="large" color="#fafafa" />
<ActivityIndicator size="large" color={darkTheme.colors.foreground} />
</View>
);
}
@@ -223,13 +235,13 @@ function MissingDaemonView() {
justifyContent: "center",
alignItems: "center",
padding: 24,
backgroundColor: "#09090b",
backgroundColor: darkTheme.colors.surface0,
}}
>
<ActivityIndicator size="small" color="#fafafa" />
<ActivityIndicator size="small" color={darkTheme.colors.foreground} />
<Text
style={{
color: "#fafafa",
color: darkTheme.colors.foreground,
marginTop: 16,
textAlign: "center",
}}
+4 -4
View File
@@ -149,7 +149,7 @@ export default function LegacyAgentRedirectScreen() {
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
content: {
flex: 1,
@@ -170,7 +170,7 @@ const styles = StyleSheet.create((theme) => ({
},
subtitle: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
textAlign: "center",
},
primaryButton: {
@@ -194,7 +194,7 @@ const styles = StyleSheet.create((theme) => ({
paddingHorizontal: theme.spacing[4],
paddingVertical: theme.spacing[3],
borderRadius: theme.borderRadius.lg,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
matchLabel: {
fontSize: theme.fontSize.base,
@@ -204,6 +204,6 @@ const styles = StyleSheet.create((theme) => ({
matchMeta: {
marginTop: theme.spacing[1],
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
}));
@@ -644,7 +644,7 @@ function AgentScreenContent({
color={
isExplorerOpen
? theme.colors.foreground
: theme.colors.mutedForeground
: theme.colors.foregroundMuted
}
/>
) : (
@@ -653,14 +653,14 @@ function AgentScreenContent({
color={
isExplorerOpen
? theme.colors.foreground
: theme.colors.mutedForeground
: theme.colors.foregroundMuted
}
/>
)}
</Pressable>
<View ref={menuButtonRef} collapsable={false}>
<Pressable onPress={handleOpenMenu} style={styles.menuButton}>
<MoreVertical size={16} color={theme.colors.mutedForeground} />
<MoreVertical size={16} color={theme.colors.foregroundMuted} />
</Pressable>
</View>
</View>
@@ -748,7 +748,7 @@ function AgentScreenContent({
<>
<ActivityIndicator
size="small"
color={theme.colors.mutedForeground}
color={theme.colors.foregroundMuted}
/>
<Text style={styles.menuMetaPendingText}>
Fetching…
@@ -777,7 +777,7 @@ function AgentScreenContent({
{/* Sub-Agents Section */}
<View style={styles.menuSubAgentsSection}>
<View style={styles.menuSubAgentsHeader}>
<Users size={16} color={theme.colors.mutedForeground} />
<Users size={16} color={theme.colors.foregroundMuted} />
<Text style={styles.menuSubAgentsLabel}>Sub-Agents</Text>
</View>
{childAgents.length === 0 ? (
@@ -807,7 +807,7 @@ function AgentScreenContent({
) : null}
<ChevronRight
size={16}
color={theme.colors.mutedForeground}
color={theme.colors.foregroundMuted}
/>
</View>
</Pressable>
@@ -953,11 +953,11 @@ const styles = StyleSheet.create((theme) => ({
outerContainer: {
flex: 1,
flexDirection: "row",
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
headerRightContent: {
flexDirection: "row",
@@ -978,7 +978,7 @@ const styles = StyleSheet.create((theme) => ({
},
loadingText: {
fontSize: theme.fontSize.base,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
centerState: {
flex: 1,
@@ -994,20 +994,20 @@ const styles = StyleSheet.create((theme) => ({
},
errorText: {
fontSize: theme.fontSize.lg,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
textAlign: "center",
},
statusText: {
marginTop: theme.spacing[2],
textAlign: "center",
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
errorDetails: {
marginTop: theme.spacing[1],
textAlign: "center",
fontSize: theme.fontSize.xs,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
offlineTitle: {
fontSize: theme.fontSize.base,
@@ -1017,12 +1017,12 @@ const styles = StyleSheet.create((theme) => ({
},
offlineDescription: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
textAlign: "center",
},
offlineDetails: {
fontSize: theme.fontSize.xs,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
textAlign: "center",
},
menuButton: {
@@ -1036,7 +1036,7 @@ const styles = StyleSheet.create((theme) => ({
...StyleSheet.absoluteFillObject,
},
dropdownMenu: {
backgroundColor: theme.colors.popover,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing[2],
shadowColor: "#000",
@@ -1054,7 +1054,7 @@ const styles = StyleSheet.create((theme) => ({
},
menuMetaLabel: {
fontSize: theme.fontSize.xs,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
letterSpacing: 0.5,
textTransform: "uppercase",
},
@@ -1069,7 +1069,7 @@ const styles = StyleSheet.create((theme) => ({
},
menuMetaPendingText: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
menuMetaValueError: {
color: theme.colors.destructive,
@@ -1110,13 +1110,13 @@ const styles = StyleSheet.create((theme) => ({
},
menuSubAgentsLabel: {
fontSize: theme.fontSize.xs,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
letterSpacing: 0.5,
textTransform: "uppercase",
},
menuSubAgentsEmpty: {
fontSize: theme.fontSize.base,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[3],
},
+1 -1
View File
@@ -46,6 +46,6 @@ export default function AgentsScreen() {
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
}));
+9 -9
View File
@@ -11,7 +11,7 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: theme.colors.palette.white,
},
scrollViewDark: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
container: {
padding: theme.spacing[6],
@@ -31,7 +31,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[8],
},
subtitleDark: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
section: {
marginBottom: theme.spacing[8],
@@ -83,7 +83,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.lg,
},
statusCardDark: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
statusLabel: {
fontSize: theme.fontSize.sm,
@@ -92,7 +92,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[1],
},
statusLabelDark: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
statusValue: {
fontSize: theme.fontSize.base,
@@ -146,7 +146,7 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: theme.colors.palette.gray[300],
},
buttonDisabledDark: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
buttonText: {
fontSize: theme.fontSize.base,
@@ -157,7 +157,7 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.palette.gray[500],
},
buttonTextDisabledDark: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
fullWidthButton: {
padding: theme.spacing[4],
@@ -202,7 +202,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.lg,
},
configCardDark: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
configTitle: {
fontSize: theme.fontSize.sm,
@@ -211,7 +211,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[2],
},
configTitleDark: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
configText: {
fontSize: theme.fontSize.sm,
@@ -219,7 +219,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[1],
},
configTextDark: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
gap3: {
gap: theme.spacing[3],
+9 -9
View File
@@ -538,7 +538,7 @@ export default function HomeScreen() {
style={styles.hostBadge}
onPress={() => openDropdownSheet("host")}
>
<Monitor size={14} color={theme.colors.mutedForeground} />
<Monitor size={14} color={theme.colors.foregroundMuted} />
<Text style={styles.hostBadgeLabel}>{hostLabel}</Text>
<View
style={[
@@ -671,7 +671,7 @@ export default function HomeScreen() {
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
agentPanel: {
flex: 1,
@@ -684,7 +684,7 @@ const styles = StyleSheet.create((theme) => ({
flex: 1,
},
inputAreaWrapper: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
configScrollContent: {
flexGrow: 1,
@@ -701,7 +701,7 @@ const styles = StyleSheet.create((theme) => ({
},
dropdownHelper: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
dropdownSheetList: {
marginTop: theme.spacing[3],
@@ -712,7 +712,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.lg,
borderWidth: 1,
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
marginBottom: theme.spacing[2],
},
dropdownSheetOptionSelected: {
@@ -724,7 +724,7 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
dropdownSheetOptionDescription: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
marginTop: theme.spacing[1],
},
@@ -757,11 +757,11 @@ const styles = StyleSheet.create((theme) => ({
gap: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.full,
},
hostBadgeLabel: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
},
@@ -769,7 +769,7 @@ const styles = StyleSheet.create((theme) => ({
width: 6,
height: 6,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.mutedForeground,
backgroundColor: theme.colors.foregroundMuted,
},
hostStatusDotOnline: {
backgroundColor: theme.colors.palette.green[500],
+1 -1
View File
@@ -75,7 +75,7 @@ export default function OrchestratorScreen() {
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
content: {
flex: 1,
+107 -21
View File
@@ -12,9 +12,10 @@ import {
Platform,
} from "react-native";
import { router } from "expo-router";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
import { Sun, Moon, Monitor } from "lucide-react-native";
import { Fonts } from "@/constants/theme";
import { useAppSettings } from "@/hooks/use-settings";
import { useAppSettings, type AppSettings } from "@/hooks/use-settings";
import { useDaemonRegistry, type DaemonProfile } from "@/contexts/daemon-registry-context";
import { useDaemonConnections, type ConnectionStatus } from "@/contexts/daemon-connections-context";
import { formatConnectionStatus, getConnectionStatusTone } from "@/utils/daemons";
@@ -34,7 +35,7 @@ const delay = (ms: number) =>
const styles = StyleSheet.create((theme) => ({
loadingContainer: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
alignItems: "center",
justifyContent: "center",
},
@@ -44,7 +45,7 @@ const styles = StyleSheet.create((theme) => ({
},
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
scrollView: {
flex: 1,
@@ -57,7 +58,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[6],
},
sectionTitle: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
letterSpacing: 0.6,
@@ -66,7 +67,7 @@ const styles = StyleSheet.create((theme) => ({
marginLeft: theme.spacing[1],
},
label: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
letterSpacing: 0.4,
@@ -74,7 +75,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[2],
},
input: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
color: theme.colors.foreground,
padding: theme.spacing[3],
borderRadius: theme.borderRadius.md,
@@ -87,7 +88,7 @@ const styles = StyleSheet.create((theme) => ({
},
// Host card styles
hostCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: 1,
borderColor: theme.colors.border,
@@ -109,7 +110,7 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
hostUrl: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontFamily: Fonts.mono,
},
@@ -151,7 +152,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.md,
},
hostActionText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
},
@@ -189,13 +190,13 @@ const styles = StyleSheet.create((theme) => ({
borderStyle: "dashed",
},
addButtonText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.semibold,
},
// Add/Edit form
formCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: 1,
borderColor: theme.colors.border,
@@ -237,7 +238,7 @@ const styles = StyleSheet.create((theme) => ({
},
// Audio settings card
audioCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: 1,
borderColor: theme.colors.border,
@@ -263,7 +264,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.base,
},
audioRowDescription: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
marginTop: 2,
},
@@ -281,11 +282,11 @@ const styles = StyleSheet.create((theme) => ({
gap: theme.spacing[1],
},
footerText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
footerVersion: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
resetButton: {
@@ -298,7 +299,7 @@ const styles = StyleSheet.create((theme) => ({
},
// Empty state
emptyCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: 1,
borderColor: theme.colors.border,
@@ -306,10 +307,39 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[3],
},
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
textAlign: "center",
},
// Theme toggle
themeToggleContainer: {
flexDirection: "row",
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
padding: 4,
gap: 4,
},
themeToggleButton: {
flex: 1,
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
gap: theme.spacing[2],
paddingVertical: theme.spacing[3],
paddingHorizontal: theme.spacing[3],
borderRadius: theme.borderRadius.md,
},
themeToggleButtonActive: {
backgroundColor: theme.colors.surface3,
},
themeToggleText: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.medium,
color: theme.colors.foregroundMuted,
},
themeToggleTextActive: {
color: theme.colors.foreground,
},
}));
type DaemonTestState = {
@@ -502,6 +532,19 @@ export default function SettingsScreen() {
[settings, updateSettings]
);
const handleThemeChange = useCallback(
(newTheme: AppSettings["theme"]) => {
void updateSettings({ theme: newTheme });
if (newTheme === "auto") {
UnistylesRuntime.setAdaptiveThemes(true);
} else {
UnistylesRuntime.setAdaptiveThemes(false);
UnistylesRuntime.setTheme(newTheme);
}
},
[updateSettings]
);
function validateServerUrl(url: string): boolean {
try {
const urlObj = new URL(url);
@@ -637,6 +680,49 @@ export default function SettingsScreen() {
)}
</View>
{/* Appearance */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Appearance</Text>
<View style={styles.themeToggleContainer}>
<Pressable
style={[
styles.themeToggleButton,
settings.theme === "light" && styles.themeToggleButtonActive,
]}
onPress={() => handleThemeChange("light")}
>
<Sun size={16} color={settings.theme === "light" ? defaultTheme.colors.foreground : defaultTheme.colors.mutedForeground} />
<Text style={[styles.themeToggleText, settings.theme === "light" && styles.themeToggleTextActive]}>
Light
</Text>
</Pressable>
<Pressable
style={[
styles.themeToggleButton,
settings.theme === "dark" && styles.themeToggleButtonActive,
]}
onPress={() => handleThemeChange("dark")}
>
<Moon size={16} color={settings.theme === "dark" ? defaultTheme.colors.foreground : defaultTheme.colors.mutedForeground} />
<Text style={[styles.themeToggleText, settings.theme === "dark" && styles.themeToggleTextActive]}>
Dark
</Text>
</Pressable>
<Pressable
style={[
styles.themeToggleButton,
settings.theme === "auto" && styles.themeToggleButtonActive,
]}
onPress={() => handleThemeChange("auto")}
>
<Monitor size={16} color={settings.theme === "auto" ? defaultTheme.colors.foreground : defaultTheme.colors.mutedForeground} />
<Text style={[styles.themeToggleText, settings.theme === "auto" && styles.themeToggleTextActive]}>
System
</Text>
</Pressable>
</View>
</View>
{/* Audio Settings */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Audio</Text>
@@ -727,7 +813,7 @@ function DaemonCard({
? theme.colors.palette.amber[500]
: statusTone === "error"
? theme.colors.destructive
: theme.colors.mutedForeground;
: theme.colors.foregroundMuted;
const badgeText = statusLabel;
const connectionError = typeof lastError === "string" && lastError.trim().length > 0 ? lastError.trim() : null;
const daemonConnection = useSessionStore(
@@ -870,7 +956,7 @@ function DaemonCard({
? theme.colors.palette.green[400]
: testState?.status === "error"
? theme.colors.palette.red[300]
: theme.colors.mutedForeground;
: theme.colors.foregroundMuted;
return (
<View style={styles.hostCard}>
@@ -911,7 +997,7 @@ function DaemonCard({
disabled={isRestarting}
>
{isRestarting ? (
<ActivityIndicator size="small" color={theme.colors.mutedForeground} />
<ActivityIndicator size="small" color={theme.colors.foregroundMuted} />
) : (
<Text style={styles.hostActionText}>Restart</Text>
)}
@@ -46,7 +46,7 @@ function getModeColor(modeId?: string): string {
const styles = StyleSheet.create((theme) => ({
container: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderBottomWidth: 1,
borderBottomColor: theme.colors.border,
},
@@ -57,7 +57,7 @@ const styles = StyleSheet.create((theme) => ({
borderBottomColor: theme.colors.border,
},
backButton: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
paddingHorizontal: theme.spacing[4],
paddingVertical: theme.spacing[2],
borderRadius: theme.borderRadius.lg,
@@ -87,7 +87,7 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: theme.colors.primary,
},
processItemInactive: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
agentIcon: {
width: 12,
+13 -13
View File
@@ -252,19 +252,19 @@ export function AgentActivityItem({ item }: AgentActivityItemProps) {
const stylesheet = StyleSheet.create((theme) => ({
card: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing[3],
marginBottom: theme.spacing[2],
},
thoughtCard: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderLeftWidth: 3,
borderLeftColor: theme.colors.palette.purple[500],
paddingVertical: theme.spacing[2],
},
timestamp: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
marginBottom: theme.spacing[1],
},
@@ -283,11 +283,11 @@ const stylesheet = StyleSheet.create((theme) => ({
lineHeight: 20,
},
thoughtText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontStyle: 'italic',
},
toolCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
marginBottom: theme.spacing[2],
overflow: 'hidden',
@@ -327,7 +327,7 @@ const stylesheet = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
expandIcon: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
toolContent: {
@@ -345,20 +345,20 @@ const stylesheet = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[1],
},
code: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontFamily: Fonts.mono,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
padding: theme.spacing[2],
borderRadius: theme.borderRadius.md,
},
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontStyle: 'italic',
},
planCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
marginBottom: theme.spacing[2],
overflow: 'hidden',
@@ -399,11 +399,11 @@ const stylesheet = StyleSheet.create((theme) => ({
flex: 1,
},
infoText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
unknownCard: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
marginBottom: theme.spacing[2],
overflow: 'hidden',
@@ -428,6 +428,6 @@ const stylesheet = StyleSheet.create((theme) => ({
borderTopWidth: theme.borderWidth[1],
borderTopColor: theme.colors.border,
padding: theme.spacing[3],
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
}));
@@ -87,7 +87,7 @@ export function DropdownField({
>
{value || placeholder}
</Text>
<ChevronDown size={16} color={defaultTheme.colors.mutedForeground} />
<ChevronDown size={16} color={defaultTheme.colors.foregroundMuted} />
</Pressable>
{errorMessage ? <Text style={styles.errorText}>{errorMessage}</Text> : null}
{warningMessage ? <Text style={styles.warningText}>{warningMessage}</Text> : null}
@@ -138,7 +138,7 @@ export function SelectField({
{value || placeholder || "Select..."}
</Text>
</View>
<ChevronRight size={20} color={defaultTheme.colors.mutedForeground} />
<ChevronRight size={20} color={defaultTheme.colors.foregroundMuted} />
</Pressable>
{errorMessage ? <Text style={styles.errorText}>{errorMessage}</Text> : null}
{warningMessage ? <Text style={styles.warningText}>{warningMessage}</Text> : null}
@@ -404,7 +404,7 @@ export function ComboSelect({
ref={inputRef}
style={styles.dropdownSearchInput}
placeholder={`Search ${label.toLowerCase()}...`}
placeholderTextColor={defaultTheme.colors.mutedForeground}
placeholderTextColor={defaultTheme.colors.foregroundMuted}
value={searchQuery}
onChangeText={setSearchQuery}
autoCapitalize="none"
@@ -486,7 +486,7 @@ function CompactSelectField({
>
<Text style={styles.compactSelectLabel}>{label}</Text>
{isLoading ? (
<ActivityIndicator size="small" color={defaultTheme.colors.mutedForeground} />
<ActivityIndicator size="small" color={defaultTheme.colors.foregroundMuted} />
) : (
<Text
style={value ? styles.compactSelectValue : styles.compactSelectPlaceholder}
@@ -933,7 +933,7 @@ export function WorkingDirectoryDropdown({
ref={inputRef}
style={styles.dropdownSearchInput}
placeholder="/path/to/project"
placeholderTextColor={defaultTheme.colors.mutedForeground}
placeholderTextColor={defaultTheme.colors.foregroundMuted}
value={searchQuery}
onChangeText={setSearchQuery}
autoCapitalize="none"
@@ -1132,20 +1132,20 @@ export function GitOptionsSection({
autoCapitalize="none"
autoCorrect={false}
placeholder="branch name"
placeholderTextColor={defaultTheme.colors.mutedForeground}
placeholderTextColor={defaultTheme.colors.foregroundMuted}
onSubmitEditing={handleConfirmEdit}
/>
<Pressable onPress={handleConfirmEdit} hitSlop={8} style={styles.baseBranchIconButton}>
<Check size={16} color={defaultTheme.colors.palette.green[500]} />
</Pressable>
<Pressable onPress={handleCancelEdit} hitSlop={8} style={styles.baseBranchIconButton}>
<X size={16} color={defaultTheme.colors.mutedForeground} />
<X size={16} color={defaultTheme.colors.foregroundMuted} />
</Pressable>
</View>
) : (
<Pressable onPress={handleStartEdit} style={styles.baseBranchValueRow}>
<Text style={styles.baseBranchValue}>{displayBranch}</Text>
<Pencil size={14} color={defaultTheme.colors.mutedForeground} />
<Pencil size={14} color={defaultTheme.colors.foregroundMuted} />
</Pressable>
)}
</View>
@@ -1179,7 +1179,7 @@ const styles = StyleSheet.create((theme) => ({
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[3],
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.lg,
@@ -1196,14 +1196,14 @@ const styles = StyleSheet.create((theme) => ({
},
dropdownPlaceholder: {
flex: 1,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.base,
},
dropdownSearchInput: {
borderRadius: theme.borderRadius.md,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
color: theme.colors.foreground,
@@ -1222,7 +1222,7 @@ const styles = StyleSheet.create((theme) => ({
opacity: 0.45,
},
dropdownSheetContainer: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderTopLeftRadius: theme.borderRadius["2xl"],
borderTopRightRadius: theme.borderRadius["2xl"],
paddingTop: theme.spacing[4],
@@ -1259,7 +1259,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
marginBottom: theme.spacing[2],
},
dropdownSheetOptionSelected: {
@@ -1271,7 +1271,7 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
dropdownSheetOptionDescription: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
marginTop: theme.spacing[1],
},
@@ -1288,7 +1288,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.sm,
},
helperText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
selectorColumn: {
@@ -1339,7 +1339,7 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
input: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.lg,
@@ -1359,7 +1359,7 @@ const styles = StyleSheet.create((theme) => ({
selectFieldControl: {
flexDirection: "row",
alignItems: "center",
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.lg,
@@ -1374,7 +1374,7 @@ const styles = StyleSheet.create((theme) => ({
gap: theme.spacing[1],
},
selectFieldLabel: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.medium,
textTransform: "uppercase",
@@ -1385,7 +1385,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.base,
},
selectFieldPlaceholder: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.base,
},
gitOptionsContainer: {
@@ -1395,7 +1395,7 @@ const styles = StyleSheet.create((theme) => ({
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[3],
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.lg,
@@ -1415,7 +1415,7 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
worktreeToggleDescription: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
baseBranchRow: {
@@ -1425,7 +1425,7 @@ const styles = StyleSheet.create((theme) => ({
paddingHorizontal: theme.spacing[4],
},
baseBranchLabel: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
baseBranchValueRow: {
@@ -1446,7 +1446,7 @@ const styles = StyleSheet.create((theme) => ({
},
baseBranchInput: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.md,
@@ -1469,7 +1469,7 @@ const styles = StyleSheet.create((theme) => ({
left: 0,
},
desktopDropdownContainer: {
backgroundColor: theme.colors.popover,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
@@ -1494,7 +1494,7 @@ const styles = StyleSheet.create((theme) => ({
flex: 1,
},
compactSelectControl: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.lg,
@@ -1506,7 +1506,7 @@ const styles = StyleSheet.create((theme) => ({
opacity: theme.opacity[50],
},
compactSelectLabel: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.medium,
textTransform: "uppercase",
@@ -1517,7 +1517,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.sm,
},
compactSelectPlaceholder: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
}));
@@ -22,6 +22,7 @@ import { AgentStatusBar } from "./agent-status-bar";
import { RealtimeControls } from "./realtime-controls";
import { useImageAttachmentPicker } from "@/hooks/use-image-attachment-picker";
import { useSessionStore } from "@/stores/session-store";
import { useDraftStore } from "@/stores/draft-store";
import {
MessageInput,
type MessagePayload,
@@ -86,8 +87,8 @@ export function AgentInputArea({
state.sessions[serverId]?.agents?.get(agentId)
);
const getDraftInput = useSessionStore((state) => state.getDraftInput);
const saveDraftInput = useSessionStore((state) => state.saveDraftInput);
const getDraftInput = useDraftStore((state) => state.getDraftInput);
const saveDraftInput = useDraftStore((state) => state.saveDraftInput);
const queuedMessagesRaw = useSessionStore((state) =>
state.sessions[serverId]?.queuedMessages?.get(agentId)
@@ -639,7 +640,7 @@ const styles = StyleSheet.create(((theme: Theme) => ({
justifyContent: "space-between",
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
@@ -661,7 +662,7 @@ const styles = StyleSheet.create(((theme: Theme) => ({
borderRadius: theme.borderRadius.full,
alignItems: "center",
justifyContent: "center",
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
queueSendButton: {
backgroundColor: theme.colors.palette.blue[600],
+14 -14
View File
@@ -94,7 +94,7 @@ export function AgentList({
const isRunning = agent.status === "running";
const agentKey = `${agent.serverId}:${agent.id}`;
const isSelected = selectedAgentId === agentKey;
const statusColor = isRunning ? "#3b82f6" : agent.requiresAttention ? "#22c55e" : null;
const statusColor = isRunning ? theme.colors.accent : agent.requiresAttention ? theme.colors.success : null;
return (
<Pressable
@@ -162,8 +162,8 @@ export function AgentList({
<RefreshControl
refreshing={isRefreshing}
onRefresh={onRefresh}
tintColor={theme.colors.mutedForeground}
colors={[theme.colors.mutedForeground]}
tintColor={theme.colors.foregroundMuted}
colors={[theme.colors.foregroundMuted]}
/>
) : undefined
}
@@ -225,19 +225,19 @@ const styles = StyleSheet.create((theme) => ({
paddingBottom: theme.spacing[4],
},
agentItem: {
paddingVertical: theme.spacing[3],
paddingVertical: theme.spacing[2],
paddingHorizontal: theme.spacing[3],
borderRadius: theme.borderRadius.lg,
marginBottom: theme.spacing[2],
marginBottom: theme.spacing[1],
},
agentItemSelected: {
backgroundColor: theme.colors.palette.zinc[800],
backgroundColor: theme.colors.surface2,
},
agentItemHovered: {
backgroundColor: theme.colors.palette.zinc[850],
backgroundColor: theme.colors.surface1,
},
agentItemPressed: {
backgroundColor: theme.colors.palette.zinc[800],
backgroundColor: theme.colors.surface2,
},
agentContent: {
flex: 1,
@@ -255,7 +255,7 @@ const styles = StyleSheet.create((theme) => ({
xs: "400",
md: "300",
},
color: theme.colors.palette.zinc[200],
color: theme.colors.foregroundMuted,
},
agentTitleHighlighted: {
color: theme.colors.foreground,
@@ -263,7 +263,7 @@ const styles = StyleSheet.create((theme) => ({
secondaryRow: {
fontSize: theme.fontSize.sm,
fontWeight: "300",
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
statusDot: {
width: 8,
@@ -283,7 +283,7 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: "rgba(0,0,0,0.35)",
},
sheetContainer: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderTopLeftRadius: theme.borderRadius["2xl"],
borderTopRightRadius: theme.borderRadius["2xl"],
paddingHorizontal: theme.spacing[6],
@@ -296,7 +296,7 @@ const styles = StyleSheet.create((theme) => ({
width: 40,
height: 4,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
sheetTitle: {
fontSize: theme.fontSize.lg,
@@ -305,7 +305,7 @@ const styles = StyleSheet.create((theme) => ({
},
sheetSubtitle: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
sheetButton: {
borderRadius: theme.borderRadius.lg,
@@ -324,7 +324,7 @@ const styles = StyleSheet.create((theme) => ({
opacity: 0.5,
},
sheetCancelButton: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
sheetCancelText: {
color: theme.colors.foreground,
@@ -52,7 +52,7 @@ export function AgentStatusBar({ agentId, serverId }: AgentStatusBarProps) {
agent.currentModeId ||
"default"}
</Text>
<ChevronDown size={14} color={theme.colors.mutedForeground} />
<ChevronDown size={14} color={theme.colors.foregroundMuted} />
</Pressable>
)}
@@ -76,17 +76,17 @@ const styles = StyleSheet.create((theme) => ({
modeBadge: {
flexDirection: "row",
alignItems: "center",
backgroundColor: theme.colors.popover,
backgroundColor: theme.colors.surface2,
gap: theme.spacing[1],
paddingHorizontal: theme.spacing[3],
paddingVertical: theme.spacing[2],
borderRadius: theme.borderRadius["2xl"],
},
modeBadgePressed: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
modeBadgeText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
textTransform: "capitalize",
@@ -85,9 +85,7 @@ export function AgentStreamView({
const [isNearBottom, setIsNearBottom] = useState(true);
const hasScrolledInitially = useRef(false);
const hasAutoScrolledOnce = useRef(false);
const isProgrammaticScrollRef = useRef(false);
const isNearBottomRef = useRef(true);
const isUserScrollingRef = useRef(false);
const streamItemCountRef = useRef(0);
const { open: openExplorer, setActiveTab: setExplorerTab } =
useExplorerSidebarStore();
@@ -160,42 +158,17 @@ export function AgentStreamView({
(event: NativeSyntheticEvent<NativeScrollEvent>) => {
const { contentOffset } = event.nativeEvent;
const threshold = Math.max(insets.bottom, 32);
// In inverted list: scrollTop 0 = bottom, higher values = scrolled up
const nearBottom = contentOffset.y <= threshold;
if (isProgrammaticScrollRef.current) {
if (nearBottom && !isNearBottomRef.current) {
isNearBottomRef.current = true;
setIsNearBottom(true);
}
return;
if (isNearBottomRef.current !== nearBottom) {
isNearBottomRef.current = nearBottom;
setIsNearBottom(nearBottom);
}
if (!nearBottom && !isUserScrollingRef.current) {
return;
}
if (isNearBottomRef.current === nearBottom) {
return;
}
isNearBottomRef.current = nearBottom;
setIsNearBottom(nearBottom);
},
[insets.bottom]
);
const handleScrollBeginDrag = useCallback(() => {
isUserScrollingRef.current = true;
}, []);
const handleMomentumScrollBegin = useCallback(() => {
isUserScrollingRef.current = true;
}, []);
const handleScrollEnd = useCallback(() => {
isUserScrollingRef.current = false;
}, []);
const scrollToBottomInternal = useCallback(
({ animated }: { animated: boolean }) => {
const list = flatListRef.current;
@@ -203,19 +176,9 @@ export function AgentStreamView({
return;
}
isProgrammaticScrollRef.current = true;
list.scrollToOffset({ offset: 0, animated });
if (!animated) {
isProgrammaticScrollRef.current = false;
isNearBottomRef.current = true;
setIsNearBottom(true);
} else {
setTimeout(() => {
isProgrammaticScrollRef.current = false;
isNearBottomRef.current = true;
setIsNearBottom(true);
}, 300);
}
isNearBottomRef.current = true;
setIsNearBottom(true);
},
[]
);
@@ -582,10 +545,6 @@ export function AgentStreamView({
}}
style={stylesheet.list}
onScroll={handleScroll}
onScrollBeginDrag={handleScrollBeginDrag}
onScrollEndDrag={handleScrollEnd}
onMomentumScrollBegin={handleMomentumScrollBegin}
onMomentumScrollEnd={handleScrollEnd}
scrollEventThrottle={16}
ListEmptyComponent={
<View style={[stylesheet.emptyState, stylesheet.contentWrapper]}>
@@ -1005,7 +964,7 @@ function PermissionRequestCard({
style={[
permissionStyles.container,
{
backgroundColor: theme.colors.secondary,
backgroundColor: theme.colors.surface2,
borderColor: theme.colors.border,
},
]}
@@ -1020,7 +979,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.description,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
{description}
@@ -1032,7 +991,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.sectionTitle,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
Proposed Plan
@@ -1041,7 +1000,7 @@ function PermissionRequestCard({
style={[
permissionStyles.contentCard,
{
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderColor: theme.colors.border,
},
]}
@@ -1058,7 +1017,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.sectionTitle,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
Command
@@ -1068,7 +1027,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.metadataLabel,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
Command
@@ -1088,7 +1047,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.metadataLabel,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
Directory
@@ -1111,7 +1070,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.sectionTitle,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
Proposed Changes
@@ -1127,7 +1086,7 @@ function PermissionRequestCard({
permissionStyles.fileBadge,
{
borderColor: theme.colors.border,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
]}
>
@@ -1146,7 +1105,7 @@ function PermissionRequestCard({
permissionStyles.diffWrapper,
{
borderColor: theme.colors.border,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
]}
>
@@ -1162,7 +1121,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.sectionTitle,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
File Content
@@ -1173,7 +1132,7 @@ function PermissionRequestCard({
style={[
permissionStyles.contentCard,
{
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderColor: theme.colors.border,
},
]}
@@ -1183,7 +1142,7 @@ function PermissionRequestCard({
style={[
permissionStyles.metadataLabel,
{
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
marginBottom: theme.spacing[1],
},
]}
@@ -1209,7 +1168,7 @@ function PermissionRequestCard({
<Text
style={[
permissionStyles.sectionTitle,
{ color: theme.colors.mutedForeground },
{ color: theme.colors.foregroundMuted },
]}
>
Raw Request
@@ -1218,7 +1177,7 @@ function PermissionRequestCard({
style={[
permissionStyles.contentCard,
{
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderColor: theme.colors.border,
},
]}
@@ -1306,7 +1265,7 @@ function PermissionRequestCard({
const stylesheet = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
contentWrapper: {
width: "100%",
@@ -1361,14 +1320,14 @@ const stylesheet = StyleSheet.create((theme) => ({
width: 6,
height: 6,
borderRadius: 3,
backgroundColor: theme.colors.mutedForeground,
backgroundColor: theme.colors.foregroundMuted,
},
invertedWrapper: {
transform: [{ scaleY: -1 }],
width: "100%",
},
emptyStateText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
textAlign: "center",
},
@@ -1390,7 +1349,7 @@ const stylesheet = StyleSheet.create((theme) => ({
width: 48,
height: 48,
borderRadius: 24,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
alignItems: "center",
justifyContent: "center",
shadowColor: "#000",
+10 -10
View File
@@ -26,7 +26,7 @@ interface ArtifactDrawerProps {
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
flexDirection: "column",
},
header: {
@@ -77,7 +77,7 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
closeButton: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
width: 40,
height: 40,
borderRadius: 20,
@@ -91,7 +91,7 @@ const styles = StyleSheet.create((theme) => ({
},
contentScroll: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
contentScrollContainer: {
padding: theme.spacing[4],
@@ -103,16 +103,16 @@ const styles = StyleSheet.create((theme) => ({
justifyContent: "center",
},
imagePlaceholderText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
imagePlaceholderSubtext: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
marginTop: theme.spacing[2],
},
codeContainer: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing[4],
borderWidth: theme.borderWidth[1],
@@ -124,14 +124,14 @@ const styles = StyleSheet.create((theme) => ({
fontFamily: Fonts.mono,
},
metadataContainer: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
padding: theme.spacing[3],
borderTopWidth: theme.borderWidth[1],
borderTopColor: theme.colors.border,
marginTop: theme.spacing[2],
},
metadataTitle: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
marginBottom: theme.spacing[2],
@@ -141,12 +141,12 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[1],
},
metadataLabel: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
width: 80,
},
metadataValue: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
flex: 1,
fontFamily: Fonts.mono,
@@ -100,16 +100,16 @@ export function AudioDebugNotice({ info, onDismiss, title = "Dictation Debug" }:
style={[
styles.container,
{
backgroundColor: theme.colors.secondary,
backgroundColor: theme.colors.surface2,
borderColor: theme.colors.border,
},
]}
>
<View style={styles.headerRow}>
<Text style={[styles.title, { color: theme.colors.mutedForeground }]}>{title}</Text>
<Text style={[styles.title, { color: theme.colors.foregroundMuted }]}>{title}</Text>
{onDismiss ? (
<Pressable accessibilityLabel="Dismiss audio debug" onPress={onDismiss} hitSlop={8}>
<X size={14} color={theme.colors.mutedForeground} />
<X size={14} color={theme.colors.foregroundMuted} />
</Pressable>
) : null}
</View>
@@ -131,13 +131,13 @@ export function AudioDebugNotice({ info, onDismiss, title = "Dictation Debug" }:
</View>
</Pressable>
) : (
<Text style={[styles.hint, { color: theme.colors.mutedForeground }]}>
<Text style={[styles.hint, { color: theme.colors.foregroundMuted }]}>
Raw audio path unavailable. Set STT_DEBUG_AUDIO_DIR on the server to persist recordings.
</Text>
)}
{stats ? (
<Text style={[styles.stats, { color: theme.colors.mutedForeground }]}>
<Text style={[styles.stats, { color: theme.colors.foregroundMuted }]}>
{stats}
</Text>
) : null}
@@ -108,7 +108,7 @@ export function useCommandAutocomplete(commands: AgentSlashCommand[], filter: st
const styles = StyleSheet.create(((theme: Theme) => ({
container: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.lg,
@@ -136,12 +136,12 @@ const styles = StyleSheet.create(((theme: Theme) => ({
fontFamily: Fonts.mono,
},
commandArgs: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontFamily: Fonts.mono,
},
commandDescription: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
marginTop: 2,
},
@@ -150,7 +150,7 @@ const styles = StyleSheet.create(((theme: Theme) => ({
paddingVertical: theme.spacing[3],
},
loadingText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
emptyItem: {
@@ -158,7 +158,7 @@ const styles = StyleSheet.create(((theme: Theme) => ({
paddingVertical: theme.spacing[3],
},
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
})) as any) as Record<string, any>;
@@ -317,7 +317,7 @@ export function ConversationSelector({
const styles = StyleSheet.create((theme) => ({
triggerButton: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
padding: theme.spacing[3],
borderRadius: theme.borderRadius.lg,
},
@@ -329,7 +329,7 @@ const styles = StyleSheet.create((theme) => ({
flex: 1,
},
modalContent: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderTopLeftRadius: theme.spacing[6],
borderTopRightRadius: theme.spacing[6],
height: "80%",
@@ -360,7 +360,7 @@ const styles = StyleSheet.create((theme) => ({
alignItems: "center",
justifyContent: "center",
gap: theme.spacing[2],
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
paddingVertical: theme.spacing[3],
borderRadius: theme.borderRadius.lg,
},
@@ -379,14 +379,14 @@ const styles = StyleSheet.create((theme) => ({
alignItems: "center",
},
loadingText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
emptyContainer: {
padding: theme.spacing[8],
alignItems: "center",
},
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
conversationItem: {
flexDirection: "row",
@@ -398,7 +398,7 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: "transparent",
},
conversationItemActive: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
conversationContent: {
flex: 1,
@@ -409,7 +409,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.base,
},
conversationDate: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
marginTop: theme.spacing[1],
},
@@ -102,7 +102,7 @@ export function DictationControls({
accessibilityLabel="Retry dictation"
style={[styles.actionButton, styles.actionButtonConfirm]}
>
<RefreshCcw size={14} color={theme.colors.background} />
<RefreshCcw size={14} color={theme.colors.surface0} />
</Pressable>
) : (
<>
@@ -118,7 +118,7 @@ export function DictationControls({
accessibilityLabel="Insert transcription and send"
style={[styles.actionButton, styles.actionButtonConfirm]}
>
<ArrowUp size={14} color={theme.colors.background} />
<ArrowUp size={14} color={theme.colors.surface0} />
</Pressable>
</>
)}
@@ -165,7 +165,7 @@ export function DictationOverlay({
<View
style={[
overlayStyles.container,
{ backgroundColor: theme.colors.palette.blue[600] },
{ backgroundColor: theme.colors.accent },
]}
>
<Pressable
@@ -215,7 +215,7 @@ export function DictationOverlay({
>
<RefreshCcw
size={20}
color={theme.colors.palette.blue[600]}
color={theme.colors.accent}
strokeWidth={2.5}
/>
</Pressable>
@@ -243,7 +243,7 @@ export function DictationOverlay({
>
<ArrowUp
size={20}
color={theme.colors.palette.blue[600]}
color={theme.colors.accent}
strokeWidth={2.5}
/>
</Pressable>
@@ -265,7 +265,7 @@ const styles = StyleSheet.create((theme) => ({
justifyContent: "center",
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
activeContainer: {
flexDirection: "row",
@@ -296,11 +296,11 @@ const styles = StyleSheet.create((theme) => ({
},
actionButtonCancel: {
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
actionButtonSecondary: {
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
actionButtonConfirm: {
borderColor: theme.colors.foreground,
@@ -48,12 +48,12 @@ export function DictationStatusNotice({
case "error":
return theme.colors.palette.red[500];
default:
return theme.colors.background;
return theme.colors.surface0;
}
})();
const foregroundColor = variant === "info" ? theme.colors.foreground : theme.colors.palette.white;
const secondaryColor = variant === "info" ? theme.colors.mutedForeground : theme.colors.palette.white;
const secondaryColor = variant === "info" ? theme.colors.foregroundMuted : theme.colors.palette.white;
return (
<View
+7 -7
View File
@@ -108,22 +108,22 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.foreground,
},
headerLine: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
headerText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
addLine: {
backgroundColor: "rgba(46, 160, 67, 0.15)",
},
addText: {
color: theme.colors.foreground,
color: theme.colors.palette.green[800],
},
removeLine: {
backgroundColor: "rgba(248, 81, 73, 0.1)",
},
removeText: {
color: theme.colors.foreground,
color: theme.colors.palette.red[800],
},
addHighlight: {
backgroundColor: "rgba(46, 160, 67, 0.4)",
@@ -132,10 +132,10 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: "rgba(248, 81, 73, 0.35)",
},
contextLine: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
contextText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
emptyState: {
padding: theme.spacing[4],
@@ -144,6 +144,6 @@ const styles = StyleSheet.create((theme) => ({
},
emptyText: {
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
}));
+2 -2
View File
@@ -49,7 +49,7 @@ const styles = StyleSheet.create((theme) => ({
},
subtitle: {
fontSize: theme.fontSize.lg,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
textAlign: "center",
marginBottom: theme.spacing[8],
},
@@ -77,7 +77,7 @@ const styles = StyleSheet.create((theme) => ({
secondaryButton: {
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
secondaryButtonText: {
fontSize: theme.fontSize.base,
@@ -251,7 +251,7 @@ function SidebarContent({
color={
activeTab === "changes"
? theme.colors.foreground
: theme.colors.mutedForeground
: theme.colors.foregroundMuted
}
/>
<Text
@@ -272,7 +272,7 @@ function SidebarContent({
color={
activeTab === "files"
? theme.colors.foreground
: theme.colors.mutedForeground
: theme.colors.foregroundMuted
}
/>
<Text
@@ -291,7 +291,7 @@ function SidebarContent({
)}
{isMobile && (
<Pressable onPress={onClose} style={styles.closeButton}>
<X size={18} color={theme.colors.mutedForeground} />
<X size={18} color={theme.colors.foregroundMuted} />
</Pressable>
)}
</View>
@@ -352,14 +352,14 @@ const styles = StyleSheet.create((theme) => ({
top: 0,
right: 0,
bottom: 0,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
overflow: "hidden",
},
desktopSidebar: {
position: "relative",
borderLeftWidth: 1,
borderLeftColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
resizeHandle: {
position: "absolute",
@@ -396,12 +396,12 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.md,
},
tabActive: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
tabText: {
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.normal,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
tabTextActive: {
color: theme.colors.foreground,
@@ -430,6 +430,6 @@ const styles = StyleSheet.create((theme) => ({
padding: theme.spacing[2],
},
viewToggleActive: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
}));
@@ -80,7 +80,7 @@ const styles = StyleSheet.create((theme) => ({
},
backdrop: {
...StyleSheet.absoluteFillObject,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
opacity: 0.7,
},
overlayContent: {
@@ -756,7 +756,7 @@ export function FileExplorerPane({
</View>
<Pressable style={styles.sortButton} onPress={handleSortCycle}>
<Text style={styles.sortButtonText}>{currentSortLabel}</Text>
<ChevronDown size={14} color={theme.colors.mutedForeground} />
<ChevronDown size={14} color={theme.colors.foregroundMuted} />
</Pressable>
</View>
{showListLoadingBanner && (
@@ -947,7 +947,7 @@ export function FileExplorerPane({
{selectedEntryPath?.split("/").pop() ?? "Preview"}
</Text>
<Pressable onPress={handleClosePreviewSheet} style={styles.sheetCloseButton}>
<X size={20} color={theme.colors.mutedForeground} />
<X size={20} color={theme.colors.foregroundMuted} />
</Pressable>
</View>
{isPreviewLoading && !preview ? (
@@ -1030,7 +1030,7 @@ export function FileExplorerPane({
hitSlop={8}
style={styles.downloadToastDismiss}
>
<X size={16} color={theme.colors.mutedForeground} />
<X size={16} color={theme.colors.foregroundMuted} />
</Pressable>
)}
</View>
@@ -1291,7 +1291,7 @@ function splitFileName(fileName: string): { base: string; ext: string } {
const styles = StyleSheet.create((theme) => ({
container: {
flex: 1,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
content: {
flex: 1,
@@ -1325,7 +1325,7 @@ const styles = StyleSheet.create((theme) => ({
pathText: {
flex: 1,
fontSize: theme.fontSize.sm,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontFamily: Fonts.mono,
},
backButton: {
@@ -1343,7 +1343,7 @@ const styles = StyleSheet.create((theme) => ({
paddingHorizontal: theme.spacing[3],
},
loadingBannerText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
sortButton: {
@@ -1355,10 +1355,10 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.md,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
sortButtonText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
centerState: {
@@ -1369,7 +1369,7 @@ const styles = StyleSheet.create((theme) => ({
padding: theme.spacing[4],
},
loadingText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
errorText: {
@@ -1401,12 +1401,12 @@ const styles = StyleSheet.create((theme) => ({
paddingVertical: theme.spacing[1],
},
goToWorkspaceButtonText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontWeight: theme.fontWeight.semibold,
},
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.base,
textAlign: "center",
},
@@ -1422,7 +1422,7 @@ const styles = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[1],
},
entryRowBackground: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
entryInfo: {
flex: 1,
@@ -1443,7 +1443,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.base,
},
entryMeta: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
marginTop: theme.spacing[1],
},
@@ -1465,7 +1465,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.md,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
padding: theme.spacing[1],
},
entryMenuItem: {
@@ -1499,7 +1499,7 @@ const styles = StyleSheet.create((theme) => ({
borderColor: theme.colors.border,
padding: theme.spacing[2],
gap: theme.spacing[2],
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
marginHorizontal: theme.spacing[1],
marginBottom: theme.spacing[1],
minWidth: 0,
@@ -1511,10 +1511,10 @@ const styles = StyleSheet.create((theme) => ({
alignItems: "center",
justifyContent: "center",
overflow: "hidden",
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
gridImageBackground: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
gridImage: {
width: "100%",
@@ -1525,11 +1525,11 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.sm,
},
gridMeta: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
sheetBackground: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
handleIndicator: {
backgroundColor: theme.colors.palette.zinc[600],
@@ -1586,7 +1586,7 @@ const styles = StyleSheet.create((theme) => ({
flexDirection: "row",
alignItems: "center",
gap: theme.spacing[3],
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
@@ -1608,12 +1608,12 @@ const styles = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
downloadToastStatus: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
downloadProgressBar: {
height: 3,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.full,
marginTop: theme.spacing[1],
overflow: "hidden",
+65 -43
View File
@@ -37,41 +37,63 @@ interface HighlightedTextProps {
lineType: "add" | "remove" | "context" | "header";
}
// GitHub syntax highlight colors for dark/light modes
const darkHighlightColors: Record<HighlightStyle, string> = {
keyword: "#ff7b72",
comment: "#8b949e",
string: "#a5d6ff",
number: "#79c0ff",
literal: "#79c0ff",
function: "#d2a8ff",
definition: "#d2a8ff",
class: "#ffa657",
type: "#ff7b72",
tag: "#7ee787",
attribute: "#79c0ff",
property: "#79c0ff",
variable: "#c9d1d9",
operator: "#79c0ff",
punctuation: "#c9d1d9",
regexp: "#a5d6ff",
escape: "#79c0ff",
meta: "#8b949e",
heading: "#79c0ff",
link: "#a5d6ff",
};
const lightHighlightColors: Record<HighlightStyle, string> = {
keyword: "#cf222e",
comment: "#6e7781",
string: "#0a3069",
number: "#0550ae",
literal: "#0550ae",
function: "#8250df",
definition: "#8250df",
class: "#953800",
type: "#cf222e",
tag: "#116329",
attribute: "#0550ae",
property: "#0550ae",
variable: "#24292f",
operator: "#0550ae",
punctuation: "#24292f",
regexp: "#0a3069",
escape: "#0550ae",
meta: "#6e7781",
heading: "#0550ae",
link: "#0a3069",
};
function HighlightedText({ tokens, lineType }: HighlightedTextProps) {
const { theme } = useUnistyles();
const isDark = theme.colors.surface0 === "#18181c";
// Get color for a highlight style using GitHub Dark theme
// Text colors are the same regardless of line type - only background changes
// Get color for a highlight style
const getTokenColor = (style: HighlightStyle | null): string => {
const baseColor = "#c9d1d9"; // GitHub foreground
const baseColor = isDark ? "#c9d1d9" : "#24292f";
if (!style) return baseColor;
// GitHub Dark theme colors
const highlightColors: Record<HighlightStyle, string> = {
keyword: "#ff7b72", // red
comment: "#8b949e", // gray
string: "#a5d6ff", // light blue
number: "#79c0ff", // blue
literal: "#79c0ff", // blue
function: "#d2a8ff", // purple
definition: "#d2a8ff", // purple
class: "#ffa657", // orange
type: "#ff7b72", // red (same as keyword in GitHub)
tag: "#7ee787", // green
attribute: "#79c0ff", // blue
property: "#79c0ff", // blue
variable: baseColor,
operator: "#79c0ff", // blue
punctuation: "#c9d1d9", // foreground
regexp: "#a5d6ff", // light blue
escape: "#79c0ff", // blue
meta: "#8b949e", // gray
heading: "#79c0ff", // blue
link: "#a5d6ff", // light blue
};
return highlightColors[style] ?? baseColor;
const colors = isDark ? darkHighlightColors : lightHighlightColors;
return colors[style] ?? baseColor;
};
return (
@@ -253,7 +275,7 @@ const DiffFileSection = memo(function DiffFileSection({
>
<ChevronRight
size={16}
color={theme.colors.mutedForeground}
color={theme.colors.foregroundMuted}
/>
</View>
<Text style={styles.filePath} numberOfLines={1} ellipsizeMode="middle">
@@ -470,7 +492,7 @@ const styles = StyleSheet.create((theme) => ({
},
loadingText: {
fontSize: theme.fontSize.base,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
errorContainer: {
flex: 1,
@@ -492,14 +514,14 @@ const styles = StyleSheet.create((theme) => ({
},
emptyText: {
fontSize: theme.fontSize.lg,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
fileSection: {
borderRadius: theme.borderRadius.lg,
overflow: "hidden",
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.accentBorder,
borderColor: theme.colors.borderAccent,
marginBottom: theme.spacing[2],
},
fileHeader: {
@@ -566,13 +588,13 @@ const styles = StyleSheet.create((theme) => ({
diffContent: {
borderTopWidth: theme.borderWidth[1],
borderTopColor: theme.colors.border,
backgroundColor: "#0d1117",
backgroundColor: theme.colors.surface1,
},
diffContentInner: {
flexDirection: "column",
},
linesContainer: {
backgroundColor: "#0d1117",
backgroundColor: theme.colors.surface1,
},
diffLineContainer: {
paddingHorizontal: theme.spacing[3],
@@ -587,24 +609,24 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: "rgba(46, 160, 67, 0.15)", // GitHub green
},
addLineText: {
color: "#c9d1d9", // Same text color as all code
color: theme.colors.foreground,
},
removeLineContainer: {
backgroundColor: "rgba(248, 81, 73, 0.1)", // GitHub red
},
removeLineText: {
color: "#c9d1d9", // Same text color as all code
color: theme.colors.foreground,
},
headerLineContainer: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
headerLineText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
contextLineContainer: {
backgroundColor: "#0d1117",
backgroundColor: theme.colors.surface1,
},
contextLineText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
}));
@@ -22,7 +22,7 @@ export function BackHeader({ title, rightContent, onBack }: BackHeaderProps) {
onPress={onBack ?? (() => router.back())}
style={styles.backButton}
>
<ArrowLeft size={20} color={theme.colors.mutedForeground} />
<ArrowLeft size={20} color={theme.colors.foregroundMuted} />
</Pressable>
{title && (
<Text style={styles.title} numberOfLines={1}>
@@ -19,7 +19,7 @@ export function MenuHeader({ title, rightContent }: MenuHeaderProps) {
const MenuIcon = isMobile ? Menu : PanelLeft;
const menuIconColor = !isMobile && isOpen
? theme.colors.foreground
: theme.colors.mutedForeground;
: theme.colors.foregroundMuted;
return (
<ScreenHeader
@@ -35,7 +35,7 @@ export function ScreenHeader({ left, right, leftStyle, rightStyle }: ScreenHeade
const styles = StyleSheet.create((theme) => ({
header: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
inner: {},
row: {
+4 -4
View File
@@ -212,7 +212,7 @@ export function HomeFooter() {
const styles = StyleSheet.create((theme) => ({
container: {
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
borderTopWidth: theme.borderWidth[1],
borderTopColor: theme.colors.border,
},
@@ -264,7 +264,7 @@ const styles = StyleSheet.create((theme) => ({
flex: 1,
},
hostPickerContainer: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
padding: theme.spacing[4],
borderTopLeftRadius: theme.borderRadius.xl,
borderTopRightRadius: theme.borderRadius.xl,
@@ -279,7 +279,7 @@ const styles = StyleSheet.create((theme) => ({
hostPickerButton: {
paddingVertical: theme.spacing[3],
borderRadius: theme.borderRadius.lg,
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
hostPickerButtonText: {
color: theme.colors.foreground,
@@ -290,7 +290,7 @@ const styles = StyleSheet.create((theme) => ({
paddingVertical: theme.spacing[3],
},
hostPickerCancelText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
textAlign: "center",
},
@@ -616,9 +616,9 @@ const styles = StyleSheet.create(((theme: any) => ({
inputWrapper: {
flexDirection: "column",
gap: theme.spacing[3],
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.accentBorder,
borderColor: theme.colors.borderAccent,
borderRadius: theme.borderRadius["2xl"],
paddingVertical: {
xs: theme.spacing[2],
@@ -645,7 +645,7 @@ const styles = StyleSheet.create(((theme: any) => ({
position: "relative",
borderRadius: theme.borderRadius.md,
borderWidth: 1,
borderColor: theme.colors.accentBorder,
borderColor: theme.colors.borderAccent,
overflow: "hidden",
...(IS_WEB
? {
@@ -726,7 +726,7 @@ const styles = StyleSheet.create(((theme: any) => ({
width: 34,
height: 34,
borderRadius: theme.borderRadius.full,
backgroundColor: theme.colors.palette.blue[600],
backgroundColor: theme.colors.accent,
alignItems: "center",
justifyContent: "center",
},
+21 -21
View File
@@ -99,7 +99,7 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[4],
},
bubble: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius["2xl"],
borderTopRightRadius: theme.borderRadius.sm,
paddingHorizontal: theme.spacing[4],
@@ -120,13 +120,13 @@ const userMessageStylesheet = StyleSheet.create((theme) => ({
marginTop: theme.spacing[1],
marginRight: theme.spacing[4],
alignSelf: "flex-end",
backgroundColor: theme.colors.secondary,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.base,
paddingHorizontal: theme.spacing[2],
paddingVertical: 4,
},
copiedTagText: {
color: theme.colors.secondaryForeground,
color: theme.colors.foreground,
fontSize: theme.fontSize.xs,
},
}));
@@ -231,8 +231,8 @@ export const assistantMessageStylesheet = StyleSheet.create((theme) => ({
},
// Used in custom markdownRules for inline code styling
markdownCodeInline: {
backgroundColor: theme.colors.secondary,
color: theme.colors.secondaryForeground,
backgroundColor: theme.colors.surface2,
color: theme.colors.foreground,
paddingHorizontal: theme.spacing[2],
paddingVertical: 2,
borderRadius: theme.borderRadius.sm,
@@ -241,7 +241,7 @@ export const assistantMessageStylesheet = StyleSheet.create((theme) => ({
},
// Used in custom markdownRules for path chip styling
pathChip: {
backgroundColor: theme.colors.secondary,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.full,
paddingHorizontal: theme.spacing[2],
paddingVertical: 2,
@@ -249,7 +249,7 @@ export const assistantMessageStylesheet = StyleSheet.create((theme) => ({
marginVertical: 2,
},
pathChipText: {
color: theme.colors.secondaryForeground,
color: theme.colors.foreground,
fontFamily: Fonts.mono,
fontSize: 13,
},
@@ -262,7 +262,7 @@ const turnCopyButtonStylesheet = StyleSheet.create((theme) => ({
marginLeft: theme.spacing[4],
},
iconColor: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
iconHoveredColor: {
color: theme.colors.foreground,
@@ -340,8 +340,8 @@ const expandableBadgeStylesheet = StyleSheet.create((theme) => ({
pressable: {
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.accentBorder,
backgroundColor: theme.colors.secondary,
borderColor: theme.colors.borderAccent,
backgroundColor: theme.colors.surface2,
paddingHorizontal: theme.spacing[2],
paddingVertical: theme.spacing[1],
},
@@ -369,7 +369,7 @@ const expandableBadgeStylesheet = StyleSheet.create((theme) => ({
},
secondaryLabel: {
flex: 1,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.base,
fontWeight: theme.fontWeight.normal,
marginLeft: theme.spacing[2],
@@ -386,7 +386,7 @@ const expandableBadgeStylesheet = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.md,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
padding: theme.spacing[2],
gap: theme.spacing[2],
flexShrink: 1,
@@ -721,7 +721,7 @@ const activityLogStylesheet = StyleSheet.create((theme) => ({
marginTop: theme.spacing[1],
},
detailsText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
marginRight: theme.spacing[1],
},
@@ -875,7 +875,7 @@ const todoListCardStylesheet = StyleSheet.create((theme) => ({
marginBottom: theme.spacing[2],
},
card: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
@@ -899,7 +899,7 @@ const todoListCardStylesheet = StyleSheet.create((theme) => ({
letterSpacing: 0.6,
},
timestamp: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
providerBadge: {
@@ -914,7 +914,7 @@ const todoListCardStylesheet = StyleSheet.create((theme) => ({
fontWeight: theme.fontWeight.semibold,
},
progressText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
marginBottom: theme.spacing[2],
},
@@ -946,11 +946,11 @@ const todoListCardStylesheet = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.sm,
},
itemTextCompleted: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
textDecorationLine: "line-through",
},
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontStyle: "italic",
},
@@ -979,7 +979,7 @@ export const TodoListCard = memo(function TodoListCard({
[timestamp]
);
const iconColor = theme.colors.background;
const iconColor = theme.colors.surface0;
return (
<View
@@ -1174,7 +1174,7 @@ const ExpandableBadge = memo(function ExpandableBadge({
{hasDetails ? (
<ChevronRight
size={14}
color={theme.colors.mutedForeground}
color={theme.colors.foregroundMuted}
style={[
expandableBadgeStylesheet.chevron,
{ transform: [{ rotate: isExpanded ? "90deg" : "0deg" }] },
@@ -1194,7 +1194,7 @@ const ExpandableBadge = memo(function ExpandableBadge({
const agentThoughtStylesheet = StyleSheet.create((theme) => ({
emptyText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontStyle: "italic" as const,
},
@@ -75,7 +75,7 @@ const styles = StyleSheet.create((theme) => ({
alignItems: "center",
},
modeSelectorContent: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
borderRadius: theme.borderRadius.lg,
padding: theme.spacing[4],
minWidth: 280,
@@ -85,7 +85,7 @@ const styles = StyleSheet.create((theme) => ({
padding: theme.spacing[4],
borderRadius: theme.borderRadius.md,
marginBottom: theme.spacing[2],
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
modeItemActive: {
backgroundColor: theme.colors.primary,
@@ -100,7 +100,7 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.primaryForeground,
},
modeDescription: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
modeDescriptionActive: {
@@ -48,7 +48,7 @@ export function RealtimeControls() {
size={20}
color={
isMuted
? theme.colors.background
? theme.colors.surface0
: theme.colors.foreground
}
/>
@@ -91,7 +91,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.full,
alignItems: "center",
justifyContent: "center",
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderWidth: theme.borderWidth[2],
borderColor: theme.colors.border,
},
@@ -226,7 +226,7 @@ export function SlidingSidebar({ selectedAgentId }: SlidingSidebarProps) {
style={styles.settingsButton}
onPress={handleSettingsMobile}
>
<Settings size={20} color={theme.colors.mutedForeground} />
<Settings size={20} color={theme.colors.foregroundMuted} />
<Text style={styles.settingsButtonText}>Settings</Text>
</Pressable>
</View>
@@ -273,7 +273,7 @@ export function SlidingSidebar({ selectedAgentId }: SlidingSidebarProps) {
style={styles.settingsButton}
onPress={handleSettingsDesktop}
>
<Settings size={20} color={theme.colors.mutedForeground} />
<Settings size={20} color={theme.colors.foregroundMuted} />
<Text style={styles.settingsButtonText}>Settings</Text>
</Pressable>
</View>
@@ -294,7 +294,7 @@ const styles = StyleSheet.create((theme) => ({
top: 0,
left: 0,
bottom: 0,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
overflow: "hidden",
},
sidebarContent: {
@@ -305,7 +305,7 @@ const styles = StyleSheet.create((theme) => ({
desktopSidebar: {
borderRightWidth: 1,
borderRightColor: theme.colors.border,
backgroundColor: theme.colors.background,
backgroundColor: theme.colors.surface0,
},
sidebarHeader: {
paddingHorizontal: theme.spacing[4],
@@ -326,7 +326,7 @@ const styles = StyleSheet.create((theme) => ({
},
newAgentButtonHovered: {
borderColor: theme.colors.palette.zinc[500],
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
newAgentButtonText: {
fontSize: theme.fontSize.base,
@@ -361,6 +361,6 @@ const styles = StyleSheet.create((theme) => ({
settingsButtonText: {
fontSize: theme.fontSize.base,
fontWeight: theme.fontWeight.normal,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
}));
@@ -357,7 +357,7 @@ const styles = StyleSheet.create((theme) => ({
gap: theme.spacing[2],
},
sectionTitle: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
fontWeight: theme.fontWeight.semibold,
textTransform: "uppercase",
@@ -370,7 +370,7 @@ const styles = StyleSheet.create((theme) => ({
borderRadius: theme.borderRadius.base,
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
fileBadgeText: {
color: theme.colors.foreground,
@@ -378,7 +378,7 @@ const styles = StyleSheet.create((theme) => ({
fontSize: theme.fontSize.xs,
},
rangeText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.xs,
},
diffContainer: {
@@ -386,13 +386,13 @@ const styles = StyleSheet.create((theme) => ({
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.base,
overflow: "hidden",
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
scrollArea: {
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.base,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
scrollContent: {
padding: theme.spacing[2],
@@ -407,7 +407,7 @@ const styles = StyleSheet.create((theme) => ({
borderWidth: theme.borderWidth[1],
borderColor: theme.colors.border,
borderRadius: theme.borderRadius.base,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
jsonScrollError: {
borderColor: theme.colors.destructive,
@@ -419,7 +419,7 @@ const styles = StyleSheet.create((theme) => ({
color: theme.colors.destructive,
},
emptyStateText: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
fontStyle: "italic",
},
@@ -7,11 +7,13 @@ import React, {
ReactNode,
} from "react";
import { View, Text, Pressable } from "react-native";
import { StyleSheet } from "react-native-unistyles";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import Animated from "react-native-reanimated";
import {
BottomSheetModal,
BottomSheetScrollView,
BottomSheetBackdrop,
BottomSheetBackgroundProps,
} from "@gorhom/bottom-sheet";
import { Pencil, Eye, SquareTerminal, Search, Wrench, X } from "lucide-react-native";
import { ToolCallDetailsContent, useToolCallDetails } from "./tool-call-details";
@@ -53,6 +55,17 @@ const toolKindIcons: Record<string, React.ComponentType<{ size?: number; color?:
search: Search,
};
// ----- Custom Background Component -----
function CustomSheetBackground({ style }: BottomSheetBackgroundProps) {
const { theme } = useUnistyles();
const containerStyle = useMemo(
() => [style, { backgroundColor: theme.colors.surface2, borderRadius: 16 }],
[style, theme.colors.surface2]
);
return <Animated.View pointerEvents="none" style={containerStyle} />;
}
// ----- Provider Component -----
interface ToolCallSheetProviderProps {
@@ -163,14 +176,14 @@ function ToolCallSheetContent({ data, onClose }: ToolCallSheetContentProps) {
const styles = StyleSheet.create((theme) => ({
sheetBackground: {
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
handleIndicator: {
backgroundColor: theme.colors.palette.zinc[600],
},
container: {
flex: 1,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
header: {
flexDirection: "row",
@@ -200,11 +213,11 @@ const styles = StyleSheet.create((theme) => ({
padding: theme.spacing[2],
},
closeIcon: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
content: {
flex: 1,
backgroundColor: theme.colors.card,
backgroundColor: theme.colors.surface2,
},
contentContainer: {
paddingHorizontal: theme.spacing[4],
+2 -2
View File
@@ -32,7 +32,7 @@ const styles = StyleSheet.create((theme) => ({
elevation: 8,
},
buttonIdle: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
},
buttonRecording: {
backgroundColor: theme.colors.destructive,
@@ -44,7 +44,7 @@ const styles = StyleSheet.create((theme) => ({
backgroundColor: theme.colors.palette.green[500],
},
label: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
fontSize: theme.fontSize.sm,
},
// Recording icon
@@ -35,13 +35,14 @@ import {
type SessionState,
type DaemonConnectionSnapshot,
} from "@/stores/session-store";
import { useDraftStore } from "@/stores/draft-store";
import type { AgentDirectoryEntry } from "@/types/agent-directory";
import { sendOsNotification } from "@/utils/os-notifications";
// Re-export types from session-store for backward compatibility
// Re-export types from session-store and draft-store for backward compatibility
export type { DraftInput } from "@/stores/draft-store";
export type {
MessageEntry,
DraftInput,
ProviderModelState,
Agent,
ExplorerEntry,
@@ -428,8 +429,7 @@ export function SessionProvider({
const setGitDiffs = useSessionStore((state) => state.setGitDiffs);
const setFileExplorer = useSessionStore((state) => state.setFileExplorer);
const setProviderModels = useSessionStore((state) => state.setProviderModels);
const getDraftInput = useSessionStore((state) => state.getDraftInput);
const saveDraftInput = useSessionStore((state) => state.saveDraftInput);
const clearDraftInput = useDraftStore((state) => state.clearDraftInput);
const setQueuedMessages = useSessionStore((state) => state.setQueuedMessages);
const getSession = useSessionStore((state) => state.getSession);
const updateSessionClient = useSessionStore((state) => state.updateSessionClient);
@@ -1515,7 +1515,7 @@ export function SessionProvider({
clearAgentStreamHead(serverId, agentId);
// Remove draft input
saveDraftInput(agentId, { text: "", images: [] });
clearDraftInput(agentId);
setPendingPermissions(serverId, (prev) => {
let changed = false;
@@ -1592,7 +1592,7 @@ export function SessionProvider({
setHasHydratedAgents,
updateConnectionStatus,
getSession,
saveDraftInput,
clearDraftInput,
notifyAgentAttention,
]);
+64
View File
@@ -0,0 +1,64 @@
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
import AsyncStorage from "@react-native-async-storage/async-storage";
export interface DraftInput {
text: string;
images: Array<{ uri: string; mimeType: string }>;
}
interface DraftStoreState {
drafts: Record<string, DraftInput>;
createModalDraft: DraftInput | null;
}
interface DraftStoreActions {
getDraftInput: (agentId: string) => DraftInput | undefined;
saveDraftInput: (agentId: string, draft: DraftInput) => void;
clearDraftInput: (agentId: string) => void;
getCreateModalDraft: () => DraftInput | null;
saveCreateModalDraft: (draft: DraftInput | null) => void;
}
type DraftStore = DraftStoreState & DraftStoreActions;
export const useDraftStore = create<DraftStore>()(
persist(
(set, get) => ({
drafts: {},
createModalDraft: null,
getDraftInput: (agentId) => {
return get().drafts[agentId];
},
saveDraftInput: (agentId, draft) => {
set((state) => ({
drafts: {
...state.drafts,
[agentId]: draft,
},
}));
},
clearDraftInput: (agentId) => {
set((state) => {
const { [agentId]: _, ...rest } = state.drafts;
return { drafts: rest };
});
},
getCreateModalDraft: () => {
return get().createModalDraft;
},
saveCreateModalDraft: (draft) => {
set({ createModalDraft: draft });
},
}),
{
name: "paseo-drafts",
storage: createJSONStorage(() => AsyncStorage),
}
)
);
-49
View File
@@ -60,11 +60,6 @@ export type MessageEntry =
status: "executing" | "completed" | "failed";
};
export type DraftInput = {
text: string;
images: Array<{ uri: string; mimeType: string }>;
};
export type ProviderModelState = {
models: AgentModelDefinition[] | null;
fetchedAt: Date | null;
@@ -250,12 +245,6 @@ export interface SessionState {
interface SessionStoreState {
sessions: Record<string, SessionState>;
// Top-level drafts (keyed by agentId, not serverId:agentId since agent IDs are globally unique)
drafts: Map<string, DraftInput>;
// Single draft for the create agent modal
createModalDraft: DraftInput | null;
// Agent activity timestamps (top-level, keyed by agentId to prevent cascade rerenders)
agentLastActivity: Map<string, Date>;
}
@@ -305,14 +294,6 @@ interface SessionStoreActions {
// Provider models
setProviderModels: (serverId: string, models: Map<AgentProvider, ProviderModelState> | ((prev: Map<AgentProvider, ProviderModelState>) => Map<AgentProvider, ProviderModelState>)) => void;
// Draft inputs (top-level, not in sessions)
getDraftInput: (agentId: string) => DraftInput | undefined;
saveDraftInput: (agentId: string, draft: DraftInput) => void;
// Create modal draft
getCreateModalDraft: () => DraftInput | null;
saveCreateModalDraft: (draft: DraftInput | null) => void;
// Queued messages
setQueuedMessages: (serverId: string, value: Map<string, Array<{ id: string; text: string; images?: Array<{ uri: string; mimeType: string }> }>> | ((prev: Map<string, Array<{ id: string; text: string; images?: Array<{ uri: string; mimeType: string }> }>>) => Map<string, Array<{ id: string; text: string; images?: Array<{ uri: string; mimeType: string }> }>>)) => void;
@@ -392,8 +373,6 @@ function createInitialSessionState(serverId: string, client: DaemonClientV2, aud
export const useSessionStore = create<SessionStore>()(
subscribeWithSelector((set, get) => ({
sessions: {},
drafts: new Map(),
createModalDraft: null,
agentLastActivity: new Map(),
// Session management
@@ -779,34 +758,6 @@ export const useSessionStore = create<SessionStore>()(
});
},
// Draft inputs (top-level, keyed by agentId only)
getDraftInput: (agentId) => {
return get().drafts.get(agentId);
},
saveDraftInput: (agentId, draft) => {
set((prev) => {
const nextDrafts = new Map(prev.drafts);
nextDrafts.set(agentId, draft);
return {
...prev,
drafts: nextDrafts,
};
});
},
// Create modal draft
getCreateModalDraft: () => {
return get().createModalDraft;
},
saveCreateModalDraft: (draft) => {
set((prev) => ({
...prev,
createModalDraft: draft,
}));
},
// Queued messages
setQueuedMessages: (serverId, value) => {
set((prev) => {
+14 -14
View File
@@ -91,7 +91,7 @@ export function createMarkdownStyles(theme: Theme) {
heading6: {
fontSize: theme.fontSize.base,
fontWeight: theme.fontWeight.semibold,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
marginTop: theme.spacing[3],
marginBottom: theme.spacing[1],
lineHeight: 20,
@@ -104,7 +104,7 @@ export function createMarkdownStyles(theme: Theme) {
// =========================================================================
strong: {
fontWeight: theme.fontWeight.bold,
fontWeight: theme.fontWeight.medium,
},
em: {
@@ -113,7 +113,7 @@ export function createMarkdownStyles(theme: Theme) {
s: {
textDecorationLine: "line-through" as const,
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
},
link: {
@@ -131,8 +131,8 @@ export function createMarkdownStyles(theme: Theme) {
// =========================================================================
code_inline: {
backgroundColor: theme.colors.secondary,
color: theme.colors.secondaryForeground,
backgroundColor: theme.colors.surface2,
color: theme.colors.foreground,
paddingHorizontal: theme.spacing[1],
paddingVertical: 2,
borderRadius: theme.borderRadius.sm,
@@ -141,8 +141,8 @@ export function createMarkdownStyles(theme: Theme) {
},
code_block: {
backgroundColor: theme.colors.secondary,
color: theme.colors.secondaryForeground,
backgroundColor: theme.colors.surface2,
color: theme.colors.foreground,
padding: theme.spacing[3],
borderRadius: theme.borderRadius.md,
fontFamily: Fonts.mono,
@@ -151,8 +151,8 @@ export function createMarkdownStyles(theme: Theme) {
},
fence: {
backgroundColor: theme.colors.secondary,
color: theme.colors.secondaryForeground,
backgroundColor: theme.colors.surface2,
color: theme.colors.foreground,
padding: theme.spacing[3],
borderRadius: theme.borderRadius.md,
borderWidth: 1,
@@ -178,7 +178,7 @@ export function createMarkdownStyles(theme: Theme) {
},
thead: {
backgroundColor: theme.colors.secondary,
backgroundColor: theme.colors.surface2,
},
tbody: {},
@@ -188,7 +188,7 @@ export function createMarkdownStyles(theme: Theme) {
borderBottomWidth: 1,
borderRightWidth: 1,
borderColor: theme.colors.border,
backgroundColor: theme.colors.secondary,
backgroundColor: theme.colors.surface2,
fontWeight: theme.fontWeight.semibold,
color: theme.colors.foreground,
fontSize: theme.fontSize.sm,
@@ -244,14 +244,14 @@ export function createMarkdownStyles(theme: Theme) {
},
bullet_list_icon: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
marginRight: 4,
fontSize: theme.fontSize.base,
lineHeight: 22,
},
ordered_list_icon: {
color: theme.colors.mutedForeground,
color: theme.colors.foregroundMuted,
marginRight: 4,
fontSize: theme.fontSize.base,
fontWeight: theme.fontWeight.semibold,
@@ -264,7 +264,7 @@ export function createMarkdownStyles(theme: Theme) {
// =========================================================================
blockquote: {
backgroundColor: theme.colors.muted,
backgroundColor: theme.colors.surface2,
borderLeftWidth: 4,
borderLeftColor: theme.colors.primary,
paddingHorizontal: theme.spacing[4],
+57 -19
View File
@@ -103,10 +103,34 @@ export const baseColors = {
},
} as const;
// Semantic color tokens (shadcn-style)
// Semantic color tokens - Layer-based system
const lightSemanticColors = {
background: "#ffffff",
// Surfaces (layers) - shifted one step lighter
surface0: "#ffffff", // App background
surface1: "#fafafa", // Subtle hover (was zinc-100, now zinc-50)
surface2: "#f4f4f5", // Elevated: badges, inputs, sheets (was zinc-200, now zinc-100)
surface3: "#e4e4e7", // Highest elevation (was zinc-300, now zinc-200)
// Text
foreground: "#09090b",
foregroundMuted: "#71717a",
// Borders - shifted one step lighter
border: "#e4e4e7", // (was zinc-200, now zinc-200 - keep for contrast)
borderAccent: "#e4e4e7", // (was zinc-300, now zinc-200)
// Brand
accent: "#20744A",
accentForeground: "#ffffff",
// Semantic
destructive: "#dc2626",
destructiveForeground: "#ffffff",
success: "#20744A",
successForeground: "#ffffff",
// Legacy aliases (for gradual migration)
background: "#ffffff",
card: "#ffffff",
cardForeground: "#09090b",
popover: "#ffffff",
@@ -114,25 +138,44 @@ const lightSemanticColors = {
primary: "#18181b",
primaryForeground: "#fafafa",
secondary: "#f4f4f5",
secondaryForeground: "#18181b",
secondaryForeground: "#09090b",
muted: "#f4f4f5",
mutedForeground: "#71717a",
accent: "#f4f4f5",
accentForeground: "#18181b",
destructive: "#ef4444",
destructiveForeground: "#fafafa",
border: "#e4e4e7",
accentBorder: "#3f3f46",
input: "#e4e4e7",
accentBorder: "#e4e4e7",
input: "#f4f4f5",
ring: "#18181b",
} as const;
const darkSemanticColors = {
background: "#09090b",
// Surfaces (layers)
surface0: "#18181c", // App background
surface1: "#1f1f23", // Subtle hover
surface2: "#27272a", // Elevated: badges, inputs, sheets
surface3: "#3f3f46", // Highest elevation
// Text
foreground: "#fafafa",
card: "#09090b",
foregroundMuted: "#a1a1aa",
// Borders
border: "#27272a",
borderAccent: "#3f3f46",
// Brand
accent: "#20744A",
accentForeground: "#ffffff",
// Semantic
destructive: "#ef4444",
destructiveForeground: "#ffffff",
success: "#20744A",
successForeground: "#ffffff",
// Legacy aliases (for gradual migration)
background: "#18181c",
card: "#27272a",
cardForeground: "#fafafa",
popover: "#18181b",
popover: "#27272a",
popoverForeground: "#fafafa",
primary: "#fafafa",
primaryForeground: "#18181b",
@@ -140,12 +183,7 @@ const darkSemanticColors = {
secondaryForeground: "#fafafa",
muted: "#27272a",
mutedForeground: "#a1a1aa",
accent: "#27272a",
accentForeground: "#fafafa",
destructive: "#7f1d1d",
destructiveForeground: "#fafafa",
border: "#27272e",
accentBorder: "#414146",
accentBorder: "#3f3f46",
input: "#27272a",
ring: "#d4d4d8",
} as const;