diff --git a/.env.example b/.env.example index b3625eb..e6eb1e7 100644 --- a/.env.example +++ b/.env.example @@ -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 diff --git a/app/admin/page.jsx b/app/admin/page.jsx index 2c774c1..a06120b 100644 --- a/app/admin/page.jsx +++ b/app/admin/page.jsx @@ -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 ( diff --git a/app/ai-notes/page.jsx b/app/ai-notes/page.jsx index 5b04120..9655a18 100644 --- a/app/ai-notes/page.jsx +++ b/app/ai-notes/page.jsx @@ -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 ( diff --git a/app/ai-quiz/page.jsx b/app/ai-quiz/page.jsx index c4bb84a..79247d7 100644 --- a/app/ai-quiz/page.jsx +++ b/app/ai-quiz/page.jsx @@ -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 ( diff --git a/app/ai-summary/page.jsx b/app/ai-summary/page.jsx index b81cfda..5022702 100644 --- a/app/ai-summary/page.jsx +++ b/app/ai-summary/page.jsx @@ -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 ( diff --git a/app/chat/page.jsx b/app/chat/page.jsx index d4770c4..ea65526 100644 --- a/app/chat/page.jsx +++ b/app/chat/page.jsx @@ -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 ( diff --git a/app/dashboard/layout.jsx b/app/dashboard/layout.jsx new file mode 100644 index 0000000..00d50d1 --- /dev/null +++ b/app/dashboard/layout.jsx @@ -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; +} diff --git a/app/flashcards/page.jsx b/app/flashcards/page.jsx index 64ac35c..cde647a 100644 --- a/app/flashcards/page.jsx +++ b/app/flashcards/page.jsx @@ -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 ( diff --git a/app/forgot-password/page.jsx b/app/forgot-password/page.jsx index b726861..71895ac 100644 --- a/app/forgot-password/page.jsx +++ b/app/forgot-password/page.jsx @@ -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 ; diff --git a/app/history/page.jsx b/app/history/page.jsx index d47bfeb..05b9374 100644 --- a/app/history/page.jsx +++ b/app/history/page.jsx @@ -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 ( diff --git a/app/layout.jsx b/app/layout.jsx index 31c42a2..76b3a16 100644 --- a/app/layout.jsx +++ b/app/layout.jsx @@ -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" }, @@ -12,6 +65,7 @@ export const metadata = { { url: "/icon.svg", type: "image/svg+xml" }, ], }, + manifest: "/manifest.webmanifest", }; export default function RootLayout({ children }) { diff --git a/app/login/page.jsx b/app/login/page.jsx index 75de0df..188e243 100644 --- a/app/login/page.jsx +++ b/app/login/page.jsx @@ -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 ; diff --git a/app/manifest.js b/app/manifest.js new file mode 100644 index 0000000..c55a401 --- /dev/null +++ b/app/manifest.js @@ -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", + }, + ], + }; +} diff --git a/app/notes/page.jsx b/app/notes/page.jsx index f782eef..ce309ec 100644 --- a/app/notes/page.jsx +++ b/app/notes/page.jsx @@ -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 ( diff --git a/app/opengraph-image.jsx b/app/opengraph-image.jsx new file mode 100644 index 0000000..613ba9d --- /dev/null +++ b/app/opengraph-image.jsx @@ -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( + ( +
+
+
+
+ AI +
+ StudyAI +
+
+ Turn Any Topic Into + Smart Study Material. +
+
+ AI notes, summaries, quizzes, flashcards, and solved questions for + focused learners. +
+
+
+ {["Smart Notes", "Quick Summary", "Quiz Ready", "Flashcards"].map( + (label, index) => ( +
+ {label} + Ready +
+ ), + )} +
+
+ ), + size, + ); +} diff --git a/app/page.jsx b/app/page.jsx index e706e86..0a5a399 100644 --- a/app/page.jsx +++ b/app/page.jsx @@ -8,20 +8,137 @@ import HowItWorks from "@/components/HowItWorks"; import Navbar from "@/components/Navbar"; import StatsSection from "@/components/StatsSection"; import Testimonials from "@/components/Testimonials"; +import { + absoluteUrl, + defaultDescription, + defaultTitle, + jsonLd, + siteName, + siteUrl, +} from "@/lib/seo"; + +const homepageFaqs = [ + { + question: "How does StudyAI work?", + answer: + "Enter a topic, paste study material, or ask a question. StudyAI uses AI to generate clear notes, summaries, explanations, quizzes, and practice material in seconds.", + }, + { + question: "Is StudyAI free?", + answer: + "Yes. Students can start with StudyAI for free and quickly try AI notes, summaries, quizzes, flashcards, and question solving.", + }, + { + question: "Can StudyAI create quizzes and flashcards?", + answer: + "Yes. StudyAI can turn topics and pasted notes into quiz-style practice questions and interactive flashcards for revision.", + }, + { + question: "Can StudyAI help with exam revision?", + answer: + "Yes. StudyAI helps organize key ideas, definitions, formulas, summaries, and practice questions so students can review faster before exams.", + }, +]; + +const structuredData = [ + { + "@context": "https://schema.org", + "@type": "WebApplication", + name: siteName, + url: siteUrl, + applicationCategory: "EducationalApplication", + operatingSystem: "Web", + description: defaultDescription, + offers: { + "@type": "Offer", + price: "0", + priceCurrency: "USD", + }, + featureList: [ + "AI notes generator", + "AI summary generator", + "AI quiz generator", + "AI flashcards", + "Question solver", + "Saved study workspace", + ], + publisher: { + "@type": "Organization", + name: siteName, + url: siteUrl, + logo: absoluteUrl("/icon.svg"), + }, + }, + { + "@context": "https://schema.org", + "@type": "Organization", + name: siteName, + url: siteUrl, + logo: absoluteUrl("/icon.svg"), + }, + { + "@context": "https://schema.org", + "@type": "FAQPage", + mainEntity: homepageFaqs.map((item) => ({ + "@type": "Question", + name: item.question, + acceptedAnswer: { + "@type": "Answer", + text: item.answer, + }, + })), + }, +]; + +export const metadata = { + title: { + absolute: defaultTitle, + }, + description: defaultDescription, + alternates: { + canonical: "/", + }, + openGraph: { + title: defaultTitle, + description: defaultDescription, + url: "/", + siteName, + 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"], + }, +}; export default function Home() { return ( -
- - - - - - - - - -
-
+ <> +