Skip to content
Merged
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
13 changes: 11 additions & 2 deletions src/app/generate/GeneratePageClient.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { Navbar } from "@/components/layout/Navbar";
import { Footer } from "@/components/layout/Footer";
import { SearchInput } from "@/components/Generator/SearchInput";
import { MarkdownPreview } from "@/components/Generator/MarkdownPreview";
import { LoadingOverlay } from "@/components/Generator/LoadingOverlay";
import { navLinks } from "@/constants/navLinks";
import { TerminalMockup } from "@/components/sections/TerminalMockup";

interface GeneratePageProps {
repoSlug?: string; // Optional pre-filled repo from server-side route
repoSlug?: string;
}

export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
Expand Down Expand Up @@ -66,8 +68,14 @@ export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
};

return (
<div className="min-h-screen bg-black text-white">
<div className="relative min-h-screen bg-black text-white">
{/* UI LOADING OVERLAY
Renders on top of everything when isLoading is true
*/}
{isLoading && <LoadingOverlay />}

<Navbar links={navLinks} />

<main className="pt-40 pb-20 px-4 max-w-6xl mx-auto">
<SearchInput
onGenerate={handleGenerate}
Expand All @@ -77,6 +85,7 @@ export default function GeneratePageClient({ repoSlug }: GeneratePageProps) {
/>
<MarkdownPreview content={markdown} />
</main>
<TerminalMockup />
<Footer />
</div>
);
Expand Down
4 changes: 2 additions & 2 deletions src/app/generate/[repo]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export async function generateMetadata({
params,
}: PageProps): Promise<Metadata> {
const resolvedParams = await params;
const repoName = resolvedParams.repo; // full repo slug like "facebook/react"
const repoDisplayName = repoName.split("/").pop(); // e.g., "react"
const repoName = resolvedParams.repo;
const repoDisplayName = repoName.split("/").slice(-1)[0] ?? repoName;

return {
title: `AI-Generated README for ${repoDisplayName} | ReadmeGenAI`,
Expand Down
106 changes: 106 additions & 0 deletions src/components/Generator/LoadingOverlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"use client";

import React, { useState, useEffect } from "react";

export const LoadingOverlay = () => {
const [terminalText, setTerminalText] = useState("");
const fullText = "INITIALIZING_NEURAL_ENGINE... [OK]";

useEffect(() => {
let i = 0;
const interval = setInterval(() => {
setTerminalText(fullText.slice(0, i));
i++;
if (i > fullText.length) i = 0;
}, 100);
return () => clearInterval(interval);
}, []);

return (
<div className="fixed inset-0 z-100 flex flex-col items-center justify-center bg-[#050505] font-mono">
{/* BACKGROUND GRID EFFECT */}
<div
className="absolute inset-0 opacity-10"
style={{
backgroundImage:
"linear-gradient(#333 1px, transparent 1px), linear-gradient(90deg, #333 1px, transparent 1px)",
backgroundSize: "40px 40px",
}}
></div>

{/* RING CONTAINER */}
<div className="relative flex h-64 w-64 items-center justify-center">
{/* Chromatic Orbiting Rings */}
<div className="absolute h-36 w-36 rounded-full border border-red-500/40 mix-blend-screen blur-[2px] animate-[ring-pulse_4s_linear_infinite] scale-110"></div>
<div className="absolute h-36 w-36 rounded-full border border-emerald-400/40 mix-blend-screen blur-[2px] animate-[ring-pulse_4s_linear_infinite_1s] scale-105"></div>
<div className="absolute h-36 w-36 rounded-full border border-indigo-500/40 mix-blend-screen blur-[2px] animate-[ring-pulse_4s_linear_infinite_2s] scale-110"></div>

{/* Technical Inner Ring */}
<div className="absolute h-28 w-28 rounded-full border border-dashed border-white/20 animate-spin-slow"></div>

{/* Core White Ring */}
<div className="absolute h-32 w-32 rounded-full border-2 border-white shadow-[0_0_30px_rgba(255,255,255,0.2)] animate-[ring-pulse_3s_ease-in-out_infinite]"></div>

{/* Binary Data Bits (Decorative) */}
<div className="absolute inset-0 flex items-center justify-center opacity-40 text-[8px] text-emerald-500 pointer-events-none">
<div className="animate-pulse">01011001</div>
</div>
</div>

{/* CODING VIBE TEXT ELEMENTS */}
<div className="mt-8 flex flex-col items-center gap-4 z-10">
<div className="flex flex-col items-center">
<p className="text-xs tracking-[0.5em] text-zinc-500 uppercase mb-1">
System Status
</p>
<div className="flex items-baseline gap-2">
<span className="h-2 w-2 rounded-full bg-emerald-500 animate-pulse"></span>
<p className="text-xl font-bold tracking-tighter text-white">
{terminalText}
<span className="animate-bounce">_</span>
</p>
</div>
</div>

{/* DATA METRICS FOOTER */}
<div className="mt-4 grid grid-cols-3 gap-8 text-[10px] text-zinc-600 border-t border-zinc-800 pt-4 uppercase tracking-widest">
<div className="flex flex-col items-center">
<span>CPU</span>
<span className="text-emerald-400">88.4%</span>
</div>
<div className="flex flex-col items-center border-x border-zinc-800 px-8">
<span>MEM</span>
<span className="text-indigo-400">12GB</span>
</div>
<div className="flex flex-col items-center">
<span>PING</span>
<span className="text-red-400">14MS</span>
</div>
</div>
</div>

<style
dangerouslySetInnerHTML={{
__html: `
@keyframes ring-pulse {
0%, 100% { transform: scale(1) rotate(0deg); opacity: 0.3; }
50% { transform: scale(1.1) rotate(180deg); opacity: 0.7; }
}
.animate-spin-slow {
animation: spin 10s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.mix-blend-screen {
mix-blend-mode: screen;
}
`,
}}
/>
</div>
);
};

export default LoadingOverlay;
Loading