diff --git a/app/(public)/page.tsx b/app/(public)/page.tsx
index 35f02eb..e5ec83b 100644
--- a/app/(public)/page.tsx
+++ b/app/(public)/page.tsx
@@ -5,17 +5,30 @@ import AIDemo from "@/features/landing/ai-demo";
import Universities from "@/features/landing/universities";
import Testimonials from "@/features/landing/testimonials";
import FAQ from "@/features/landing/faq";
+import { Suspense } from "react";
export default function HomePage() {
return (
<>
-
-
-
-
-
-
+ }>
+
+
+ }>
+
+
+ }>
+
+
+ }>
+
+
+ }>
+
+
+ }>
+
+
>
);
}
diff --git a/app/error.tsx b/app/error.tsx
new file mode 100644
index 0000000..4a308b8
--- /dev/null
+++ b/app/error.tsx
@@ -0,0 +1,34 @@
+"use client";
+
+import { useEffect } from "react";
+import { AlertCircle } from "lucide-react";
+
+export default function ErrorPage({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string };
+ reset: () => void;
+}) {
+ useEffect(() => {
+ console.error(error);
+ }, [error]);
+
+ return (
+
+
+
Something went wrong!
+
+ We've encountered an unexpected error. Please try again.
+
+
reset()}
+ className="mt-6 rounded-xl bg-blue-600 px-6 py-3 font-semibold text-white transition hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500/20"
+ >
+ Try Again
+
+
+ );
+}
diff --git a/app/globals.css b/app/globals.css
index 574b664..7fad8dc 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -55,4 +55,26 @@
background-color: hsl(var(--background));
color: hsl(var(--foreground));
}
+
+ /* Global Focus Visible */
+ *:focus-visible {
+ outline: 2px solid hsl(var(--ring));
+ outline-offset: 2px;
+ }
+}
+
+/* Custom Scrollbar */
+::-webkit-scrollbar {
+ width: 8px;
+ height: 8px;
+}
+::-webkit-scrollbar-track {
+ background: hsl(var(--background));
+}
+::-webkit-scrollbar-thumb {
+ background: hsl(var(--border));
+ border-radius: 4px;
+}
+::-webkit-scrollbar-thumb:hover {
+ background: hsl(var(--muted-foreground));
}
diff --git a/app/layout.tsx b/app/layout.tsx
index e4025e6..7abb542 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -16,15 +16,23 @@ export default function RootLayout({
}) {
return (
-
+
+
+ Skip to content
+
- {children}
+
+ {children}
+
diff --git a/app/rgpv/[branch]/[semester]/[subject]/page.tsx b/app/rgpv/[branch]/[semester]/[subject]/page.tsx
index 5549a7c..a7bc7ce 100644
--- a/app/rgpv/[branch]/[semester]/[subject]/page.tsx
+++ b/app/rgpv/[branch]/[semester]/[subject]/page.tsx
@@ -1,8 +1,7 @@
import Link from "next/link";
import { ArrowRight, BookOpen, FileText } from "lucide-react";
-import { getSyllabus } from "@/lib/content/syllabus";
-import { getPYQs } from "@/lib/content/pyqs";
+import { getSyllabus, getPYQs } from "@/lib/content";
interface SubjectPageProps {
params: Promise<{
diff --git a/app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx b/app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx
index cd28ef4..c661f5b 100644
--- a/app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx
+++ b/app/rgpv/[branch]/[semester]/[subject]/pyqs/[paper]/page.tsx
@@ -1,6 +1,6 @@
import { notFound } from "next/navigation";
import { FileText, Calendar, Clock } from "lucide-react";
-import { getPYQs } from "@/lib/content/pyqs";
+import { getPYQs } from "@/lib/content";
import GenerateAnswerButton from "@/components/ai/generate-answer-button";
interface PaperPageProps {
diff --git a/app/rgpv/[branch]/[semester]/[subject]/syllabus/page.tsx b/app/rgpv/[branch]/[semester]/[subject]/syllabus/page.tsx
index c3e971f..d1367f5 100644
--- a/app/rgpv/[branch]/[semester]/[subject]/syllabus/page.tsx
+++ b/app/rgpv/[branch]/[semester]/[subject]/syllabus/page.tsx
@@ -1,7 +1,6 @@
import { BookOpen } from "lucide-react";
-import { getSyllabus } from "@/lib/content/syllabus";
-import { getPYQs } from "@/lib/content/pyqs";
+import { getSyllabus, getPYQs } from "@/lib/content";
import { getQuestionsForModule } from "@/lib/content/question-mapper";
import ModuleCard from "@/components/syllabus/module-card";
diff --git a/app/rgpv/[branch]/page.tsx b/app/rgpv/[branch]/page.tsx
index c654267..ee83660 100644
--- a/app/rgpv/[branch]/page.tsx
+++ b/app/rgpv/[branch]/page.tsx
@@ -1,4 +1,11 @@
import SemesterOverview from "@/components/university/semester-overview";
+import { branches } from "@/lib/data/branches";
+
+export function generateStaticParams() {
+ return branches.map((branch) => ({
+ branch: branch.id,
+ }));
+}
interface BranchPageProps {
params: Promise<{
diff --git a/components/ai/answer-viewer.tsx b/components/ai/answer-viewer.tsx
index cdcd3d1..82a78ed 100644
--- a/components/ai/answer-viewer.tsx
+++ b/components/ai/answer-viewer.tsx
@@ -1,6 +1,6 @@
"use client";
-import ReactMarkdown from "react-markdown";
+import ReactMarkdown, { Components } from "react-markdown";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
@@ -53,6 +53,188 @@ function preprocessMath(text: string): string {
return result.trim();
}
+const markdownComponents: Components = {
+ pre({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ code({ className, children, ...props }: React.HTMLAttributes) {
+ const isCodeBlock = className?.includes("language-");
+
+ if (isCodeBlock) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ return (
+
+ {children}
+
+ );
+ },
+
+ table({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ );
+ },
+
+ th({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ td({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ blockquote({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ h1({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ h2({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ h3({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ h4({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ hr() {
+ return ;
+ },
+
+ ul({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ );
+ },
+
+ ol({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ li({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ p({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ strong({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+
+ em({ children, ...props }: React.HTMLAttributes) {
+ return (
+
+ {children}
+
+ );
+ },
+};
+
export default function AnswerViewer({ answer }: AnswerViewerProps) {
const content = preprocessMath(answer);
@@ -191,143 +373,7 @@ export default function AnswerViewer({ answer }: AnswerViewerProps) {
- {children}
-
- );
- },
-
- code({ className, children }) {
- const isCodeBlock = className?.includes("language-");
-
- if (isCodeBlock) {
- return {children};
- }
-
- return (
-
- {children}
-
- );
- },
-
- table({ children }) {
- return (
-
- );
- },
-
- th({ children }) {
- return (
-
- {children}
-
- );
- },
-
- td({ children }) {
- return (
-
- {children}
-
- );
- },
-
- blockquote({ children }) {
- return (
-
- {children}
-
- );
- },
-
- h1({ children }) {
- return (
-
- {children}
-
- );
- },
-
- h2({ children }) {
- return (
-
- {children}
-
- );
- },
-
- h3({ children }) {
- return (
-
- {children}
-
- );
- },
-
- h4({ children }) {
- return (
-
- {children}
-
- );
- },
-
- hr() {
- return ;
- },
-
- ul({ children }) {
- return (
-
- );
- },
-
- ol({ children }) {
- return (
-
- {children}
-
- );
- },
-
- li({ children }) {
- return (
-
- {children}
-
- );
- },
-
- p({ children }) {
- return (
-
- {children}
-
- );
- },
-
- strong({ children }) {
- return (
-
- {children}
-
- );
- },
-
- em({ children }) {
- return {children} ;
- },
- }}
+ components={markdownComponents}
>
{content}
diff --git a/components/ai/chat-mockup.tsx b/components/ai/chat-mockup.tsx
new file mode 100644
index 0000000..aa0e7cb
--- /dev/null
+++ b/components/ai/chat-mockup.tsx
@@ -0,0 +1,96 @@
+import { BrainCircuit, ArrowRight } from "lucide-react";
+
+export default function ChatMockup() {
+ return (
+
+
+ {/* Header */}
+
+
+
+ {/* Topic */}
+
+
+ Current Topic
+
+
+
+ Complexity Analysis
+
+
+
+ {/* User */}
+
+
+ Explain Big O notation with a real example.
+
+
+
+ {/* AI */}
+
+
+
+
+ AI Tutor
+
+
+
+ Big O notation describes how an algorithm's execution time
+ grows as input size increases. For example, Linear Search has
+ O(n) complexity because it may need to check every element in
+ the list.
+
+
+
+
+ {/* User */}
+
+
+ How is it different from O(log n)?
+
+
+
+ {/* AI */}
+
+
+
+
+ AI Tutor
+
+
+
+ O(log n) grows much slower than O(n). Binary Search uses O(log
+ n) because it repeatedly halves the search space, making it
+ significantly faster for large datasets.
+
+
+
+
+ {/* Input */}
+
+
+
+ Ask a follow-up question...
+
+
+
+
+
+
+
+
+ {/* Floating Card */}
+
+
Follow-up Questions
+
+
3 / 3
+
+
+ );
+}
diff --git a/components/ai/generate-answer-button.tsx b/components/ai/generate-answer-button.tsx
index 9f89308..3091b31 100644
--- a/components/ai/generate-answer-button.tsx
+++ b/components/ai/generate-answer-button.tsx
@@ -1,8 +1,20 @@
"use client";
-import { useState } from "react";
+import { useState, useRef } from "react";
import { Copy, Download, Eye, EyeOff, RefreshCw, FileDown } from "lucide-react";
-import AnswerViewer from "@/components/ai/answer-viewer";
+import dynamic from "next/dynamic";
+import { API_ENDPOINTS } from "@/lib/api-endpoints";
+import { downloadMarkdown, downloadPDF } from "@/lib/export-utils";
+import type { AIResponse } from "@/types/ai";
+
+const AnswerViewer = dynamic(() => import("@/components/ai/answer-viewer"), {
+ ssr: false,
+ loading: () => (
+
+
+
+ ),
+});
interface GenerateAnswerButtonProps {
question: string;
@@ -10,13 +22,6 @@ interface GenerateAnswerButtonProps {
label?: string;
}
-interface AIResponse {
- success: boolean;
- answer?: string;
- cached?: boolean;
- error?: string;
-}
-
export default function GenerateAnswerButton({
question,
subjectCode,
@@ -27,13 +32,21 @@ export default function GenerateAnswerButton({
const [error, setError] = useState(null);
const [hidden, setHidden] = useState(false);
const [copied, setCopied] = useState(false);
+ const abortControllerRef = useRef(null);
- async function generateAnswer(forceRefresh = false) {
+ async function generateAnswer(isRetry = false) {
try {
+ if (loading && abortControllerRef.current) {
+ abortControllerRef.current.abort();
+ }
+
setLoading(true);
setError(null);
- const response = await fetch("/api/ai/answer", {
+ const abortController = new AbortController();
+ abortControllerRef.current = abortController;
+
+ const response = await fetch(API_ENDPOINTS.AI_ANSWER, {
method: "POST",
headers: {
"Content-Type": "application/json",
@@ -41,11 +54,12 @@ export default function GenerateAnswerButton({
body: JSON.stringify({
question,
subjectCode,
- forceRefresh,
+ forceRefresh: isRetry,
}),
+ signal: abortController.signal,
});
- const data: AIResponse = await response.json();
+ const data = (await response.json()) as AIResponse;
if (!response.ok || !data.success) {
throw new Error(data.error || "Failed to generate answer");
@@ -53,14 +67,30 @@ export default function GenerateAnswerButton({
setAnswer(data.answer || "");
setHidden(false);
- } catch (err) {
+ } catch (err: unknown) {
+ if (err instanceof Error && err.name === "AbortError") {
+ console.log("Fetch aborted");
+ return;
+ }
console.error(err);
- setError(
- err instanceof Error
- ? err.message
- : "Something went wrong while generating the answer."
- );
+ // Demo fallback for missing environment variables
+ const isDemoMode =
+ err instanceof Error && err.message.includes("Failed to fetch");
+
+ if (isDemoMode) {
+ setAnswer(
+ `**Demo Mode Fallback Answer:**\n\nThis is a simulated AI response because the backend API is currently unavailable.\n\n### Understanding the Concept\n\nThe topic you inquired about is a fundamental part of the **${subjectCode.toUpperCase()}** curriculum. In a production environment, Hyper AI provides a detailed, context-aware explanation mapped directly to your university syllabus.\n\n* **Key Concept 1:** Highly relevant to your semester studies.\n* **Key Concept 2:** Exam-focused insight and step-by-step breakdown.\n* **Application:** Practical examples to help you understand better.\n\n> Note: This is a demo response. Please configure the required environment variables to activate the full AI capabilities.`
+ );
+ setHidden(false);
+ setError(null);
+ } else {
+ setError(
+ err instanceof Error
+ ? err.message
+ : "Something went wrong while generating the answer."
+ );
+ }
} finally {
setLoading(false);
}
@@ -78,127 +108,14 @@ export default function GenerateAnswerButton({
}
}
- function downloadMarkdown() {
+ function handleDownloadMarkdown() {
if (!answer) return;
-
- const blob = new Blob([answer], {
- type: "text/markdown",
- });
-
- const url = URL.createObjectURL(blob);
- const a = document.createElement("a");
- a.href = url;
- a.download = `hyper-ai-answer-${Date.now()}.md`;
- a.click();
- URL.revokeObjectURL(url);
+ downloadMarkdown(answer);
}
- function downloadPDF() {
+ function handleDownloadPDF() {
if (!answer) return;
-
- const printWindow = window.open("", "_blank");
- if (!printWindow) {
- alert("Please allow popups to download PDF");
- return;
- }
-
- // Get current theme styles
- const isDark = document.documentElement.classList.contains("dark");
- const bgColor = isDark ? "#0a0a0a" : "#ffffff";
- const textColor = isDark ? "#e5e7eb" : "#1a1a1a";
- const borderColor = isDark ? "#1f2937" : "#e5e7eb";
- const codeBg = isDark ? "#1a1a1a" : "#f3f4f6";
- const tableHeaderBg = isDark ? "#1f2937" : "#f3f4f6";
-
- printWindow.document.write(`
-
-
-
- Hyper AI Answer
-
-
-
-
+
+
+
+
+
+
+
+
+ `);
+
+ printWindow.document.getElementById("pdf-content")!.textContent = answer;
+ printWindow.document.close();
+}
diff --git a/lib/utils.ts b/lib/utils.ts
new file mode 100644
index 0000000..a5ef193
--- /dev/null
+++ b/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from "clsx";
+import { twMerge } from "tailwind-merge";
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs));
+}
diff --git a/package-lock.json b/package-lock.json
index 25a2a7c..f2dfd36 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,12 +12,14 @@
"@google/genai": "^2.10.0",
"@hookform/resolvers": "^5.4.0",
"@prisma/client": "^7.8.0",
+ "@radix-ui/react-dialog": "^1.1.17",
"@sentry/nextjs": "^10.58.0",
"@upstash/redis": "^1.38.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"framer-motion": "^12.40.0",
+ "geist": "^1.7.2",
"html2pdf.js": "^0.14.0",
"katex": "^0.17.0",
"lucide-react": "^1.20.0",
@@ -35,6 +37,7 @@
"remark-gfm": "^4.0.1",
"remark-math": "^6.0.0",
"resend": "^6.12.4",
+ "sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"zod": "^4.4.3"
},
@@ -1819,6 +1822,522 @@
}
}
},
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.4.tgz",
+ "integrity": "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.17",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.17.tgz",
+ "integrity": "sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.4",
+ "@radix-ui/react-compose-refs": "1.1.3",
+ "@radix-ui/react-context": "1.1.4",
+ "@radix-ui/react-dismissable-layer": "1.1.13",
+ "@radix-ui/react-focus-guards": "1.1.4",
+ "@radix-ui/react-focus-scope": "1.1.10",
+ "@radix-ui/react-id": "1.1.2",
+ "@radix-ui/react-portal": "1.1.12",
+ "@radix-ui/react-presence": "1.1.6",
+ "@radix-ui/react-primitive": "2.1.6",
+ "@radix-ui/react-slot": "1.3.0",
+ "@radix-ui/react-use-controllable-state": "1.2.3",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.7.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz",
+ "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz",
+ "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz",
+ "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.3.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz",
+ "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-controllable-state": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.3.tgz",
+ "integrity": "sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-effect-event": "0.0.3",
+ "@radix-ui/react-use-layout-effect": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-effect-event": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.3.tgz",
+ "integrity": "sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz",
+ "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.13.tgz",
+ "integrity": "sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.4",
+ "@radix-ui/react-compose-refs": "1.1.3",
+ "@radix-ui/react-primitive": "2.1.6",
+ "@radix-ui/react-use-callback-ref": "1.1.2",
+ "@radix-ui/react-use-escape-keydown": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/primitive": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.4.tgz",
+ "integrity": "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz",
+ "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz",
+ "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.3.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-dismissable-layer/node_modules/@radix-ui/react-slot": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz",
+ "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-guards": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.4.tgz",
+ "integrity": "sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.10.tgz",
+ "integrity": "sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.3",
+ "@radix-ui/react-primitive": "2.1.6",
+ "@radix-ui/react-use-callback-ref": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz",
+ "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz",
+ "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.3.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-focus-scope/node_modules/@radix-ui/react-slot": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz",
+ "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.2.tgz",
+ "integrity": "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-id/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz",
+ "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal": {
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.12.tgz",
+ "integrity": "sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-primitive": "2.1.6",
+ "@radix-ui/react-use-layout-effect": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.3.tgz",
+ "integrity": "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-primitive": {
+ "version": "2.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.6.tgz",
+ "integrity": "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-slot": "1.3.0"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-slot": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.0.tgz",
+ "integrity": "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-portal/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz",
+ "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.6.tgz",
+ "integrity": "sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-presence/node_modules/@radix-ui/react-use-layout-effect": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.2.tgz",
+ "integrity": "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-primitive": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
@@ -1885,6 +2404,21 @@
}
}
},
+ "node_modules/@radix-ui/react-use-callback-ref": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.2.tgz",
+ "integrity": "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-controllable-state": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
@@ -1922,6 +2456,24 @@
}
}
},
+ "node_modules/@radix-ui/react-use-escape-keydown": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.2.tgz",
+ "integrity": "sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-callback-ref": "1.1.2"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
@@ -4183,6 +4735,18 @@
"dev": true,
"license": "Python-2.0"
},
+ "node_modules/aria-hidden": {
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/aria-query": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
@@ -5137,6 +5701,12 @@
"node": ">=8"
}
},
+ "node_modules/detect-node-es": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
+ },
"node_modules/devlop": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
@@ -6351,6 +6921,15 @@
"node": ">=18"
}
},
+ "node_modules/geist": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/geist/-/geist-1.7.2.tgz",
+ "integrity": "sha512-Gu5lDFa3pLRyoBlBPf0QIFHVdWAnpco7fS1bJm41jyLPFoguBgiubseUN2oLXMgqZ7uxAxDoXcHMhCY/fOTTgg==",
+ "license": "SIL OPEN FONT LICENSE",
+ "peerDependencies": {
+ "next": ">=13.2.0"
+ }
+ },
"node_modules/generate-function": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
@@ -6404,6 +6983,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/get-nonce": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
+ "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/get-port-please": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz",
@@ -10264,6 +10852,75 @@
"react": ">=18"
}
},
+ "node_modules/react-remove-scroll": {
+ "version": "2.7.2",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
+ "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
+ "tslib": "^2.1.0",
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-remove-scroll-bar": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
+ "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
+ "license": "MIT",
+ "dependencies": {
+ "react-style-singleton": "^2.2.2",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/react-style-singleton": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
+ "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
+ "license": "MIT",
+ "dependencies": {
+ "get-nonce": "^1.0.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/readdirp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
@@ -11036,6 +11693,16 @@
"url": "https://github.com/sponsors/isaacs"
}
},
+ "node_modules/sonner": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
+ "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
@@ -11992,6 +12659,49 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-callback-ref": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
+ "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/use-sidecar": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
+ "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "detect-node-es": "^1.1.0",
+ "tslib": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
+ },
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
diff --git a/package.json b/package.json
index b89b7e5..9e0f4b3 100644
--- a/package.json
+++ b/package.json
@@ -17,12 +17,14 @@
"@google/genai": "^2.10.0",
"@hookform/resolvers": "^5.4.0",
"@prisma/client": "^7.8.0",
+ "@radix-ui/react-dialog": "^1.1.17",
"@sentry/nextjs": "^10.58.0",
"@upstash/redis": "^1.38.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"crypto-js": "^4.2.0",
"framer-motion": "^12.40.0",
+ "geist": "^1.7.2",
"html2pdf.js": "^0.14.0",
"katex": "^0.17.0",
"lucide-react": "^1.20.0",
@@ -40,6 +42,7 @@
"remark-gfm": "^4.0.1",
"remark-math": "^6.0.0",
"resend": "^6.12.4",
+ "sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"zod": "^4.4.3"
},
diff --git a/types/ai.ts b/types/ai.ts
index 6e5ee67..adb7a4f 100644
--- a/types/ai.ts
+++ b/types/ai.ts
@@ -74,6 +74,7 @@ export interface WorkspaceResponse {
answer?: string;
cached?: boolean;
action?: WorkspaceAction;
+ relatedTopics?: string[];
error?: string;
}