-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Integrate /beta into the Homepage Hero and enhance interactive demo #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…demo with command input and output display
WalkthroughThe PR adds an interactive demo experience to the homepage by introducing a new Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related issues
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (5)
client/src/components/InteractiveDemoHero.tsx (5)
1-1: Unused import:useEffect.The
useEffecthook is imported but not used anywhere in this component.🔎 Proposed fix
-import { useState, useRef, useEffect } from "react"; +import { useState, useRef } from "react";
40-48: Minor:setTimeoutnot cleaned up on unmount.If the component unmounts within the 300ms delay (e.g., user navigates away quickly), the callback will still execute, potentially causing state updates on an unmounted component. This is a minor edge case but worth noting.
🔎 Proposed fix using useRef for cleanup
+ const timeoutRef = useRef<NodeJS.Timeout | null>(null); + const handleExampleClick = async (example: string) => { if (isLoading) return; setInput(example); - // Auto-submit after a brief moment to show the user what was selected - setTimeout(async () => { + timeoutRef.current = setTimeout(async () => { await sendMessage(example); setInput(""); }, 300); }; + + // Cleanup on unmount + useEffect(() => { + return () => { + if (timeoutRef.current) clearTimeout(timeoutRef.current); + }; + }, []);
50-61: Missing error handling for clipboard API.
navigator.clipboard.writeText()can throw if the page isn't in a secure context or if the user denies permission. Consider wrapping in try-catch to prevent unhandled promise rejections.🔎 Proposed fix
const copyLastCommand = () => { const lastAssistant = messages.filter((m) => m.role === "assistant").pop(); if (lastAssistant) { const codeMatch = lastAssistant.content.match(/```[\s\S]*?```/g); const textToCopy = codeMatch ? codeMatch.map((c) => c.replace(/```\w*\n?/g, "").trim()).join("\n") : lastAssistant.content; - navigator.clipboard.writeText(textToCopy); - setCopied(true); - setTimeout(() => setCopied(false), 2000); + navigator.clipboard.writeText(textToCopy) + .then(() => { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }) + .catch((err) => { + console.error("Failed to copy:", err); + }); } };
132-138: Consider adding accessible label for the input field.The input relies solely on the placeholder for context. Screen reader users would benefit from an associated label. Consider adding a visually hidden label for accessibility.
🔎 Proposed improvement
<div className="flex-1 relative"> + <label htmlFor="cortex-input" className="sr-only"> + Enter your request + </label> <span className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-500 font-mono text-sm"> $ </span> <Input + id="cortex-input" value={input} onChange={(e) => setInput(e.target.value)}
256-273: Unused function:formatCommandsPreview.This function is defined but never called anywhere in the component. Consider removing it to reduce dead code.
🔎 Proposed fix
-function formatCommandsPreview(content: string): React.ReactNode { - const codeMatch = content.match(/```[\s\S]*?```/g); - if (codeMatch) { - return ( - <div className="space-y-2"> - {codeMatch.map((block, i) => { - const code = block.replace(/```\w*\n?/g, "").trim(); - return ( - <div key={i} className="text-green-400"> - {code} - </div> - ); - })} - </div> - ); - } - return <div className="text-gray-400">Processing...</div>; -} - function formatOutput(content: string): React.ReactNode {
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
client/src/components/InteractiveDemoHero.tsxclient/src/hooks/useCortexDemo.tsclient/src/index.cssclient/src/sections/HomePage.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
client/src/components/InteractiveDemoHero.tsx (1)
client/src/hooks/useCortexDemo.ts (1)
useCortexDemo(22-67)
client/src/sections/HomePage.tsx (1)
client/src/components/InteractiveDemoHero.tsx (1)
InteractiveDemoHero(17-254)
🔇 Additional comments (7)
client/src/index.css (1)
1399-1413: CSS utilities are correctly implemented.The
.hide-scrollbarutility properly covers all browser engines. Minor note:.scroll-smoothis potentially redundant sincescroll-behavior: smoothis already applied globally tohtmlat line 380, though having an explicit utility class can be useful for scoped application.client/src/hooks/useCortexDemo.ts (1)
13-20: System context is well-structured for the demo use case.The prompt clearly constrains the AI to output only shell commands in a single code block, which aligns with the PR objective for a streamlined terminal-like experience. The explicit prohibitions help ensure consistent, clean output.
client/src/sections/HomePage.tsx (2)
59-59: Import is correctly added.
428-435: Hero section refactored cleanly to use the new interactive demo component.The integration replaces the previous static CTAs with the interactive demo widget. The adjusted animation parameters (y: 30, delay: 0.4s) provide appropriate staggering after the preceding headline animations.
client/src/components/InteractiveDemoHero.tsx (3)
32-38: Form submission logic is correctly implemented.The handler properly validates input, clears the field optimistically before the async operation, and prevents double submissions during loading.
63-92: Rate limit reached state is well-designed.The celebratory UI with clear CTA to install the CLI provides a good user experience when the demo limit is reached.
275-288: Output formatting function is correctly implemented.The function properly parses and renders code blocks with appropriate styling while preserving surrounding text content.
| export default function InteractiveDemoHero() { | ||
| const [input, setInput] = useState(""); | ||
| const [copied, setCopied] = useState(false); | ||
| const messagesEndRef = useRef<HTMLDivElement>(null); | ||
| const terminalRef = useRef<HTMLDivElement>(null); | ||
|
|
||
| const { | ||
| messages, | ||
| isLoading, | ||
| error, | ||
| remaining, | ||
| limitReached, | ||
| sendMessage, | ||
| } = useCortexDemo(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Auto-scroll to latest message is not implemented.
messagesEndRef is defined and rendered at line 216 but never used to scroll the terminal view. This means when new messages appear, users won't automatically see the latest output — they'll need to manually scroll.
🔎 Proposed fix using useEffect to auto-scroll
First, ensure useEffect is imported (currently imported but flagged as unused), then add:
+ // Auto-scroll to bottom when messages change
+ useEffect(() => {
+ messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
+ }, [messages, isLoading]);
+
const handleSubmit = async (e: React.FormEvent) => {Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In client/src/components/InteractiveDemoHero.tsx around lines 17 to 31, add an
effect that auto-scrolls the terminal to the latest message: import and use
useEffect (it's currently present but unused), then create a useEffect that runs
when messages change and calls messagesEndRef.current?.scrollIntoView({
behavior: "smooth", block: "nearest" }) or, if you prefer scrolling the
container, call terminalRef.current?.scrollTop =
terminalRef.current.scrollHeight; ensure the effect guards for null refs and
runs on messages updates so the view always scrolls to the newest output.
|
@coderabbitai generate docstrings |
✅ Actions performedInitiated docstring generation; will generate only if new commits exist. |
|
Note Docstrings generation - SUCCESS |
Docstrings generation was requested by @sujay-d07. * #4 (comment) The following files were modified: * `client/src/components/InteractiveDemoHero.tsx` * `client/src/hooks/useCortexDemo.ts` * `client/src/sections/HomePage.tsx`
Closes cortexlinux/cortex#254
Summary:
• Interactive Demo Hero - Embedded live /beta demo directly on homepage
• Example Prompt Chips - 5 clickable suggestions, horizontally scrollable on mobile
• Rate Limiting - 5 free requests, then prompts CLI installation
• Streamlined Layout - Input → Terminal Output → Install CTA
• Optimized AI Output - Returns only essential commands, no explanatory text
Summary by CodeRabbit
New Features
Style
✏️ Tip: You can customize this high-level summary in your review settings.