Skip to content

Commit d536327

Browse files
chat input updates
1 parent b9254cb commit d536327

File tree

14 files changed

+310
-541
lines changed

14 files changed

+310
-541
lines changed

app/globals.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,18 @@ body {
66
font-family: Arial, Helvetica, sans-serif;
77
}
88

9+
910
@layer utilities {
1011
.text-balance {
1112
text-wrap: balance;
13+
.animate-spin-slow {
14+
animation: spin-slow var(--star-speed, 5s) linear infinite;
15+
}
16+
}
17+
@keyframes spin-slow {
18+
to {
19+
transform: rotate(360deg);
20+
}
1221
}
1322
}
1423

app/page.tsx

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"use client"
33

44
import React from "react"
5-
import { useRouter } from "next/navigation"
65

76
import type { ViewType } from "@/components/auth"
87
import { AuthDialog } from "@/components/auth-dialog"
@@ -24,18 +23,8 @@ import type { ExecutionResult } from "@/lib/types"
2423
import type { DeepPartial } from "ai"
2524
import { experimental_useObject as useObject } from "ai/react"
2625
import { usePostHog } from "posthog-js/react"
27-
import { type SetStateAction, useCallback, useEffect, useState } from "react"
26+
import { useCallback, useEffect, useState } from "react"
2827
import { useLocalStorage } from "usehooks-ts"
29-
import posthog from "posthog-js"
30-
31-
const TEMPLATE_IDS = {
32-
CODE_INTERPRETER_V1: "code-interpreter-v1",
33-
NEXTJS_DEVELOPER: "nextjs-developer",
34-
VUE_DEVELOPER: "vue-developer",
35-
STREAMLIT_DEVELOPER: "streamlit-developer",
36-
GRADIO_DEVELOPER: "gradio-developer",
37-
CODINIT_ENGINEER: "codinit-engineer",
38-
} as const
3928

