Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
b829cb5
Add shared SEO utilities
malikfaheem007 Jul 18, 2026
7ca3c75
Add app-wide SEO metadata
malikfaheem007 Jul 18, 2026
f0f44e2
Add homepage SEO schema and social metadata
malikfaheem007 Jul 18, 2026
8fd15b8
Add robots configuration
malikfaheem007 Jul 18, 2026
4fc5c00
Add sitemap route
malikfaheem007 Jul 18, 2026
2e188e5
Add web app manifest
malikfaheem007 Jul 18, 2026
ef1daa1
Add Open Graph image route
malikfaheem007 Jul 18, 2026
e7aece1
Add Twitter image route
malikfaheem007 Jul 18, 2026
794d755
Noindex dashboard route
malikfaheem007 Jul 18, 2026
81d208c
Noindex admin page
malikfaheem007 Jul 18, 2026
24c27b6
Noindex AI notes page
malikfaheem007 Jul 18, 2026
a51d0b8
Noindex AI quiz page
malikfaheem007 Jul 18, 2026
4c5f6df
Noindex AI summary page
malikfaheem007 Jul 18, 2026
8695bc2
Noindex AI chat page
malikfaheem007 Jul 18, 2026
9ba9b76
Noindex flashcards page
malikfaheem007 Jul 18, 2026
3a55c0f
Noindex forgot password page
malikfaheem007 Jul 18, 2026
613949a
Noindex history page
malikfaheem007 Jul 18, 2026
9fbaaf9
Noindex login page
malikfaheem007 Jul 18, 2026
619ead5
Noindex saved notes page
malikfaheem007 Jul 18, 2026
d8c531e
Noindex planner page
malikfaheem007 Jul 18, 2026
b4bc4ff
Noindex profile page
malikfaheem007 Jul 18, 2026
358da18
Noindex questions page
malikfaheem007 Jul 18, 2026
b52e2da
Noindex reset password page
malikfaheem007 Jul 18, 2026
e7fa040
Noindex settings page
malikfaheem007 Jul 18, 2026
ef2f996
Noindex sign in alias page
malikfaheem007 Jul 18, 2026
542bbdb
Noindex sign up alias page
malikfaheem007 Jul 18, 2026
e5e1965
Noindex signup page
malikfaheem007 Jul 18, 2026
dc667fe
Noindex summaries page
malikfaheem007 Jul 18, 2026
6c771a0
Update example site URL port
malikfaheem007 Jul 18, 2026
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
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ GEMINI_MODEL=gemini-2.5-flash
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url_here
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key_here
SUPABASE_SERVICE_ROLE_KEY=your_supabase_service_role_key_here
NEXT_PUBLIC_SITE_URL=http://localhost:3000
NEXT_PUBLIC_SITE_URL=http://localhost:3005
NEXT_PUBLIC_ADMIN_EMAIL=your_admin_email@example.com
8 changes: 5 additions & 3 deletions app/admin/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AdminDashboardClient from "@/components/AdminDashboardClient";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "Admin Dashboard - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "Admin Dashboard",
description: "Manage StudyAI users and platform analytics.",
};
path: "/admin",
});

export default function AdminPage() {
return (
Expand Down
8 changes: 5 additions & 3 deletions app/ai-notes/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AINotesGenerator from "@/components/AINotesGenerator";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "AI Notes - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "AI Notes",
description: "Generate Gemini-powered study notes and save them to StudyAI.",
};
path: "/ai-notes",
});

export default function AINotesPage() {
return (
Expand Down
8 changes: 5 additions & 3 deletions app/ai-quiz/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AIQuizGenerator from "@/components/AIQuizGenerator";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "AI Quiz - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "AI Quiz",
description: "Generate interactive Gemini-powered quizzes from any topic or notes.",
};
path: "/ai-quiz",
});

export default function AIQuizPage() {
return (
Expand Down
8 changes: 5 additions & 3 deletions app/ai-summary/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AISummaryGenerator from "@/components/AISummaryGenerator";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "AI Summary - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "AI Summary",
description: "Summarize long study material with Gemini-powered AI.",
};
path: "/ai-summary",
});

export default function AISummaryPage() {
return (
Expand Down
8 changes: 5 additions & 3 deletions app/chat/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AIChatPageClient from "@/components/AIChatPageClient";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "AI Chat - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "AI Chat",
description: "Chat with StudyAI and save your conversations securely.",
};
path: "/chat",
});

export default function ChatPage() {
return (
Expand Down
11 changes: 11 additions & 0 deletions app/dashboard/layout.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = buildNoIndexMetadata({
title: "Dashboard",
description: "Open your StudyAI workspace.",
path: "/dashboard",
});

export default function DashboardLayout({ children }) {
return children;
}
8 changes: 5 additions & 3 deletions app/flashcards/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AIFlashcardsGenerator from "@/components/AIFlashcardsGenerator";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "Flashcards - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "Flashcards",
description: "Generate interactive Gemini-powered flashcards from any topic or notes.",
};
path: "/flashcards",
});

export default function FlashcardsPage() {
return (
Expand Down
8 changes: 5 additions & 3 deletions app/forgot-password/page.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ForgotPasswordForm } from "@/components/PasswordResetForms";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "Forgot Password - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "Forgot Password",
description: "Reset your StudyAI password securely.",
};
path: "/forgot-password",
});

export default function ForgotPasswordPage() {
return <ForgotPasswordForm />;
Expand Down
8 changes: 5 additions & 3 deletions app/history/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import AIHistoryPageClient from "@/components/AIHistoryPageClient";
import DashboardShell from "@/components/DashboardShell";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "AI History - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "AI History",
description: "Search, filter, reuse, and manage previous StudyAI generations.",
};
path: "/history",
});

