Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 87 additions & 58 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,65 +1,94 @@
import Image from "next/image";
"use client";

import { useState } from "react";
import ReactMarkdown from "react-markdown";

export default function Home() {
const [url, setUrl] = useState("");
const [loading, setLoading] = useState(false);
const [markdown, setMarkdown] = useState("");
const [error, setError] = useState("");

const handleGenerate = async () => {
setLoading(true);
setError("");
setMarkdown("");

try {
const response = await fetch("/api/generate", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url }),
});

const data = await response.json();

if (!response.ok) throw new Error(data.error || "Failed to generate");

setMarkdown(data.markdown);
} catch (err: unknown) {
if (err instanceof Error) {
setError(err.message);
} else {
setError(String(err));
}
} finally {
setLoading(false);
}
};

const copyToClipboard = () => {
navigator.clipboard.writeText(markdown);
alert("Copied to clipboard!");
};

return (
<div className="flex min-h-screen items-center justify-center bg-zinc-50 font-sans dark:bg-black">
<main className="flex min-h-screen w-full max-w-3xl flex-col items-center justify-between py-32 px-16 bg-white dark:bg-black sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={100}
height={20}
priority
/>
<div className="flex flex-col items-center gap-6 text-center sm:items-start sm:text-left">
<h1 className="max-w-xs text-3xl font-semibold leading-10 tracking-tight text-black dark:text-zinc-50">
To get started, edit the page.tsx file.
</h1>
<p className="max-w-md text-lg leading-8 text-zinc-600 dark:text-zinc-400">
Looking for a starting point or more instructions? Head over to{" "}
<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Templates
</a>{" "}
or the{" "}
<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
className="font-medium text-zinc-950 dark:text-zinc-50"
>
Learning
</a>{" "}
center.
</p>
<main className="min-h-screen bg-slate-950 text-slate-50 p-8">
<div className="max-w-4xl mx-auto space-y-8">
{/* Header */}
<div className="text-center space-y-2">
<h1 className="text-4xl font-bold tracking-tight text-blue-400">ReadmeGenAI</h1>
<p className="text-slate-400">Turn any GitHub URL into a professional README in seconds.</p>
</div>
<div className="flex flex-col gap-4 text-base font-medium sm:flex-row">
<a
className="flex h-12 w-full items-center justify-center gap-2 rounded-full bg-foreground px-5 text-background transition-colors hover:bg-[#383838] dark:hover:bg-[#ccc] md:w-[158px]"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={16}
height={16}
/>
Deploy Now
</a>
<a
className="flex h-12 w-full items-center justify-center rounded-full border border-solid border-black/[.08] px-5 transition-colors hover:border-transparent hover:bg-black/[.04] dark:border-white/[.145] dark:hover:bg-[#1a1a1a] md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"

{/* Input Section */}
<div className="flex gap-4">
<input
type="text"
placeholder="https://github.com/username/repo"
className="flex-1 bg-slate-900 border border-slate-800 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
value={url}
onChange={(e) => setUrl(e.target.value)}
/>
<button
onClick={handleGenerate}
disabled={loading || !url}
className="bg-blue-600 hover:bg-blue-500 disabled:opacity-50 px-6 py-2 rounded-lg font-medium transition-all"
>
Documentation
</a>
{loading ? "Generating..." : "Generate"}
</button>
</div>
</main>
</div>

{error && <div className="p-4 bg-red-900/20 border border-red-900 text-red-400 rounded-lg">{error}</div>}

{/* Output Section */}
{markdown && (
<div className="space-y-4 animate-in fade-in duration-700">
<div className="flex justify-between items-center">
<h2 className="text-xl font-semibold text-slate-300">Preview</h2>
<button
onClick={copyToClipboard}
className="text-sm bg-slate-800 hover:bg-slate-700 px-3 py-1 rounded border border-slate-700"
>
Copy Markdown
</button>
</div>
<div className="prose prose-invert max-w-none bg-slate-900 p-6 rounded-xl border border-slate-800 shadow-xl">
<ReactMarkdown>{markdown}</ReactMarkdown>
</div>
</div>
)}
</div>
</main>
);
}
}
Loading