UI/UX enhancements: refined footer layout, dashboard sidebar fixes, header tweaks, and theme alignment
This commit is contained in:
@@ -1,18 +1,15 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { ReactNode, useEffect } from "react"
|
import { ReactNode } from "react"
|
||||||
import { LayoutDashboard, Users, Database, Terminal, Settings, FileText, Tag } from "lucide-react"
|
import { LayoutDashboard, Users, Database, Terminal, Settings, FileText, Tag } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { usePathname } from "next/navigation"
|
import { usePathname } from "next/navigation"
|
||||||
import { Logo } from "@/components/Logo"
|
import { Logo } from "@/components/Logo"
|
||||||
|
import { AdminThemeToggle } from "@/components/AdminThemeToggle"
|
||||||
|
|
||||||
export default function AdminLayout({ children }: { children: ReactNode }) {
|
export default function AdminLayout({ children }: { children: ReactNode }) {
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.documentElement.classList.add('dark');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-screen bg-background overflow-hidden text-foreground selection:bg-[#00F0FF]/20">
|
<div className="flex h-screen bg-background overflow-hidden text-foreground selection:bg-[#00F0FF]/20">
|
||||||
{/* Sidebar */}
|
{/* Sidebar */}
|
||||||
@@ -35,9 +32,16 @@ export default function AdminLayout({ children }: { children: ReactNode }) {
|
|||||||
</aside>
|
</aside>
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
<main className="flex-1 overflow-y-auto bg-background">
|
<div className="flex-1 flex flex-col h-screen overflow-hidden">
|
||||||
{children}
|
{/* Top bar with theme toggle */}
|
||||||
</main>
|
<header className="h-14 border-b border-border bg-background/95 backdrop-blur-md flex items-center justify-between px-6 shrink-0">
|
||||||
|
<p className="text-sm font-bold text-muted-foreground uppercase tracking-widest">PragatiVeer Admin</p>
|
||||||
|
<AdminThemeToggle />
|
||||||
|
</header>
|
||||||
|
<main className="flex-1 overflow-y-auto bg-background">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ export default function AICoachDashboard() {
|
|||||||
{ label: "Mistakes Mastered", value: 38, color: "text-green-400", bg: "bg-green-400/5", border: "border-green-400/20", icon: <CheckCircle2 size={32} /> },
|
{ label: "Mistakes Mastered", value: 38, color: "text-green-400", bg: "bg-green-400/5", border: "border-green-400/20", icon: <CheckCircle2 size={32} /> },
|
||||||
{ label: "AI Sessions", value: 124, color: "text-purple-400", bg: "bg-purple-400/5", border: "border-purple-400/20", icon: <Bot size={32} /> },
|
{ label: "AI Sessions", value: 124, color: "text-purple-400", bg: "bg-purple-400/5", border: "border-purple-400/20", icon: <Bot size={32} /> },
|
||||||
].map((stat) => (
|
].map((stat) => (
|
||||||
<Card key={stat.label} className={`border ${stat.border} ${stat.bg} backdrop-blur-sm shadow-sm hover:shadow-[0_0_20px_rgba(0,240,255,0.2)] transition-all duration-300 transform hover:-translate-y-1 rounded-2xl`}>
|
<Card key={stat.label} className={`border ${stat.border} ${stat.bg} backdrop-blur-sm transition-all duration-300 transform hover:-translate-y-1 rounded-2xl`}>
|
||||||
<CardContent className="p-6 flex flex-col items-center justify-center text-center">
|
<CardContent className="p-6 flex flex-col items-center justify-center text-center">
|
||||||
<div className="text-3xl mb-2 filter drop-shadow-md">{stat.icon}</div>
|
<div className="text-3xl mb-2 filter drop-shadow-md">{stat.icon}</div>
|
||||||
<div className={`text-4xl font-black ${stat.color} leading-none tracking-tight mb-2 filter drop-shadow-sm`}>{stat.value}</div>
|
<div className={`text-4xl font-black ${stat.color} leading-none tracking-tight mb-2 filter drop-shadow-sm`}>{stat.value}</div>
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ export default function CBTPage() {
|
|||||||
type="date"
|
type="date"
|
||||||
value={dateFilter}
|
value={dateFilter}
|
||||||
onChange={(e) => setDateFilter(e.target.value)}
|
onChange={(e) => setDateFilter(e.target.value)}
|
||||||
className="w-full px-4 py-2 bg-background border border-border rounded-xl text-sm focus:ring-2 focus:ring-[#00F0FF] outline-none text-foreground [color-scheme:dark]"
|
className="w-full px-4 py-2 bg-background border border-border rounded-xl text-sm focus:ring-2 focus:ring-[#00F0FF] outline-none text-foreground dark:[color-scheme:dark] [color-scheme:light]"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative w-full sm:w-64">
|
<div className="relative w-full sm:w-64">
|
||||||
@@ -370,7 +370,7 @@ export default function CBTPage() {
|
|||||||
</Button>
|
</Button>
|
||||||
) : isAttempted ? (
|
) : isAttempted ? (
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Link href={`/cbt/${exam.id}/result`} className="flex-1">
|
<Link href={`/dashboard/cbt/history/${attempt.id}`} className="flex-1">
|
||||||
<Button className="w-full gap-2 rounded-xl bg-secondary border border-border text-foreground hover:bg-secondary/80 font-bold">
|
<Button className="w-full gap-2 rounded-xl bg-secondary border border-border text-foreground hover:bg-secondary/80 font-bold">
|
||||||
<PlayCircle size={16} /> Result
|
<PlayCircle size={16} /> Result
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const userInitials = user ? user.name.split(" ").filter(n => /^[a-zA-Z]/.test(n)).slice(0, 2).map(n => n[0]).join("").toUpperCase() : "DS"
|
const userInitials = user ? user.name.split(" ").filter(n => /^[a-zA-Z]/.test(n)).slice(0, 2).map(n => n[0]).join("").toUpperCase() : "DS"
|
||||||
const targetExamLabel = user?.target_exam === "JEE_Main" ? "JEE Main" : user?.target_exam === "JEE_Advanced" ? "JEE Advanced" : user?.target_exam === "NEET" ? "NEET" : "NEET/JEE"
|
const targetExamLabel = user?.target_exam === "JEE_Main" ? "JEE" : user?.target_exam === "JEE_Advanced" ? "JEE Advanced" : user?.target_exam === "NEET" ? "NEET" : "NEET/JEE"
|
||||||
|
|
||||||
// Trial logic removed as requested
|
// Trial logic removed as requested
|
||||||
|
|
||||||
@@ -76,7 +76,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
<div className="px-6 py-5">
|
<div className="px-6 py-5">
|
||||||
<Logo href="/dashboard" className="w-full" imageClassName="object-contain object-left scale-110 origin-left" height={56} />
|
<Logo href="/dashboard" className="w-full" imageClassName="object-contain object-left scale-110 origin-left" height={56} />
|
||||||
</div>
|
</div>
|
||||||
<nav className="flex-1 px-4 space-y-1.5 mt-4 overflow-y-auto">
|
<nav className="flex-1 min-h-0 px-4 pb-16 space-y-1.5 mt-4 overflow-y-auto custom-scrollbar">
|
||||||
{/* <div className="pt-2 pb-2">
|
{/* <div className="pt-2 pb-2">
|
||||||
<p className="px-3 text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-2">
|
<p className="px-3 text-xs font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-2">
|
||||||
<span className="w-1.5 h-1.5 rounded-full bg-white"></span> Free Tier
|
<span className="w-1.5 h-1.5 rounded-full bg-white"></span> Free Tier
|
||||||
@@ -84,10 +84,8 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
</div> */}
|
</div> */}
|
||||||
|
|
||||||
<div className="pt-3 pb-1">
|
<div className="pt-3 pb-1">
|
||||||
<p className="px-3 text-[10px] font-black uppercase tracking-widest text-muted-foreground/60 flex items-center gap-2">
|
<p className="px-4 text-[11px] font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-2">
|
||||||
<span className="flex-1 h-px bg-border/60"></span>
|
<span className="w-1.5 h-1.5 rounded-full bg-yellow-500"></span> Pro Tier
|
||||||
<span className="flex items-center gap-1.5"><span className="w-1.5 h-1.5 rounded-full bg-yellow-500 shadow-[0_0_8px_-2px_rgba(234,179,8,0.8)]"></span>Pro Tier</span>
|
|
||||||
<span className="flex-1 h-px bg-border/60"></span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -131,10 +129,8 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="pt-4 pb-1">
|
<div className="pt-4 pb-1">
|
||||||
<p className="px-3 text-[10px] font-black uppercase tracking-widest text-muted-foreground/60 flex items-center gap-2">
|
<p className="px-4 text-[11px] font-bold uppercase tracking-widest text-muted-foreground flex items-center gap-2">
|
||||||
<span className="flex-1 h-px bg-border/60"></span>
|
<span className="w-1.5 h-1.5 rounded-full bg-cyan-500"></span> AI Coach
|
||||||
<span className="flex items-center gap-1.5"><span className="w-1.5 h-1.5 rounded-full bg-[#00F0FF] shadow-[0_0_8px_-2px_#00F0FF]"></span>AI Coach</span>
|
|
||||||
<span className="flex-1 h-px bg-border/60"></span>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<NavItem
|
<NavItem
|
||||||
@@ -249,7 +245,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
className="w-full flex items-center justify-between p-2 rounded-xl bg-background/50 hover:bg-background transition-colors border border-border/50 shadow-sm mt-3"
|
className="w-full flex items-center justify-between p-2 rounded-xl bg-background/50 hover:bg-background transition-colors border border-border/50 shadow-sm mt-3"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 text-left">
|
<div className="flex items-center gap-3 text-left">
|
||||||
<div className="h-8 w-8 rounded-full bg-[#00F0FF]/25 text-[#00F0FF] flex items-center justify-center font-bold text-sm shadow-[0_0_10px_-2px_#00F0FF] shrink-0">
|
<div className="h-8 w-8 rounded-full bg-cyan-500/20 text-cyan-700 dark:bg-cyan-500/20 dark:text-cyan-400 flex items-center justify-center font-bold text-sm shadow-none dark:shadow-[0_0_10px_-2px_#00F0FF] shrink-0">
|
||||||
{userInitials}
|
{userInitials}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1 min-w-0">
|
<div className="flex-1 min-w-0">
|
||||||
@@ -272,7 +268,7 @@ export default function DashboardLayout({ children }: { children: ReactNode }) {
|
|||||||
{user ? `Welcome back, ${user.name.split(" ")[0]}!` : "Welcome back!"}
|
{user ? `Welcome back, ${user.name.split(" ")[0]}!` : "Welcome back!"}
|
||||||
</h2>
|
</h2>
|
||||||
{user && (
|
{user && (
|
||||||
<Badge variant="outline" className="bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20 font-bold tracking-wide uppercase px-2.5 py-0.5 animate-pulse">
|
<Badge variant="outline" className="bg-cyan-500/10 text-cyan-700 dark:text-cyan-400 border-cyan-500/20 font-bold tracking-wide uppercase px-2.5 py-0.5 animate-pulse shadow-none dark:shadow-[0_0_10px_-2px_#00F0FF]">
|
||||||
{targetExamLabel} Target
|
{targetExamLabel} Target
|
||||||
</Badge>
|
</Badge>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -70,6 +70,17 @@ body {
|
|||||||
@apply antialiased selection:bg-primary/20;
|
@apply antialiased selection:bg-primary/20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ─── Light mode: flatten card shadows so they don't look 3D/lifted ─── */
|
||||||
|
:root:not(.dark) .shadow-sm,
|
||||||
|
:root:not(.dark) .shadow,
|
||||||
|
:root:not(.dark) .shadow-md,
|
||||||
|
:root:not(.dark) .shadow-lg,
|
||||||
|
:root:not(.dark) .shadow-xl,
|
||||||
|
:root:not(.dark) .shadow-2xl,
|
||||||
|
:root:not(.dark) [class*="shadow-"] {
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
@layer utilities {
|
@layer utilities {
|
||||||
.text-balance {
|
.text-balance {
|
||||||
text-wrap: balance;
|
text-wrap: balance;
|
||||||
|
|||||||
@@ -37,14 +37,30 @@ export default function RootLayout({
|
|||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: `
|
__html: `
|
||||||
try {
|
try {
|
||||||
if (window.location.pathname.startsWith('/dashboard') || window.location.pathname.startsWith('/cbt')) {
|
if (window.location.pathname.startsWith('/admin')) {
|
||||||
if (localStorage.getItem('theme') === 'dark' || (!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
// Admin panel: uses its own separate theme key, defaults to dark
|
||||||
document.documentElement.classList.add('dark')
|
const adminTheme = localStorage.getItem('admin-theme');
|
||||||
|
if (adminTheme === 'dark' || !adminTheme) {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.remove('dark')
|
document.documentElement.classList.remove('dark');
|
||||||
|
}
|
||||||
|
} else if (window.location.pathname.startsWith('/dashboard') || window.location.pathname.startsWith('/cbt')) {
|
||||||
|
// Dashboard: uses 'theme' key, defaults to light
|
||||||
|
const theme = localStorage.getItem('theme');
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.add('dark')
|
// Public pages: uses 'theme' key, defaults to light
|
||||||
|
const theme = localStorage.getItem('theme');
|
||||||
|
if (theme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
`,
|
`,
|
||||||
|
|||||||
@@ -8,11 +8,10 @@ import Image from "next/image"
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { motion, useScroll, useTransform, Variants } from "framer-motion"
|
import { motion, useScroll, useTransform, Variants } from "framer-motion"
|
||||||
import { useRef, useEffect } from "react"
|
import { useRef, useEffect } from "react"
|
||||||
|
import { ThemeToggle } from "@/components/ThemeToggle"
|
||||||
|
|
||||||
export default function MarketingPage() {
|
export default function MarketingPage() {
|
||||||
useEffect(() => {
|
|
||||||
document.documentElement.classList.add('dark');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const containerRef = useRef(null)
|
const containerRef = useRef(null)
|
||||||
const { scrollYProgress } = useScroll({
|
const { scrollYProgress } = useScroll({
|
||||||
@@ -82,6 +81,7 @@ export default function MarketingPage() {
|
|||||||
<Link href="/about" className="hover:text-foreground transition-colors">About Us</Link>
|
<Link href="/about" className="hover:text-foreground transition-colors">About Us</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
<ThemeToggle />
|
||||||
<Link href="/login" className="text-sm font-bold hover:text-primary transition-colors hidden sm:block">Log in</Link>
|
<Link href="/login" className="text-sm font-bold hover:text-primary transition-colors hidden sm:block">Log in</Link>
|
||||||
<Link href="/signup">
|
<Link href="/signup">
|
||||||
<Button className="rounded-full font-bold px-6 shadow-[0_0_15px_-5px_var(--color-primary)] hover:shadow-[0_0_25px_-5px_var(--color-primary)] transition-all">Get Started</Button>
|
<Button className="rounded-full font-bold px-6 shadow-[0_0_15px_-5px_var(--color-primary)] hover:shadow-[0_0_25px_-5px_var(--color-primary)] transition-all">Get Started</Button>
|
||||||
@@ -549,66 +549,31 @@ export default function MarketingPage() {
|
|||||||
{/* Global Footer (Static) */}
|
{/* Global Footer (Static) */}
|
||||||
<footer className="relative z-10 bg-background/90 backdrop-blur-md border-t border-border pt-16 pb-8">
|
<footer className="relative z-10 bg-background/90 backdrop-blur-md border-t border-border pt-16 pb-8">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-12 mb-16">
|
<div className="flex flex-col items-center max-w-2xl mx-auto mb-16 space-y-6">
|
||||||
<div className="md:col-span-1 space-y-4">
|
<div className="relative h-24 w-[28rem] mb-2">
|
||||||
<div className="relative h-12 w-64 mb-6">
|
<Image
|
||||||
<Image
|
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg"
|
||||||
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg"
|
alt="PragatiVeer" fill className="object-contain dark:hidden"
|
||||||
alt="PragatiVeer" fill className="object-contain object-left scale-135 origin-left dark:hidden"
|
/>
|
||||||
/>
|
<Image
|
||||||
<Image
|
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_dark_background.svg"
|
||||||
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_dark_background.svg"
|
alt="PragatiVeer" fill className="object-contain hidden dark:block"
|
||||||
alt="PragatiVeer" fill className="object-contain object-left scale-135 origin-left hidden dark:block"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-muted-foreground font-medium leading-relaxed">
|
|
||||||
PragatiVeer is India's AI-powered daily practice platform for JEE and NEET aspirants. It is a product of Gyannetra Pvt Ltd.
|
|
||||||
</p>
|
|
||||||
<div className="flex items-center gap-4 pt-2">
|
|
||||||
{/*
|
|
||||||
<Link href="#" className="text-muted-foreground hover:text-foreground transition-colors">
|
|
||||||
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"></path></svg>
|
|
||||||
</Link>
|
|
||||||
<Link href="#" className="text-muted-foreground hover:text-foreground transition-colors">
|
|
||||||
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path></svg>
|
|
||||||
</Link>
|
|
||||||
<Link href="#" className="text-muted-foreground hover:text-foreground transition-colors">
|
|
||||||
<svg viewBox="0 0 24 24" width="20" height="20" stroke="currentColor" strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z"></path><rect x="2" y="9" width="4" height="12"></rect><circle cx="4" cy="4" r="2"></circle></svg>
|
|
||||||
</Link>
|
|
||||||
*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold mb-6 tracking-tight text-foreground">Product</h4>
|
|
||||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
|
||||||
<li><Link href="#features" className="hover:text-primary transition-colors">Features</Link></li>
|
|
||||||
<li><Link href="#pricing" className="hover:text-primary transition-colors">Pricing</Link></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold mb-6 tracking-tight text-foreground">Company</h4>
|
|
||||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
|
||||||
<li><Link href="/about" className="hover:text-primary transition-colors">About Us</Link></li>
|
|
||||||
<li><Link href="/contact" className="hover:text-primary transition-colors">Contact</Link></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold mb-6 tracking-tight text-foreground">Legal</h4>
|
|
||||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
|
||||||
<li><Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link></li>
|
|
||||||
<li><Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link></li>
|
|
||||||
<li><Link href="/refund" className="hover:text-primary transition-colors">Refund Policy</Link></li>
|
|
||||||
<li><Link href="/cancellation" className="hover:text-primary transition-colors">Cancellation Policy</Link></li>
|
|
||||||
<li><Link href="/disclaimer" className="hover:text-primary transition-colors">Disclaimer</Link></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground font-medium leading-relaxed text-center w-full">
|
||||||
|
PragatiVeer is India's AI-powered daily practice platform for JEE and NEET aspirants. It is a product of Gyannetra Pvt Ltd.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t border-border pt-8 flex flex-col md:flex-row items-center justify-between gap-4">
|
<div className="border-t border-border pt-8 flex flex-col md:flex-row items-center justify-between gap-6">
|
||||||
<p className="text-sm text-muted-foreground font-medium">© {new Date().getFullYear()} PragatiVeer. All rights reserved.</p>
|
<p className="text-sm text-muted-foreground font-medium">© {new Date().getFullYear()} PragatiVeer. All rights reserved.</p>
|
||||||
|
<div className="flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm text-muted-foreground font-medium">
|
||||||
|
<Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link>
|
||||||
|
<Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link>
|
||||||
|
<Link href="/refund" className="hover:text-primary transition-colors">Refund Policy</Link>
|
||||||
|
<Link href="/cancellation" className="hover:text-primary transition-colors">Cancellation Policy</Link>
|
||||||
|
<Link href="/disclaimer" className="hover:text-primary transition-colors">Disclaimer</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export function AITutorChat() {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
className="fixed bottom-6 right-6 h-14 w-14 rounded-full shadow-[0_0_20px_-5px_var(--color-primary)] flex items-center justify-center z-50 bg-[#00F0FF] text-background hover:bg-[#00F0FF]/90 transition-transform hover:scale-105"
|
className="fixed bottom-6 right-6 h-14 w-14 rounded-full flex items-center justify-center z-50 bg-[#00F0FF] text-background hover:bg-[#00F0FF]/90 transition-transform hover:scale-105"
|
||||||
>
|
>
|
||||||
<Bot size={28} />
|
<Bot size={28} />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -68,7 +68,7 @@ export function AITutorChat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className={`fixed right-0 md:right-6 bottom-0 md:bottom-6 border-border bg-background/95 backdrop-blur-xl shadow-2xl z-50 flex flex-col overflow-hidden transition-all duration-300 ease-in-out
|
<Card className={`fixed right-0 md:right-6 bottom-0 md:bottom-6 border-border bg-background/95 backdrop-blur-xl z-50 flex flex-col overflow-hidden transition-all duration-300 ease-in-out
|
||||||
${isExpanded ? 'w-full md:w-[600px] h-full md:h-[80vh] rounded-none md:rounded-2xl' : 'w-full md:w-[400px] h-[600px] rounded-t-2xl md:rounded-2xl'}
|
${isExpanded ? 'w-full md:w-[600px] h-full md:h-[80vh] rounded-none md:rounded-2xl' : 'w-full md:w-[400px] h-[600px] rounded-t-2xl md:rounded-2xl'}
|
||||||
`}>
|
`}>
|
||||||
<CardHeader className="p-4 border-b border-border bg-secondary/30 flex flex-row items-center justify-between space-y-0 shrink-0">
|
<CardHeader className="p-4 border-b border-border bg-secondary/30 flex flex-row items-center justify-between space-y-0 shrink-0">
|
||||||
|
|||||||
44
src/components/AdminThemeToggle.tsx
Normal file
44
src/components/AdminThemeToggle.tsx
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react"
|
||||||
|
import { Moon, Sun } from "lucide-react"
|
||||||
|
|
||||||
|
export function AdminThemeToggle() {
|
||||||
|
const [isDark, setIsDark] = useState(true) // admin defaults to dark
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Admin uses its own separate localStorage key, defaults to dark
|
||||||
|
const savedTheme = localStorage.getItem('admin-theme');
|
||||||
|
if (savedTheme === 'light') {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
setIsDark(false);
|
||||||
|
} else {
|
||||||
|
// Default to dark for admin
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
setIsDark(true);
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const toggleTheme = () => {
|
||||||
|
if (isDark) {
|
||||||
|
document.documentElement.classList.remove('dark')
|
||||||
|
localStorage.setItem('admin-theme', 'light');
|
||||||
|
setIsDark(false)
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.add('dark')
|
||||||
|
localStorage.setItem('admin-theme', 'dark');
|
||||||
|
setIsDark(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={toggleTheme}
|
||||||
|
className="p-2 rounded-xl hover:bg-secondary/80 transition-colors border border-transparent hover:border-border text-muted-foreground hover:text-foreground"
|
||||||
|
aria-label="Toggle Admin Dark Mode"
|
||||||
|
title={isDark ? "Switch to Light Mode" : "Switch to Dark Mode"}
|
||||||
|
>
|
||||||
|
{isDark ? <Sun size={18} /> : <Moon size={18} />}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import Image from "next/image"
|
import Image from "next/image"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
|
import { ThemeToggle } from "@/components/ThemeToggle"
|
||||||
export function PublicLayout({ children }: { children: React.ReactNode }) {
|
export function PublicLayout({ children }: { children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-background text-foreground overflow-x-hidden selection:bg-primary/20 relative">
|
<div className="min-h-screen bg-background text-foreground overflow-x-hidden selection:bg-primary/20 relative">
|
||||||
@@ -24,6 +24,7 @@ export function PublicLayout({ children }: { children: React.ReactNode }) {
|
|||||||
<Link href="/about" className="hover:text-foreground transition-colors">About Us</Link>
|
<Link href="/about" className="hover:text-foreground transition-colors">About Us</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
<ThemeToggle />
|
||||||
<Link href="/login" className="text-sm font-bold hover:text-primary transition-colors hidden sm:block">Log in</Link>
|
<Link href="/login" className="text-sm font-bold hover:text-primary transition-colors hidden sm:block">Log in</Link>
|
||||||
<Link href="/signup">
|
<Link href="/signup">
|
||||||
<Button className="rounded-full font-bold px-6 shadow-[0_0_15px_-5px_var(--color-primary)] hover:shadow-[0_0_25px_-5px_var(--color-primary)] transition-all">Get Started</Button>
|
<Button className="rounded-full font-bold px-6 shadow-[0_0_15px_-5px_var(--color-primary)] hover:shadow-[0_0_25px_-5px_var(--color-primary)] transition-all">Get Started</Button>
|
||||||
@@ -40,56 +41,31 @@ export function PublicLayout({ children }: { children: React.ReactNode }) {
|
|||||||
{/* Global Footer (Static) */}
|
{/* Global Footer (Static) */}
|
||||||
<footer className="relative z-10 bg-background/90 backdrop-blur-md border-t border-border pt-16 pb-8">
|
<footer className="relative z-10 bg-background/90 backdrop-blur-md border-t border-border pt-16 pb-8">
|
||||||
<div className="max-w-7xl mx-auto px-6">
|
<div className="max-w-7xl mx-auto px-6">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-12 mb-16">
|
<div className="flex flex-col items-center max-w-2xl mx-auto mb-16 space-y-6">
|
||||||
<div className="md:col-span-1 space-y-4">
|
<div className="relative h-24 w-[28rem] mb-2">
|
||||||
<div className="relative h-12 w-64 mb-6">
|
<Image
|
||||||
<Image
|
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg"
|
||||||
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_light_background.svg"
|
alt="PragatiVeer" fill className="object-contain dark:hidden"
|
||||||
alt="PragatiVeer" fill className="object-contain object-left scale-135 origin-left dark:hidden"
|
/>
|
||||||
/>
|
<Image
|
||||||
<Image
|
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_dark_background.svg"
|
||||||
src="/PragatiVeer_Logo/SVG_Logos/Rectangular_dark_background.svg"
|
alt="PragatiVeer" fill className="object-contain hidden dark:block"
|
||||||
alt="PragatiVeer" fill className="object-contain object-left scale-135 origin-left hidden dark:block"
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-muted-foreground font-medium leading-relaxed">
|
|
||||||
PragatiVeer is India's AI-powered daily practice platform for JEE and NEET aspirants. It is a product of Gyannetra Pvt Ltd.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold mb-6 tracking-tight text-foreground">Product</h4>
|
|
||||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
|
||||||
<li><Link href="/#features" className="hover:text-primary transition-colors">Features</Link></li>
|
|
||||||
<li><Link href="/#pricing" className="hover:text-primary transition-colors">Pricing</Link></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold mb-6 tracking-tight text-foreground">Company</h4>
|
|
||||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
|
||||||
<li><Link href="/about" className="hover:text-primary transition-colors">About Us</Link></li>
|
|
||||||
<li><Link href="/contact" className="hover:text-primary transition-colors">Contact</Link></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<h4 className="font-bold mb-6 tracking-tight text-foreground">Legal</h4>
|
|
||||||
<ul className="space-y-3 text-sm font-medium text-muted-foreground">
|
|
||||||
<li><Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link></li>
|
|
||||||
<li><Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link></li>
|
|
||||||
<li><Link href="/refund" className="hover:text-primary transition-colors">Refund Policy</Link></li>
|
|
||||||
<li><Link href="/cancellation" className="hover:text-primary transition-colors">Cancellation Policy</Link></li>
|
|
||||||
<li><Link href="/disclaimer" className="hover:text-primary transition-colors">Disclaimer</Link></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p className="text-sm text-muted-foreground font-medium leading-relaxed text-center w-full">
|
||||||
|
PragatiVeer is India's AI-powered daily practice platform for JEE and NEET aspirants. It is a product of Gyannetra Pvt Ltd.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="border-t border-border pt-8 flex flex-col md:flex-row items-center justify-between gap-4">
|
<div className="border-t border-border pt-8 flex flex-col md:flex-row items-center justify-between gap-6">
|
||||||
<p className="text-sm text-muted-foreground font-medium">© {new Date().getFullYear()} PragatiVeer. All rights reserved.</p>
|
<p className="text-sm text-muted-foreground font-medium">© {new Date().getFullYear()} PragatiVeer. All rights reserved.</p>
|
||||||
{/* <div className="flex items-center gap-2 text-sm text-muted-foreground font-medium">
|
<div className="flex flex-wrap items-center justify-center gap-x-6 gap-y-2 text-sm text-muted-foreground font-medium">
|
||||||
Made with <div className="size-2 rounded-full bg-primary animate-pulse"></div> by AI Agents
|
<Link href="/terms" className="hover:text-primary transition-colors">Terms & Conditions</Link>
|
||||||
</div> */}
|
<Link href="/privacy" className="hover:text-primary transition-colors">Privacy Policy</Link>
|
||||||
|
<Link href="/refund" className="hover:text-primary transition-colors">Refund Policy</Link>
|
||||||
|
<Link href="/cancellation" className="hover:text-primary transition-colors">Cancellation Policy</Link>
|
||||||
|
<Link href="/disclaimer" className="hover:text-primary transition-colors">Disclaimer</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ export function ThemeToggle() {
|
|||||||
const [isDark, setIsDark] = useState(false)
|
const [isDark, setIsDark] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
// Default is light; only go dark if explicitly saved as 'dark'
|
||||||
const savedTheme = localStorage.getItem('theme');
|
const savedTheme = localStorage.getItem('theme');
|
||||||
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
|
if (savedTheme === 'dark') {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
setIsDark(true);
|
setIsDark(true);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export function TierBadge({ tier }: TierBadgeProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge className="text-xs font-semibold uppercase tracking-wider bg-[#00F0FF]/10 text-[#00F0FF] border-[#00F0FF]/20 hover:bg-[#00F0FF]/20 transition-colors shadow-[0_0_10px_-2px_#00F0FF]">
|
<Badge className="text-xs font-semibold uppercase tracking-wider bg-cyan-500/10 text-cyan-700 dark:text-cyan-400 border-cyan-500/20 hover:bg-cyan-500/20 transition-colors shadow-none dark:shadow-[0_0_10px_-2px_#00F0FF]">
|
||||||
AI Coach
|
AI Coach
|
||||||
</Badge>
|
</Badge>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
|
|||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-2xl border border-border bg-background text-foreground shadow-sm transition-all duration-300 hover:shadow-md",
|
"rounded-2xl border border-border bg-background text-foreground transition-all duration-300",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
Reference in New Issue
Block a user