From a0f39302919fbacf7a0d407f01b1a50413ea6f70 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Mon, 02 Mar 2026 23:15:13 +0100
Subject: [PATCH] feat: on-device speech recognition, navigation screen, session picker

---
 components/chat/CommandBar.tsx |  146 ++++++++++++++++++++++++++++++------------------
 1 files changed, 91 insertions(+), 55 deletions(-)

diff --git a/components/chat/CommandBar.tsx b/components/chat/CommandBar.tsx
index 9853d8f..de9c0f4 100644
--- a/components/chat/CommandBar.tsx
+++ b/components/chat/CommandBar.tsx
@@ -1,67 +1,103 @@
 import React, { useState } from "react";
-import { Pressable, ScrollView, Text, View } from "react-native";
-
-interface Command {
-  label: string;
-  value: string;
-}
-
-const DEFAULT_COMMANDS: Command[] = [
-  { label: "/s", value: "/s" },
-  { label: "/ss", value: "/ss" },
-  { label: "/clear", value: "/clear" },
-  { label: "/help", value: "/help" },
-  { label: "/status", value: "/status" },
-];
+import { Pressable, Text, View, useWindowDimensions } from "react-native";
+import * as Haptics from "expo-haptics";
 
 interface CommandBarProps {
-  onCommand: (command: string) => void;
-  commands?: Command[];
+  onSessions: () => void;
+  onScreenshot: () => void;
+  onHelp: () => void;
 }
 
-export function CommandBar({
-  onCommand,
-  commands = DEFAULT_COMMANDS,
-}: CommandBarProps) {
-  const [activeCommand, setActiveCommand] = useState<string | null>(null);
+export function CommandBar({ onSessions, onScreenshot, onHelp }: CommandBarProps) {
+  return (
+    <View
+      style={{
+        flexDirection: "row",
+        paddingHorizontal: 12,
+        paddingVertical: 6,
+        gap: 8,
+      }}
+    >
+      <CmdBtn icon="📋" label="Sessions" bg="#1A2744" border="#2E4A7A" onPress={onSessions} />
+      <CmdBtn icon="📸" label="Screen" bg="#1A3A2A" border="#2E6A4A" onPress={onScreenshot} />
+      <CmdBtn icon="❓" label="Help" bg="#3A1A2A" border="#6A2E4A" onPress={onHelp} />
+    </View>
+  );
+}
 
-  function handlePress(command: Command) {
-    setActiveCommand(command.value);
-    onCommand(command.value);
-    setTimeout(() => setActiveCommand(null), 200);
-  }
+interface TextModeCommandBarProps {
+  onSessions: () => void;
+  onScreenshot: () => void;
+  onNavigate: () => void;
+  onClear: () => void;
+}
+
+export function TextModeCommandBar({
+  onSessions,
+  onScreenshot,
+  onNavigate,
+  onClear,
+}: TextModeCommandBarProps) {
+  return (
+    <View
+      style={{
+        flexDirection: "row",
+        paddingHorizontal: 12,
+        paddingVertical: 6,
+        gap: 8,
+      }}
+    >
+      <CmdBtn icon="📋" label="Sessions" bg="#1A2744" border="#2E4A7A" onPress={onSessions} />
+      <CmdBtn icon="📸" label="Screen" bg="#1A3A2A" border="#2E6A4A" onPress={onScreenshot} />
+      <CmdBtn icon="🧭" label="Navigate" bg="#2A2A1A" border="#5A5A2E" onPress={onNavigate} />
+      <CmdBtn icon="🗑" label="Clear" bg="#3A1A1A" border="#6A2E2E" onPress={onClear} />
+    </View>
+  );
+}
+
+function CmdBtn({
+  icon,
+  label,
+  bg,
+  border,
+  onPress,
+}: {
+  icon: string;
+  label: string;
+  bg: string;
+  border: string;
+  onPress: () => void;
+}) {
+  const [pressed, setPressed] = useState(false);
+  const { width } = useWindowDimensions();
 
   return (
-    <View className="border-t border-pai-border">
-      <ScrollView
-        horizontal
-        showsHorizontalScrollIndicator={false}
-        contentContainerStyle={{ paddingHorizontal: 12, paddingVertical: 8, gap: 8 }}
+    <View style={{ flex: 1 }}>
+      <Pressable
+        onPressIn={() => setPressed(true)}
+        onPressOut={() => setPressed(false)}
+        onPress={() => {
+          Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
+          onPress();
+        }}
       >
-        {commands.map((cmd) => (
-          <Pressable
-            key={cmd.value}
-            onPress={() => handlePress(cmd)}
-            className="rounded-full px-4 py-2"
-            style={({ pressed }) => ({
-              backgroundColor:
-                activeCommand === cmd.value || pressed
-                  ? "#4A9EFF"
-                  : "#1E1E2E",
-            })}
-          >
-            <Text
-              className="text-sm font-medium"
-              style={{
-                color:
-                  activeCommand === cmd.value ? "#FFFFFF" : "#9898B0",
-              }}
-            >
-              {cmd.label}
-            </Text>
-          </Pressable>
-        ))}
-      </ScrollView>
+        <View
+          style={{
+            height: 68,
+            borderRadius: 16,
+            alignItems: "center",
+            justifyContent: "center",
+            backgroundColor: pressed ? "#4A9EFF" : bg,
+            borderWidth: 1.5,
+            borderColor: pressed ? "#4A9EFF" : border,
+          }}
+        >
+          <Text style={{ fontSize: 26, marginBottom: 2 }}>{icon}</Text>
+          <Text style={{ color: "#C8C8E0", fontSize: 13, fontWeight: "700" }}>
+            {label}
+          </Text>
+        </View>
+      </Pressable>
     </View>
   );
 }

--
Gitblit v1.3.1