-
Notifications
You must be signed in to change notification settings - Fork 0
update frontend #17
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
update frontend #17
Conversation
Co-Authored-By: ansif mk <215146833+ansifmk@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughSummary by CodeRabbit
WalkthroughThis pull request adds four new page components (docs, examples, features, generate) with supporting UI components for a documentation site. It also refactors the Hero component, updates navigation links to real routes, and refreshes version metadata. The changes establish a client-side routing structure with dedicated pages and a generation interface that integrates with an API endpoint. Changes
Sequence DiagramsequenceDiagram
actor User
participant SearchInput
participant GeneratePage
participant API as /api/generate
participant MarkdownPreview
User->>SearchInput: Enter GitHub URL & submit
SearchInput->>SearchInput: Validate URL contains "github.com"
SearchInput->>GeneratePage: onGenerate(url)
GeneratePage->>GeneratePage: setIsLoading(true)
GeneratePage->>API: POST with GitHub URL
API->>API: Process request
API-->>GeneratePage: Return markdown JSON
GeneratePage->>GeneratePage: Parse response & setMarkdown()
GeneratePage->>GeneratePage: setIsLoading(false)
GeneratePage->>MarkdownPreview: Pass markdown content
MarkdownPreview->>User: Display formatted markdown
User->>MarkdownPreview: Click Copy button
MarkdownPreview->>MarkdownPreview: Copy to clipboard & show feedback
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ❌ 3❌ Failed checks (1 warning, 2 inconclusive)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ 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: 8
🤖 Fix all issues with AI agents
In `@src/app/docs/page.tsx`:
- Line 5: Remove the unused import symbol ChevronRight from the import statement
that currently reads "import { ChevronRight, Terminal } from 'lucide-react';" so
only the used symbol Terminal is imported; update the import to remove the
unused identifier and keep formatting consistent.
In `@src/app/examples/page.tsx`:
- Around line 97-102: The Button is nested inside Link (Link -> Button), which
produces invalid HTML because Link renders an <a> and Button renders a <button>;
fix by making the Button render as an anchor or by handling navigation in the
Button's onClick: either update the Button (component prop like asChild or prop
to render an <a>) so it outputs an <a> and keep it wrapped by Link, or remove
Link and call router.push('/#search-input') from an onClick handler on Button
(while keeping ExternalLink icon inside). Adjust usage around the Link, Button,
and ExternalLink symbols accordingly to avoid nesting interactive tags.
- Around line 37-42: Replace the duplicated local navLinks arrays with a single
shared constant and fix the Docs href to '/docs': create a new exported constant
named navLinks (array of objects with name/href) in a common module, ensure the
Docs entry uses '/docs' (not '#docs'), then import and use this navLinks
constant in the page components that currently define navLinks (e.g., the
Examples and Generate page components) instead of redefining it locally so all
pages share the same source of truth.
In `@src/app/generate/page.tsx`:
- Around line 22-27: Before calling response.json() in the fetch handling inside
page.tsx, check response.ok and handle non-2xx responses first; if !response.ok,
read the response text (or use response.status / statusText) and surface that as
the error message instead of attempting to parse JSON, so setMarkdown is only
called after a successful response and alerts show the real server error; update
the block that currently does const data = await response.json(); if
(data.markdown) { setMarkdown(...) } else { alert(...) } to first verify
response.ok and handle fallback text/status accordingly.
In `@src/components/Generator/MarkdownPreview.tsx`:
- Around line 8-12: The handleCopy function fires
navigator.clipboard.writeText(content) without handling promise rejections;
update handleCopy to handle the returned Promise (either make handleCopy async
and await inside try/catch or attach .then/.catch) so rejections don’t become
unhandled; on success call setCopied(true) and start the timeout to reset it,
and on failure log/report the error (or show a user-facing fallback) instead of
optimistically setting copied—reference the handleCopy function and
navigator.clipboard.writeText call when making the change.
In `@src/components/Generator/SearchInput.tsx`:
- Line 3: Remove the unused named import Search from the lucide-react import in
SearchInput.tsx: update the import statement that currently reads "import {
Search, Loader2, Github } from 'lucide-react';" to only include the actually
used icons (e.g., Loader2 and Github) so the unused Search symbol is eliminated
and the bundler/linter warning is resolved.
- Around line 14-21: The submit handler in SearchInput uses
url.includes('github.com') and alert(), which is weak and poor UX; update
handleSubmit to parse the input with the URL constructor (wrap in try/catch),
validate that urlObj.hostname === 'github.com' or
urlObj.hostname.endsWith('.github.com') (so only real GitHub hostnames pass),
and replace the alert() with an inline error state (e.g., add/setError state in
the SearchInput component, set a descriptive message on validation failure,
clear the error on input change, and only call onGenerate(url) when validation
passes).
In `@src/components/sections/Hero.tsx`:
- Line 36: The Link in the Hero component uses a relative href ("generate")
which can resolve incorrectly on nested routes; update the href prop in the Link
element inside src/components/sections/Hero.tsx (the Link that currently reads
href="generate") to use an absolute path href="/generate" so it always points to
the top-level /generate route (matching the other Link that uses "/examples").
🧹 Nitpick comments (6)
src/components/layout/Navbar.tsx (1)
32-40: Usenext/link<Link>for internal navigation to enable client-side routing.The Navbar renders internal routes (
/,/features,/examples,/docs) using plain<a>tags, which causes full-page reloads instead of client-side navigation. Since the PR is moving from hash-based anchors to real Next.js routes, this should use<Link>fromnext/link.The same applies to the mobile menu links at lines 73-80.
♻️ Proposed fix
Add the import:
+"use client"; import React, { useState, useEffect } from 'react'; +import Link from 'next/link'; import { Menu, X, Github } from 'lucide-react';Replace
<a>with<Link>for internal navigation (desktop):- <a + <Link key={link.name} href={link.href} className="px-4 py-2 text-sm font-medium text-gray-400 hover:text-white transition-colors" > {link.name} - </a> + </Link>And similarly for the mobile menu links.
src/app/page.tsx (1)
8-13: Extract sharednavLinksto avoid duplication across pages.This identical
navLinksarray is duplicated in every page component (page.tsx,features/page.tsx,docs/page.tsx,generate/page.tsx). Extract it to a shared constant (e.g.,src/constants/navigation.ts) so changes only need to be made in one place.♻️ Example shared constant
Create
src/constants/navigation.ts:export const navLinks = [ { name: 'Home', href: '/' }, { name: 'Features', href: '/features' }, { name: 'Examples', href: '/examples' }, { name: 'Docs', href: '/docs' }, ];Then import it in each page:
+import { navLinks } from '@/constants/navigation'; export default function Home() { - const navLinks = [ - { name: 'Home', href: '/' }, - { name: 'Features', href: '/features' }, - { name: 'Examples', href: '/examples' }, - { name: 'Docs', href: '/docs' }, - ];src/app/features/page.tsx (1)
55-55: Inconsistent Tailwind gradient syntax — usebg-linear-to-b(v4) instead ofbg-gradient-to-b(v3).
Hero.tsx(line 23) uses the Tailwind v4 syntaxbg-linear-to-b, but this file uses the deprecated v3 syntaxbg-gradient-to-b. These should be consistent.♻️ Proposed fix
- <span className="bg-clip-text text-transparent bg-gradient-to-b from-white to-white/40"> + <span className="bg-clip-text text-transparent bg-linear-to-b from-white to-white/40">src/app/examples/page.tsx (2)
1-1:"use client"is unnecessary — this page has no client-side hooks or handlers.All interactivity lives in child components (
Navbar,Button) that are already marked"use client". Removing the directive lets Next.js render this page on the server, improving initial load performance.
63-104: Use a stable key instead of array index.
key={idx}is fine for a static list that never reorders, butexample.repois unique and more descriptive.- {examples.map((example, idx) => ( - <div - key={idx} + {examples.map((example) => ( + <div + key={example.repo}src/app/generate/page.tsx (1)
8-34: Consider usinguseRef+AbortControllerto cancel in-flight requests on unmount.If the user navigates away while a generation is in progress, the fetch continues and may call
setStateon an unmounted component. This is a minor concern for now but worth noting.
| import React from 'react'; | ||
| import { Navbar } from '@/components/layout/Navbar'; | ||
| import { Footer } from '@/components/layout/Footer'; | ||
| import { ChevronRight, Terminal } from 'lucide-react'; |
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.
Remove unused import ChevronRight.
Static analysis confirms ChevronRight is imported but never used.
🧹 Proposed fix
-import { ChevronRight, Terminal } from 'lucide-react';
+import { Terminal } from 'lucide-react';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { ChevronRight, Terminal } from 'lucide-react'; | |
| import { Terminal } from 'lucide-react'; |
🧰 Tools
🪛 GitHub Check: build-and-lint
[warning] 5-5:
'ChevronRight' is defined but never used
🤖 Prompt for AI Agents
In `@src/app/docs/page.tsx` at line 5, Remove the unused import symbol
ChevronRight from the import statement that currently reads "import {
ChevronRight, Terminal } from 'lucide-react';" so only the used symbol Terminal
is imported; update the import to remove the unused identifier and keep
formatting consistent.
| const navLinks = [ | ||
| { name: 'Home', href: '/' }, | ||
| { name: 'Features', href: '/#features' }, | ||
| { name: 'Examples', href: '/examples' }, | ||
| { name: 'Docs', href: '#docs' }, | ||
| ]; |
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.
🛠️ Refactor suggestion | 🟠 Major
Inconsistent nav links across pages and #docs vs /docs.
The navLinks array is duplicated in each page component (here and in generate/page.tsx), and the values differ: this file uses { href: '#docs' } (Line 41) while generate/page.tsx uses { href: '/docs' }. Extract a shared constant to avoid drift.
Proposed fix — shared nav links
Create a shared file, e.g. src/constants/navLinks.ts:
export const navLinks = [
{ name: 'Home', href: '/' },
{ name: 'Features', href: '/features' },
{ name: 'Examples', href: '/examples' },
{ name: 'Docs', href: '/docs' },
];Then import it in each page instead of redefining locally.
🤖 Prompt for AI Agents
In `@src/app/examples/page.tsx` around lines 37 - 42, Replace the duplicated local
navLinks arrays with a single shared constant and fix the Docs href to '/docs':
create a new exported constant named navLinks (array of objects with name/href)
in a common module, ensure the Docs entry uses '/docs' (not '#docs'), then
import and use this navLinks constant in the page components that currently
define navLinks (e.g., the Examples and Generate page components) instead of
redefining it locally so all pages share the same source of truth.
| <Link href="/#search-input"> | ||
| <Button variant="outline" className="w-full text-sm py-2"> | ||
| Try this style | ||
| <ExternalLink size={14} /> | ||
| </Button> | ||
| </Link> |
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.
Invalid HTML: <button> nested inside <a>.
Link renders an <a> tag and Button renders a <button>. Nesting interactive elements is invalid HTML and causes unpredictable behavior across browsers and assistive technologies. Either make the Button render as an anchor (e.g., pass asChild or use a styled <a>) or use router.push on the button's onClick.
🤖 Prompt for AI Agents
In `@src/app/examples/page.tsx` around lines 97 - 102, The Button is nested inside
Link (Link -> Button), which produces invalid HTML because Link renders an <a>
and Button renders a <button>; fix by making the Button render as an anchor or
by handling navigation in the Button's onClick: either update the Button
(component prop like asChild or prop to render an <a>) so it outputs an <a> and
keep it wrapped by Link, or remove Link and call router.push('/#search-input')
from an onClick handler on Button (while keeping ExternalLink icon inside).
Adjust usage around the Link, Button, and ExternalLink symbols accordingly to
avoid nesting interactive tags.
| const data = await response.json(); | ||
| if (data.markdown) { | ||
| setMarkdown(data.markdown); | ||
| } else { | ||
| alert(data.error || "Something went wrong"); | ||
| } |
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.
Check response.ok before parsing JSON to avoid misleading errors.
If the server returns a non-2xx status with an HTML body (e.g., a 502 gateway error), response.json() will throw a SyntaxError, and the catch block will show "Failed to connect to the server" — which is misleading.
Proposed fix
const response = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: githubUrl }),
});
+ if (!response.ok) {
+ const text = await response.text();
+ let message = "Something went wrong";
+ try { message = JSON.parse(text).error || message; } catch {}
+ alert(message);
+ return;
+ }
+
const data = await response.json();
if (data.markdown) {
setMarkdown(data.markdown);
} else {
alert(data.error || "Something went wrong");
}🤖 Prompt for AI Agents
In `@src/app/generate/page.tsx` around lines 22 - 27, Before calling
response.json() in the fetch handling inside page.tsx, check response.ok and
handle non-2xx responses first; if !response.ok, read the response text (or use
response.status / statusText) and surface that as the error message instead of
attempting to parse JSON, so setMarkdown is only called after a successful
response and alerts show the real server error; update the block that currently
does const data = await response.json(); if (data.markdown) { setMarkdown(...) }
else { alert(...) } to first verify response.ok and handle fallback text/status
accordingly.
| const handleCopy = () => { | ||
| navigator.clipboard.writeText(content); | ||
| setCopied(true); | ||
| setTimeout(() => setCopied(false), 2000); | ||
| }; |
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.
Unhandled promise rejection from navigator.clipboard.writeText.
writeText returns a Promise that rejects when clipboard access is denied or unavailable (e.g., non-HTTPS, permissions policy). The call is fire-and-forget, so a rejection becomes an unhandled promise error.
Proposed fix
- const handleCopy = () => {
- navigator.clipboard.writeText(content);
- setCopied(true);
- setTimeout(() => setCopied(false), 2000);
- };
+ const handleCopy = async () => {
+ try {
+ await navigator.clipboard.writeText(content);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ } catch {
+ console.error('Failed to copy to clipboard');
+ }
+ };📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleCopy = () => { | |
| navigator.clipboard.writeText(content); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| }; | |
| const handleCopy = async () => { | |
| try { | |
| await navigator.clipboard.writeText(content); | |
| setCopied(true); | |
| setTimeout(() => setCopied(false), 2000); | |
| } catch { | |
| console.error('Failed to copy to clipboard'); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In `@src/components/Generator/MarkdownPreview.tsx` around lines 8 - 12, The
handleCopy function fires navigator.clipboard.writeText(content) without
handling promise rejections; update handleCopy to handle the returned Promise
(either make handleCopy async and await inside try/catch or attach .then/.catch)
so rejections don’t become unhandled; on success call setCopied(true) and start
the timeout to reset it, and on failure log/report the error (or show a
user-facing fallback) instead of optimistically setting copied—reference the
handleCopy function and navigator.clipboard.writeText call when making the
change.
| @@ -0,0 +1,56 @@ | |||
| "use client"; | |||
| import React, { useState } from 'react'; | |||
| import { Search, Loader2, Github } from 'lucide-react'; | |||
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.
Remove unused import Search.
Static analysis confirms Search is imported but never used.
🧹 Proposed fix
-import { Search, Loader2, Github } from 'lucide-react';
+import { Loader2, Github } from 'lucide-react';📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| import { Search, Loader2, Github } from 'lucide-react'; | |
| import { Loader2, Github } from 'lucide-react'; |
🧰 Tools
🪛 GitHub Check: build-and-lint
[warning] 3-3:
'Search' is defined but never used
🤖 Prompt for AI Agents
In `@src/components/Generator/SearchInput.tsx` at line 3, Remove the unused named
import Search from the lucide-react import in SearchInput.tsx: update the import
statement that currently reads "import { Search, Loader2, Github } from
'lucide-react';" to only include the actually used icons (e.g., Loader2 and
Github) so the unused Search symbol is eliminated and the bundler/linter warning
is resolved.
| const handleSubmit = (e: React.FormEvent) => { | ||
| e.preventDefault(); | ||
| if (url.includes('github.com')) { | ||
| onGenerate(url); | ||
| } else { | ||
| alert("Please enter a valid GitHub URL"); | ||
| } | ||
| }; |
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.
Weak URL validation — url.includes('github.com') is easily bypassed.
This check matches strings like "not-github.com.evil.site/repo" or "evil.com?q=github.com". Consider using a stricter pattern. Also, alert() is a poor UX choice for validation feedback — consider inline error state instead.
🔒 Proposed stricter validation
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
- if (url.includes('github.com')) {
+ const githubUrlPattern = /^https?:\/\/(www\.)?github\.com\/[\w.-]+\/[\w.-]+/;
+ if (githubUrlPattern.test(url.trim())) {
onGenerate(url);
} else {
alert("Please enter a valid GitHub URL");
}
};📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleSubmit = (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| if (url.includes('github.com')) { | |
| onGenerate(url); | |
| } else { | |
| alert("Please enter a valid GitHub URL"); | |
| } | |
| }; | |
| const handleSubmit = (e: React.FormEvent) => { | |
| e.preventDefault(); | |
| const githubUrlPattern = /^https?:\/\/(www\.)?github\.com\/[\w.-]+\/[\w.-]+/; | |
| if (githubUrlPattern.test(url.trim())) { | |
| onGenerate(url); | |
| } else { | |
| alert("Please enter a valid GitHub URL"); | |
| } | |
| }; |
🤖 Prompt for AI Agents
In `@src/components/Generator/SearchInput.tsx` around lines 14 - 21, The submit
handler in SearchInput uses url.includes('github.com') and alert(), which is
weak and poor UX; update handleSubmit to parse the input with the URL
constructor (wrap in try/catch), validate that urlObj.hostname === 'github.com'
or urlObj.hostname.endsWith('.github.com') (so only real GitHub hostnames pass),
and replace the alert() with an inline error state (e.g., add/setError state in
the SearchInput component, set a descriptive message on validation failure,
clear the error on input change, and only call onGenerate(url) when validation
passes).
|
|
||
| {/* CTA Buttons - Now Functional */} | ||
| <div className="flex flex-col sm:flex-row justify-center items-center gap-4 mb-20 animate-in fade-in slide-in-from-bottom-6 duration-1000"> | ||
| <Link href="generate" className="w-full sm:w-auto"> |
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.
Bug: Missing leading slash — href="generate" should be href="/generate".
This is a relative path, which resolves based on the current route. On / it works, but if Hero is ever rendered on a nested page, it would resolve incorrectly (e.g., /features/generate). Line 43 correctly uses /examples with a leading slash.
🐛 Proposed fix
- <Link href="generate" className="w-full sm:w-auto">
+ <Link href="/generate" className="w-full sm:w-auto">📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Link href="generate" className="w-full sm:w-auto"> | |
| <Link href="/generate" className="w-full sm:w-auto"> |
🤖 Prompt for AI Agents
In `@src/components/sections/Hero.tsx` at line 36, The Link in the Hero component
uses a relative href ("generate") which can resolve incorrectly on nested
routes; update the href prop in the Link element inside
src/components/sections/Hero.tsx (the Link that currently reads href="generate")
to use an absolute path href="/generate" so it always points to the top-level
/generate route (matching the other Link that uses "/examples").
🚀 BΞYTΞFLʘW | Pull Request Protocol
PR Type: (Choose one:
feat|fix|refactor|docs|perf)Issue Link: Fixes #
📝 System Summary
Provide a concise brief of the changes introduced to the stream.
🛠️ Technical Changes
.........🧪 Quality Assurance (QA)
npm run buildexecuted without errors.🖼️ Visual Evidence
If this PR affects the UI, drop a screenshot or GIF below:
📡 Developer Authorization
Authorized by: @naheel0 @ansifmk
Timestamp: {{ 10/2/2026 }}