Matthias Nott
2026-03-02 a0f39302919fbacf7a0d407f01b1a50413ea6f70
components/chat/InputBar.tsx
....@@ -6,16 +6,23 @@
66 TextInput,
77 View,
88 } from "react-native";
9
+import * as Haptics from "expo-haptics";
910 import { VoiceButton } from "./VoiceButton";
1011
1112 interface InputBarProps {
1213 onSendText: (text: string) => void;
13
- onSendVoice: (audioUri: string, durationMs: number) => void;
14
+ onReplay: () => void;
15
+ isTextMode: boolean;
16
+ onToggleMode: () => void;
1417 }
1518
16
-export function InputBar({ onSendText, onSendVoice }: InputBarProps) {
19
+export function InputBar({
20
+ onSendText,
21
+ onReplay,
22
+ isTextMode,
23
+ onToggleMode,
24
+}: InputBarProps) {
1725 const [text, setText] = useState("");
18
- const [isVoiceMode, setIsVoiceMode] = useState(false);
1926 const inputRef = useRef<TextInput>(null);
2027
2128 const handleSend = useCallback(() => {
....@@ -25,42 +32,108 @@
2532 setText("");
2633 }, [text, onSendText]);
2734
28
- const toggleMode = useCallback(() => {
29
- setIsVoiceMode((prev) => {
30
- if (prev) {
31
- // Switching to text mode — focus input after mode switch
32
- setTimeout(() => inputRef.current?.focus(), 100);
33
- } else {
34
- Keyboard.dismiss();
35
- }
36
- return !prev;
37
- });
38
- }, []);
39
-
40
- if (isVoiceMode) {
35
+ if (!isTextMode) {
36
+ // Voice mode: [Replay] [Talk] [Aa]
4137 return (
42
- <View className="border-t border-pai-border bg-pai-bg">
43
- {/* Mode toggle */}
38
+ <View
39
+ style={{
40
+ flexDirection: "row",
41
+ gap: 10,
42
+ paddingHorizontal: 16,
43
+ paddingVertical: 10,
44
+ paddingBottom: 6,
45
+ borderTopWidth: 1,
46
+ borderTopColor: "#2E2E45",
47
+ alignItems: "center",
48
+ }}
49
+ >
50
+ {/* Replay last message */}
4451 <Pressable
45
- onPress={toggleMode}
46
- className="absolute top-3 right-4 z-10 w-10 h-10 items-center justify-center"
52
+ onPress={() => {
53
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
54
+ onReplay();
55
+ }}
4756 >
48
- <Text className="text-2xl">⌨️</Text>
57
+ <View
58
+ style={{
59
+ width: 68,
60
+ height: 68,
61
+ borderRadius: 34,
62
+ alignItems: "center",
63
+ justifyContent: "center",
64
+ backgroundColor: "#1A2E1A",
65
+ borderWidth: 1.5,
66
+ borderColor: "#3A6A3A",
67
+ }}
68
+ >
69
+ <Text style={{ fontSize: 24 }}>▶</Text>
70
+ <Text style={{ color: "#8ABF8A", fontSize: 10, marginTop: 1, fontWeight: "600" }}>Replay</Text>
71
+ </View>
4972 </Pressable>
5073
51
- <VoiceButton onVoiceMessage={onSendVoice} />
74
+ {/* Talk button — center, biggest */}
75
+ <View style={{ flex: 1, alignItems: "center" }}>
76
+ <VoiceButton onTranscript={onSendText} />
77
+ </View>
78
+
79
+ {/* Text mode toggle */}
80
+ <Pressable
81
+ onPress={() => {
82
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
83
+ onToggleMode();
84
+ setTimeout(() => inputRef.current?.focus(), 150);
85
+ }}
86
+ >
87
+ <View
88
+ style={{
89
+ width: 68,
90
+ height: 68,
91
+ borderRadius: 34,
92
+ alignItems: "center",
93
+ justifyContent: "center",
94
+ backgroundColor: "#1A1A3E",
95
+ borderWidth: 1.5,
96
+ borderColor: "#3A3A7A",
97
+ }}
98
+ >
99
+ <Text style={{ fontSize: 22, color: "#9898D0", fontWeight: "700" }}>Aa</Text>
100
+ </View>
101
+ </Pressable>
52102 </View>
53103 );
54104 }
55105
106
+ // Text mode: [Mic] [TextInput] [Send]
56107 return (
57
- <View className="border-t border-pai-border bg-pai-bg px-3 py-2 flex-row items-end gap-2">
108
+ <View
109
+ style={{
110
+ flexDirection: "row",
111
+ gap: 8,
112
+ paddingHorizontal: 12,
113
+ paddingVertical: 8,
114
+ borderTopWidth: 1,
115
+ borderTopColor: "#2E2E45",
116
+ alignItems: "flex-end",
117
+ }}
118
+ >
58119 {/* Voice mode toggle */}
59120 <Pressable
60
- onPress={toggleMode}
61
- className="w-10 h-10 items-center justify-center rounded-full bg-pai-bg-tertiary mb-0.5"
121
+ onPress={() => {
122
+ Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
123
+ Keyboard.dismiss();
124
+ onToggleMode();
125
+ }}
126
+ style={{
127
+ width: 40,
128
+ height: 40,
129
+ borderRadius: 20,
130
+ alignItems: "center",
131
+ justifyContent: "center",
132
+ backgroundColor: "#1E1E2E",
133
+ marginBottom: 2,
134
+ }}
62135 >
63
- <Text className="text-xl">🎤</Text>
136
+ <Text style={{ fontSize: 20 }}>🎤</Text>
64137 </Pressable>
65138
66139 {/* Text input */}
....@@ -75,19 +148,39 @@
75148 onSubmitEditing={handleSend}
76149 returnKeyType="send"
77150 blurOnSubmit
78
- className="flex-1 bg-pai-bg-tertiary rounded-2xl px-4 py-2.5 text-pai-text text-base"
79
- style={{ maxHeight: 120 }}
151
+ style={{
152
+ flex: 1,
153
+ backgroundColor: "#1E1E2E",
154
+ borderRadius: 20,
155
+ paddingHorizontal: 16,
156
+ paddingVertical: 10,
157
+ maxHeight: 120,
158
+ color: "#E8E8F0",
159
+ fontSize: 16,
160
+ }}
80161 />
81162
82163 {/* Send button */}
83164 <Pressable
84165 onPress={handleSend}
85166 disabled={!text.trim()}
86
- className={`w-10 h-10 rounded-full items-center justify-center mb-0.5 ${
87
- text.trim() ? "bg-pai-accent" : "bg-pai-bg-tertiary"
88
- }`}
167
+ style={{
168
+ width: 40,
169
+ height: 40,
170
+ borderRadius: 20,
171
+ alignItems: "center",
172
+ justifyContent: "center",
173
+ marginBottom: 2,
174
+ backgroundColor: text.trim() ? "#4A9EFF" : "#1E1E2E",
175
+ }}
89176 >
90
- <Text className={`text-xl ${text.trim() ? "text-white" : "text-pai-text-muted"}`}>
177
+ <Text
178
+ style={{
179
+ fontSize: 18,
180
+ fontWeight: "bold",
181
+ color: text.trim() ? "#FFFFFF" : "#5A5A78",
182
+ }}
183
+ >
91184
92185 </Text>
93186 </Pressable>