export default function HistoryPage() {
return (
Expand Down
58 changes: 56 additions & 2 deletions app/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,62 @@
import "./globals.css";
import ThemeProvider from "@/components/ThemeProvider";
import {
defaultDescription,
defaultTitle,
seoKeywords,
siteName,
siteUrl,
} from "@/lib/seo";

export const metadata = {
title: "StudyAI - Study Smarter with AI",
description: "Generate notes, solve questions, and summarize topics instantly.",
metadataBase: new URL(siteUrl),
applicationName: siteName,
title: {
default: defaultTitle,
template: `%s | ${siteName}`,
},
description: defaultDescription,
keywords: seoKeywords,
authors: [{ name: siteName }],
creator: siteName,
publisher: siteName,
category: "Education",
alternates: {
canonical: "/",
},
openGraph: {
type: "website",
locale: "en_US",
url: "/",
siteName,
title: defaultTitle,
description: defaultDescription,
images: [
{
url: "/opengraph-image",
width: 1200,
height: 630,
alt: "StudyAI AI study workspace for notes, summaries, quizzes, and flashcards",
},
],
},
twitter: {
card: "summary_large_image",
title: defaultTitle,
description: defaultDescription,
images: ["/twitter-image"],
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
"max-video-preview": -1,
"max-image-preview": "large",
"max-snippet": -1,
},
},
icons: {
icon: [
{ url: "/icon.svg", type: "image/svg+xml" },
Expand All @@ -12,6 +65,7 @@ export const metadata = {
{ url: "/icon.svg", type: "image/svg+xml" },
],
},
manifest: "/manifest.webmanifest",
};

export default function RootLayout({ children }) {
Expand Down
7 changes: 7 additions & 0 deletions app/login/page.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import AuthForm from "@/components/AuthForm";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = buildNoIndexMetadata({
title: "Login",
description: "Log in to your StudyAI account.",
path: "/login",
});

export default function LoginPage() {
return <AuthForm mode="login" />;
Expand Down
22 changes: 22 additions & 0 deletions app/manifest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { defaultDescription, siteName } from "@/lib/seo";

export default function manifest() {
return {
name: `${siteName} - AI Study Workspace`,
short_name: siteName,
description: defaultDescription,
start_url: "/",
scope: "/",
display: "standalone",
background_color: "#f8fafc",
theme_color: "#635bff",
icons: [
{
src: "/icon.svg",
sizes: "64x64",
type: "image/svg+xml",
purpose: "any maskable",
},
],
};
}
8 changes: 5 additions & 3 deletions app/notes/page.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import DashboardShell from "@/components/DashboardShell";
import SavedNotesPageClient from "@/components/SavedNotesPageClient";
import { buildNoIndexMetadata } from "@/lib/seo";

export const metadata = {
title: "Saved Notes - StudyAI",
export const metadata = buildNoIndexMetadata({
title: "Saved Notes",
description: "Search, filter, favorite, and manage saved StudyAI notes, summaries, quizzes, and flashcards.",
};
path: "/notes",
});

export default function NotesPage() {
return (
Expand Down
125 changes: 125 additions & 0 deletions app/opengraph-image.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { ImageResponse } from "next/og";

export const alt =
"StudyAI - AI study notes, summaries, quizzes, and flashcards";
export const size = {
width: 1200,
height: 630,
};
export const contentType = "image/png";

export default function Image() {
return new ImageResponse(
(
<div
style={{
alignItems: "center",
background:
"linear-gradient(135deg, #eef2ff 0%, #ffffff 44%, #dbeafe 100%)",
color: "#0f172a",
display: "flex",
height: "100%",
justifyContent: "space-between",
padding: "72px",
width: "100%",
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
gap: 28,
maxWidth: 650,
}}
>
<div
style={{
alignItems: "center",
display: "flex",
fontSize: 34,
fontWeight: 900,
gap: 18,
}}
>
<div
style={{
alignItems: "center",
background: "linear-gradient(135deg, #6366f1, #2563eb)",
borderRadius: 26,
color: "white",
display: "flex",
height: 76,
justifyContent: "center",
width: 76,
}}
>
AI
</div>
StudyAI
</div>
<div
style={{
display: "flex",
flexDirection: "column",
fontSize: 78,
fontWeight: 950,
letterSpacing: 0,
lineHeight: 0.98,
}}
>
<span>Turn Any Topic Into</span>
<span style={{ color: "#635bff" }}>Smart Study Material.</span>
</div>
<div
style={{
color: "#475569",
fontSize: 30,
lineHeight: 1.35,
maxWidth: 600,
}}
>
AI notes, summaries, quizzes, flashcards, and solved questions for
focused learners.
</div>
</div>
<div
style={{
background: "rgba(255,255,255,0.82)",
border: "1px solid #dbeafe",
borderRadius: 38,
boxShadow: "0 28px 80px rgba(99,91,255,0.20)",
display: "flex",
flexDirection: "column",
gap: 20,
padding: 30,
width: 350,
}}
>
{["Smart Notes", "Quick Summary", "Quiz Ready", "Flashcards"].map(
(label, index) => (
<div
key={label}
style={{
alignItems: "center",
background: index === 0 ? "#eef2ff" : "#f8fafc",
border: "1px solid #e2e8f0",
borderRadius: 20,
color: index === 0 ? "#4f46e5" : "#334155",
display: "flex",
fontSize: 24,
fontWeight: 800,
justifyContent: "space-between",
padding: "18px 20px",
}}
>
<span>{label}</span>
<span style={{ color: "#22c55e" }}>Ready</span>
</div>
),
)}
</div>
</div>
),
size,
);
}
Loading