diff --git a/apps/rowboat/app/projects/[projectId]/copilot/app.tsx b/apps/rowboat/app/projects/[projectId]/copilot/app.tsx index 52358666..881fd0ef 100644 --- a/apps/rowboat/app/projects/[projectId]/copilot/app.tsx +++ b/apps/rowboat/app/projects/[projectId]/copilot/app.tsx @@ -29,6 +29,7 @@ interface AppProps { dispatch: (action: any) => void; chatContext?: any; onCopyJson?: (data: { messages: any[], lastRequest: any, lastResponse: any }) => void; + onMessagesChange?: (messages: z.infer[]) => void; } const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ @@ -37,6 +38,7 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ dispatch, chatContext = undefined, onCopyJson, + onMessagesChange, }, ref) { const messagesEndRef = useRef(null); const [messages, setMessages] = useState[]>([]); @@ -47,6 +49,11 @@ const App = forwardRef<{ handleCopyChat: () => void }, AppProps>(function App({ const [lastRequest, setLastRequest] = useState(null); const [lastResponse, setLastResponse] = useState(null); + // Notify parent of message changes + useEffect(() => { + onMessagesChange?.(messages); + }, [messages, onMessagesChange]); + // Check for initial prompt in local storage and send it useEffect(() => { const prompt = localStorage.getItem(`project_prompt_${projectId}`); @@ -303,10 +310,12 @@ export function Copilot({ }) { const [copilotKey, setCopilotKey] = useState(0); const [showCopySuccess, setShowCopySuccess] = useState(false); + const [messages, setMessages] = useState[]>([]); const appRef = useRef<{ handleCopyChat: () => void }>(null); function handleNewChat() { setCopilotKey(prev => prev + 1); + setMessages([]); } function handleCopyJson(data: { messages: any[], lastRequest: any, lastResponse: any }) { @@ -320,6 +329,7 @@ export function Copilot({ return (
@@ -364,6 +374,7 @@ export function Copilot({ dispatch={dispatch} chatContext={chatContext} onCopyJson={handleCopyJson} + onMessagesChange={setMessages} />
diff --git a/apps/rowboat/components/common/panel-common.tsx b/apps/rowboat/components/common/panel-common.tsx index 441ea179..40fef2c2 100644 --- a/apps/rowboat/components/common/panel-common.tsx +++ b/apps/rowboat/components/common/panel-common.tsx @@ -1,4 +1,5 @@ import clsx from "clsx"; +import { Sparkles } from "lucide-react"; export function ActionButton({ icon = null, @@ -34,6 +35,7 @@ interface PanelProps { children: React.ReactNode; maxHeight?: string; variant?: 'default' | 'copilot' | 'projects'; + showWelcome?: boolean; } export function Panel({ @@ -43,17 +45,31 @@ export function Panel({ children, maxHeight, variant = 'default', + showWelcome = true, }: PanelProps) { return
+ {variant === 'copilot' && showWelcome && ( +
+ +
+
+
What can I help you build?
+
 
+
+
+
+ )}
{variant === 'projects' ? ( diff --git a/apps/rowboat/tailwind.config.ts b/apps/rowboat/tailwind.config.ts index 719ce1c3..3340b862 100644 --- a/apps/rowboat/tailwind.config.ts +++ b/apps/rowboat/tailwind.config.ts @@ -19,11 +19,33 @@ const config: Config = { 'pulse-subtle': { '0%, 100%': { opacity: '1' }, '50%': { opacity: '0.85' } + }, + gradient: { + '0%': { backgroundPosition: '0% 50%' }, + '50%': { backgroundPosition: '100% 50%' }, + '100%': { backgroundPosition: '0% 50%' } + }, + 'sparkle-fade': { + '0%': { opacity: '0.2', transform: 'scale(0.9)' }, + '50%': { opacity: '0.5', transform: 'scale(1.1)' }, + '100%': { opacity: '0.2', transform: 'scale(0.9)' } + }, + typing: { + '0%, 5%': { width: '0%' }, + '45%, 55%': { width: '100%' }, + '95%, 100%': { width: '0%' } + }, + blink: { + '50%': { borderColor: 'transparent' } } }, animation: { shine: 'shine 2s infinite', - 'pulse-subtle': 'pulse-subtle 2s infinite' + 'pulse-subtle': 'pulse-subtle 2s infinite', + 'gradient': 'gradient var(--gradient-animation-duration, 15s) ease infinite', + 'sparkle': 'sparkle-fade 4s cubic-bezier(0.4, 0, 0.6, 1) infinite', + 'typing': 'typing 8s cubic-bezier(0.4, 0, 0.2, 1) infinite', + 'cursor': 'blink .75s step-end infinite' }, backgroundImage: { 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',