Skip to content

Commit 628684a

Browse files
committed
break down pages to modularize
1 parent d8937e5 commit 628684a

13 files changed

Lines changed: 1098 additions & 933 deletions

apps/web/src/App.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ function App() {
1616
<Route
1717
path="/chat"
1818
element={
19-
<ProtectedRoute>
19+
// <ProtectedRoute>
2020
<ChatPage />
21-
</ProtectedRoute>
21+
// </ProtectedRoute>
2222
}
2323
/>
2424
</Routes>
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import React, { useState } from "react";
2+
import { Button } from "@/components/ui/button";
3+
import { Textarea } from "@/components/ui/textarea";
4+
import { Send, Paperclip, FileText, X } from "lucide-react";
5+
import {
6+
Tooltip,
7+
TooltipContent,
8+
TooltipProvider,
9+
TooltipTrigger,
10+
} from "@/components/ui/tooltip";
11+
12+
interface UploadedFile {
13+
id: string;
14+
name: string;
15+
size: number;
16+
}
17+
18+
interface ChatInputProps {
19+
inputValue: string;
20+
setInputValue: (value: string) => void;
21+
uploadedFiles: UploadedFile[];
22+
setUploadedFiles: (files: UploadedFile[]) => void;
23+
onSend: () => void;
24+
isEvaluating: boolean;
25+
sidebarOpen: boolean;
26+
}
27+
28+
export function ChatInput({
29+
inputValue,
30+
setInputValue,
31+
uploadedFiles,
32+
setUploadedFiles,
33+
onSend,
34+
isEvaluating,
35+
sidebarOpen,
36+
}: ChatInputProps) {
37+
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
38+
if (e.key === "Enter" && !e.shiftKey) {
39+
e.preventDefault();
40+
if (inputValue.trim()) {
41+
onSend();
42+
}
43+
}
44+
};
45+
46+
const handleFileUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
47+
const files = e.currentTarget.files;
48+
if (files && uploadedFiles.length < 3) {
49+
Array.from(files).forEach((file) => {
50+
if (uploadedFiles.length < 3) {
51+
setUploadedFiles([
52+
...uploadedFiles,
53+
{
54+
id: Math.random().toString(36).substr(2, 9),
55+
name: file.name,
56+
size: file.size,
57+
},
58+
]);
59+
}
60+
});
61+
}
62+
};
63+
64+
const removeFile = (id: string) => {
65+
setUploadedFiles(uploadedFiles.filter((f) => f.id !== id));
66+
};
67+
68+
return (
69+
<div
70+
className={`border-t border-border bg-card/50 backdrop-blur-sm p-4 shrink-0 transition-all duration-300 ${
71+
sidebarOpen ? "ml-72" : "ml-0"
72+
}`}
73+
>
74+
<div className="max-w-4xl mx-auto space-y-4">
75+
{/* Uploaded Files Display */}
76+
{uploadedFiles.length > 0 && (
77+
<div className="flex flex-wrap gap-2">
78+
{uploadedFiles.map((file) => (
79+
<div
80+
key={file.id}
81+
className="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg bg-secondary border border-border text-sm"
82+
>
83+
<FileText className="h-3.5 w-3.5 text-muted-foreground" />
84+
<span className="text-foreground truncate max-w-xs">{file.name}</span>
85+
<button
86+
onClick={() => removeFile(file.id)}
87+
className="ml-1 text-muted-foreground hover:text-foreground transition-colors"
88+
>
89+
<X className="h-3.5 w-3.5" />
90+
</button>
91+
</div>
92+
))}
93+
</div>
94+
)}
95+
96+
{/* Input Area */}
97+
<div className="flex gap-3 items-end">
98+
<TooltipProvider>
99+
<Tooltip>
100+
<TooltipTrigger asChild>
101+
<div className="relative">
102+
<input
103+
type="file"
104+
multiple
105+
onChange={handleFileUpload}
106+
className="hidden"
107+
id="file-upload"
108+
disabled={isEvaluating || uploadedFiles.length >= 3}
109+
/>
110+
<label htmlFor="file-upload">
111+
<Button
112+
variant="outline"
113+
size="icon"
114+
className="bg-card hover:bg-secondary border-border cursor-pointer"
115+
disabled={isEvaluating || uploadedFiles.length >= 3}
116+
asChild
117+
>
118+
<span>
119+
<Paperclip className="h-4 w-4" />
120+
</span>
121+
</Button>
122+
</label>
123+
</div>
124+
</TooltipTrigger>
125+
<TooltipContent>
126+
<p>
127+
{uploadedFiles.length >= 3
128+
? "Maximum 3 files"
129+
: "Attach files (max 3)"}
130+
</p>
131+
</TooltipContent>
132+
</Tooltip>
133+
</TooltipProvider>
134+
135+
<Textarea
136+
value={inputValue}
137+
onChange={(e) => setInputValue(e.target.value)}
138+
onKeyDown={handleKeyDown}
139+
placeholder="Describe your hackathon project... (Press Enter to send, Shift+Enter for new line)"
140+
className="resize-none bg-card border-border text-foreground"
141+
rows={3}
142+
disabled={isEvaluating}
143+
/>
144+
145+
<Button
146+
onClick={onSend}
147+
disabled={!inputValue.trim() || isEvaluating}
148+
className="bg-accent hover:bg-accent/80 text-accent-foreground"
149+
size="icon"
150+
>
151+
<Send className="h-4 w-4" />
152+
</Button>
153+
</div>
154+
155+
<p className="text-xs text-muted-foreground">
156+
💡 Tip: Include project details like name, description, tech stack, and GitHub link for better evaluation
157+
</p>
158+
</div>
159+
</div>
160+
);
161+
}

0 commit comments

Comments
 (0)