4029
interface ProjectAnalysis {
4130
structure: {
@@ -99,14 +88,13 @@ const parseApiError = (error: Error | any): ParsedApiError => {
9988
}
10089

10190
export default function Home() {
102-
const router = useRouter()
10391
const posthog = usePostHog()
10492

10593
// Auth and session state
10694
const [isAuthDialogOpen, setAuthDialog] = useState(false)
10795
const [authView, setAuthView] = useState<ViewType>("sign_in")
10896
const [authError, setAuthError] = useState<string | null>(null)
109-
const { session, isLoading, userTeam, authError: authStateError } = useAuth(setAuthDialog, setAuthView)
97+
const { session, isLoading, userTeam } = useAuth(setAuthDialog, setAuthView)
11098

11199
// Chat and UI state
112100
const [messages, setMessages] = useState<Message[]>([])
@@ -123,6 +111,7 @@ export default function Home() {
123111
const [errorMessage, setErrorMessage] = useState("")
124112
const [isRateLimited, setIsRateLimited] = useState(false)
125113
const [currentRequestId, setCurrentRequestId] = useState<string>("")
114+
const [hasMounted, setHasMounted] = useState(false)
126115
const [projectContext, setProjectContext] = useState<{
127116
files: File[]
128117
analysis: ProjectAnalysis | null
@@ -161,6 +150,7 @@ export default function Home() {
161150
// Fragment state management
162151
const [fragment, setFragment] = useState<FragmentSchema | null>(null)
163152
const [result, setResult] = useState<ExecutionResult | undefined>()
153+
const [isSettingsDialogOpen, setIsSettingsDialogOpen] = useState(false)
164154

165155
// Navigation and action handlers
166156
const handleSocialClick = useCallback((platform: string) => {
@@ -340,6 +330,11 @@ export default function Home() {
340330
}
341331
}, [error, stop])
342332

333+
// Effect to track component mounting for client-side only logic
334+
useEffect(() => {
335+
setHasMounted(true)
336+
}, [])
337+
343338
// Main form submission handler
344339
const handleSubmitAuth = useCallback(async (
345340
e: React.FormEvent<HTMLFormElement>,
@@ -556,6 +551,7 @@ export default function Home() {
556551
models={availableModels}
557552
languageModel={languageModel}
558553
onLanguageModelChange={handleLanguageModelChange}
554+
hasMounted={hasMounted}
559555
/>
560556
<ChatSettings
561557
apiKeyConfigurable={!process.env.NEXT_PUBLIC_NO_API_KEY_INPUT}
@@ -589,7 +585,7 @@ export default function Home() {
589585
{/* Command Palette Integration */}
590586
<CommandPalette
591587
onCreateFragment={() => {
592-
setChatInput("Create a new React component with modern best practices including TypeScript, responsive design, and accessibility features.")
588+
setChatInput("Create a new Next.js React component with modern best practices including TypeScript, responsive design, and accessibility features.")
593589
setSelectedTemplate("nextjs-developer")
594590

595591
setTimeout(() => {
@@ -601,9 +597,8 @@ export default function Home() {
601597
}}
602598
onClearChat={handleClearChat}
603599
onOpenSettings={() => {
604-
router.push('/settings')
605600
}}
606601
/>
607602
</div>
608603
)
609-
}
604+
}

components/chat-picker.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ export function ChatPicker({
2020
models,
2121
languageModel,
2222
onLanguageModelChange,
23+
hasMounted, // Add hasMounted prop
2324
}: {
2425
templates: TemplatesDataObject
2526
selectedTemplate: 'auto' | TemplateId
2627
onSelectedTemplateChange: (template: 'auto' | TemplateId) => void
2728
models: LLMModel[]
2829
languageModel: LLMModelConfig
2930
onLanguageModelChange: (config: LLMModelConfig) => void
31+
hasMounted: boolean // Define type for hasMounted
3032
}) {
3133
return (
3234
<div className="flex items-center space-x-2">
@@ -71,6 +73,7 @@ export function ChatPicker({
7173
</div>
7274
<div className="flex flex-col">
7375
<Select
76+
key={hasMounted ? `lm-client-${languageModel.model}` : 'lm-server'} // Add key here
7477
name="languageModel"
7578
defaultValue={languageModel.model}
7679
onValueChange={(e) => onLanguageModelChange({ model: e })}

components/chat-sidebar/settings-dialog.tsx

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use client"
22

3+
import { shallow } from "zustand/shallow"
4+
import { useChatSidebarStore } from "@/lib/stores/chat-sidebar-stores"
35
import type React from "react"
46
import { useState } from "react"
5-
import { useChatSidebarStore } from "@/lib/stores/chat-sidebar-stores"
67
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
78
import { Button } from "@/components/ui/button"
89
import { Label } from "@/components/ui/label"
@@ -27,22 +28,35 @@ interface SettingsDialogProps {
2728
}
2829

2930
export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
30-
const { chatSessions, projects, clearAll, exportData, importData } = useChatSidebarStore()
31-
3231
const [autoSave, setAutoSave] = useState(true)
3332
const [showTimestamps, setShowTimestamps] = useState(true)
3433
const [compactView, setCompactView] = useState(false)
3534

36-
const totalMessages = chatSessions.reduce((sum, session) => sum + session.messages.length, 0)
37-
const storageSize = JSON.stringify({ chatSessions, projects }).length
35+
const { chatSessions, projects, exportStoreData, importStoreData, clearStoreData } =
36+
useChatSidebarStore(
37+
(state) => ({
38+
chatSessions: state.chatSessions,
39+
projects: state.projects,
40+
exportStoreData: state.exportData,
41+
importStoreData: state.importData,
42+
clearStoreData: state.clearAll,
43+
})
44+
)
45+
46+
// Defensive defaults in case chatSessions or projects are not yet populated
47+
const safeChatSessions = chatSessions || []
48+
const safeProjects = projects || []
49+
50+
const totalMessages = safeChatSessions.reduce((sum: number, session: any) => sum + (session.messages?.length || 0), 0)
51+
const storageSize = JSON.stringify({ chatSessions: safeChatSessions, projects: safeProjects }).length
3852

3953
const handleExport = () => {
40-
const data = exportData()
54+
const data = exportStoreData ? exportStoreData() : ""
4155
const blob = new Blob([data], { type: "application/json" })
4256
const url = URL.createObjectURL(blob)
4357
const a = document.createElement("a")
4458
a.href = url
45-
a.download = `chat-history-${new Date().toISOString().split("T")[0]}.json`
59+
a.download = `codinit-data-${new Date().toISOString().split("T")[0]}.json`
4660
document.body.appendChild(a)
4761
a.click()
4862
document.body.removeChild(a)
@@ -56,7 +70,9 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
5670
const reader = new FileReader()
5771
reader.onload = (e) => {
5872
const content = e.target?.result as string
59-
importData(content)
73+
if (importStoreData) {
74+
importStoreData(content)
75+
}
6076
}
6177
reader.readAsText(file)
6278
event.target.value = ""
@@ -76,11 +92,11 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
7692
<h4 className="text-sm font-medium">Statistics</h4>
7793
<div className="grid grid-cols-2 gap-4">
7894
<div className="text-center p-3 bg-muted rounded-lg">
79-
<div className="text-2xl font-bold">{chatSessions.length}</div>
95+
<div className="text-2xl font-bold">{safeChatSessions.length}</div>
8096
<div className="text-xs text-muted-foreground">Chat Sessions</div>
8197
</div>
8298
<div className="text-center p-3 bg-muted rounded-lg">
83-
<div className="text-2xl font-bold">{projects.length}</div>
99+
<div className="text-2xl font-bold">{safeProjects.length}</div>
84100
<div className="text-xs text-muted-foreground">Projects</div>
85101
</div>
86102
<div className="text-center p-3 bg-muted rounded-lg">
@@ -158,8 +174,10 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
158174
<AlertDialogCancel>Cancel</AlertDialogCancel>
159175
<AlertDialogAction
160176
onClick={() => {
161-
clearAll()
162-
onOpenChange(false)
177+
if (clearStoreData) {
178+
clearStoreData()
179+
}
180+
onOpenChange(false) // Close dialog after clearing
163181
}}
164182
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
165183
>

components/enhanced-chat-input.tsx

Lines changed: 49 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -305,9 +305,9 @@ export function EnhancedChatInput({
305305
}
306306

307307
return (
308-
<button className="px-2 py-1 rounded-sm bg-red-400/20 hover:bg-red-400/30 transition-colors" onClick={retry}>
308+
<Button className="px-2 py-1 rounded-sm bg-red-400/20 hover:bg-red-400/30 transition-colors" onClick={retry}>
309309
Try Again
310-
</button>
310+
</Button>
311311
)
312312
}
313313

@@ -377,53 +377,57 @@ export function EnhancedChatInput({
377377
onChange={handleFileInput}
378378
/>
379379
<div className="flex items-center flex-1 gap-2">
380-
<TooltipProvider>
381-
<Tooltip delayDuration={0}>
382-
<TooltipTrigger asChild>
383-
<Button
384-
disabled={!isMultiModal || isErrored}
385-
type="button"
386-
variant="outline"
387-
size="icon"
388-
className="rounded-xl h-10 w-10"
389-
onClick={(e) => {
390-
e.preventDefault()
391-
document.getElementById("multimodal")?.click()
392-
}}
393-
>
394-
<Paperclip className="h-5 w-5" />
395-
</Button>
396-
</TooltipTrigger>
397-
<TooltipContent>Add attachments</TooltipContent>
398-
</Tooltip>
399-
</TooltipProvider>
400-
401-
402-
<GitHubImportModal
403-
onImport={handleGitHubImport}
404-
isLoading={isLoading}
405-
/>
380+
<div className="relative">
381+
<div className="rounded-xl h-10 w-10" />
382+
<TooltipProvider>
383+
<Tooltip delayDuration={0}>
384+
<TooltipTrigger asChild>
385+
<Button
386+
disabled={!isMultiModal || isErrored}
387+
type="button"
388+
variant="outline"
389+
size="icon"
390+
className="absolute inset-0 rounded-xl h-10 w-10 z-10"
391+
onClick={(e) => {
392+
e.preventDefault()
393+
document.getElementById("multimodal")?.click()
394+
}}
395+
>
396+
<Paperclip className="h-5 w-5" />
397+
</Button>
398+
</TooltipTrigger>
399+
<TooltipContent>Add attachments</TooltipContent>
400+
</Tooltip>
401+
</TooltipProvider>
402+
</div>
403+
404+
<div className="relative">
405+
<GitHubImportModal
406+
onImport={handleGitHubImport}
407+
isLoading={isLoading}
408+
/>
409+
</div>
406410

407411
{files.length > 0 && filePreview}
408412
</div>
409413
<div>
410-
<TooltipProvider>
411-
<Tooltip delayDuration={0}>
412-
<TooltipTrigger asChild>
413-
<Button
414-
disabled={!input.trim() || isLoading || isEnhancing || isErrored}
415-
type="button"
416-
variant="outline"
417-
size="icon"
418-
className="rounded-xl h-10 w-10 mr-2" // Added mr-2 for spacing
419-
onClick={handleEnhanceMessage}
420-
>
421-
{isEnhancing ? <Loader2 className="h-5 w-5 animate-spin" /> : <Sparkles className="h-5 w-5" />}
422-
</Button>
423-
</TooltipTrigger>
424-
<TooltipContent>Enhance message with AI</TooltipContent>
425-
</Tooltip>
426-
</TooltipProvider>
414+
<TooltipProvider>
415+
<Tooltip delayDuration={0}>
416+
<TooltipTrigger asChild>
417+
<Button
418+
disabled={!input.trim() || isLoading || isEnhancing || isErrored}
419+
type="button"
420+
variant="outline"
421+
size="icon"
422+
className="rounded-xl h-10 w-10 mr-2" // Added mr-2 for spacing
423+
onClick={handleEnhanceMessage}
424+
>
425+
{isEnhancing ? <Loader2 className="h-5 w-5 animate-spin" /> : <Sparkles className="h-5 w-5" />}
426+
</Button>
427+
</TooltipTrigger>
428+
<TooltipContent>Enhance message with AI</TooltipContent>
429+
</Tooltip>
430+
</TooltipProvider>
427431
{!isLoading ? (
428432
<TooltipProvider>
429433
<Tooltip delayDuration={0}>

components/ui/star-border-demo.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import React from "react"
2+
import { cn } from "@/lib/utils"
3+
import { StarBorder } from "@/components/ui/star-border"
4+
5+
export function StarBorderDemo() {
6+
return (
7+
<div className="space-y-8">
8+
<StarBorder>
9+
Theme-aware Border
10+
</StarBorder>
11+
</div>
12+
)
13+
}

0 commit comments

Comments
 (0)