Skip to content

Commit e070d16

Browse files
committed
⭐️ Navigation system
1 parent aa52193 commit e070d16

File tree

17 files changed

+1220
-588
lines changed

17 files changed

+1220
-588
lines changed

frontend/app/[locale]/page.tsx

Lines changed: 15 additions & 240 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,13 @@
22

33
import { useState, useEffect } from "react";
44
import { useTranslation, Trans } from "react-i18next";
5-
import {
6-
Bot,
7-
Globe,
8-
Zap,
9-
MessagesSquare,
10-
Unplug,
11-
TextQuote,
12-
AlertTriangle,
13-
} from "lucide-react";
145
import { Button } from "@/components/ui/button";
15-
import { Card, CardContent } from "@/components/ui/card";
16-
import { Navbar } from "@/components/ui/navbar";
17-
import Link from "next/link";
6+
import { NavigationLayout } from "@/components/navigation/NavigationLayout";
7+
import { HomepageContent } from "@/components/homepage/HomepageContent";
188
import { LoginModal } from "@/components/auth/loginModal";
199
import { RegisterModal } from "@/components/auth/registerModal";
2010
import { useAuth } from "@/hooks/useAuth";
2111
import { Modal, ConfigProvider } from "antd";
22-
import { motion } from "framer-motion";
23-
import { APP_VERSION } from "@/const/constants";
24-
import { FOOTER_CONFIG } from "@/const/layoutConstants";
25-
import { versionService } from "@/services/versionService";
26-
import log from "@/lib/logger";
2712

2813
export default function Home() {
2914
const [mounted, setMounted] = useState(false);
@@ -55,27 +40,10 @@ export default function Home() {
5540
const [loginPromptOpen, setLoginPromptOpen] = useState(false);
5641
const [adminRequiredPromptOpen, setAdminRequiredPromptOpen] =
5742
useState(false);
58-
const [appVersion, setAppVersion] = useState<string>("");
59-
60-
// Get app version on mount
61-
useEffect(() => {
62-
const fetchAppVersion = async () => {
63-
try {
64-
const version = await versionService.getAppVersion();
65-
setAppVersion(version);
66-
} catch (error) {
67-
log.error("Failed to fetch app version:", error);
68-
setAppVersion(APP_VERSION); // Fallback
69-
}
70-
};
71-
72-
fetchAppVersion();
73-
}, []);
7443

7544
// Handle operations that require login
76-
const handleAuthRequired = (e: React.MouseEvent) => {
45+
const handleAuthRequired = () => {
7746
if (!isSpeedMode && !user) {
78-
e.preventDefault();
7947
setLoginPromptOpen(true);
8048
}
8149
};
@@ -98,9 +66,8 @@ export default function Home() {
9866
};
9967

10068
// Handle operations that require admin privileges
101-
const handleAdminRequired = (e: React.MouseEvent) => {
69+
const handleAdminRequired = () => {
10270
if (!isSpeedMode && user?.role !== "admin") {
103-
e.preventDefault();
10471
setAdminRequiredPromptOpen(true);
10572
}
10673
};
@@ -111,183 +78,16 @@ export default function Home() {
11178
};
11279

11380
return (
114-
<div className="min-h-screen flex flex-col bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800">
115-
{/* Top navigation bar */}
116-
<Navbar />
117-
118-
{/* Main content */}
119-
<main className="flex-1 pt-8 pb-8 flex flex-col justify-center my-8">
120-
{/* Hero area */}
121-
<section className="relative w-full py-10 flex flex-col items-center justify-center text-center px-4">
122-
<div className="absolute inset-0 bg-grid-slate-200 dark:bg-grid-slate-800 [mask-image:radial-gradient(ellipse_at_center,white_20%,transparent_75%)] -z-10"></div>
123-
<motion.h2
124-
initial={{ opacity: 0, y: -20 }}
125-
animate={{ opacity: 1, y: 0 }}
126-
transition={{ duration: 0.8, delay: 0.2 }}
127-
className="text-4xl md:text-5xl lg:text-6xl font-bold text-slate-900 dark:text-white mb-4 tracking-tight"
128-
>
129-
{t("page.title")}
130-
<span className="text-blue-600 dark:text-blue-500">
131-
{" "}
132-
{t("page.subtitle")}
133-
</span>
134-
</motion.h2>
135-
<motion.p
136-
initial={{ opacity: 0, y: -20 }}
137-
animate={{ opacity: 1, y: 0 }}
138-
transition={{ duration: 0.8, delay: 0.3 }}
139-
className="max-w-2xl text-slate-600 dark:text-slate-300 text-lg md:text-xl mb-8"
140-
>
141-
{t("page.description")}
142-
</motion.p>
143-
144-
{/* Three parallel buttons */}
145-
<motion.div
146-
initial={{ opacity: 0, y: 20 }}
147-
animate={{ opacity: 1, y: 0 }}
148-
transition={{ duration: 0.8, delay: 0.4 }}
149-
className="flex flex-col sm:flex-row gap-4"
150-
>
151-
<Link href={isSpeedMode || user ? "/chat" : "#"} onClick={handleAuthRequired}>
152-
<Button className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-6 rounded-full text-lg font-medium shadow-lg hover:shadow-xl transition-all duration-300 group">
153-
<Bot className="mr-2 h-5 w-5 group-hover:animate-pulse" />
154-
{t("page.startChat")}
155-
</Button>
156-
</Link>
157-
158-
<Link
159-
href={isSpeedMode || user?.role === "admin" ? "/setup" : "#"}
160-
onClick={handleAdminRequired}
161-
>
162-
<Button className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-6 rounded-full text-lg font-medium shadow-lg hover:shadow-xl transition-all duration-300 group">
163-
<Zap className="mr-2 h-5 w-5 group-hover:animate-pulse" />
164-
{t("page.quickConfig")}
165-
</Button>
166-
</Link>
167-
168-
<Link href={isSpeedMode || user ? "/space" : "#"} onClick={handleAuthRequired}>
169-
<Button className="bg-blue-600 hover:bg-blue-700 text-white px-8 py-6 rounded-full text-lg font-medium shadow-lg hover:shadow-xl transition-all duration-300 group">
170-
<Globe className="mr-2 h-5 w-5 group-hover:animate-pulse" />
171-
{t("page.agentSpace")}
172-
</Button>
173-
</Link>
174-
</motion.div>
175-
176-
{/* Data protection notice - only shown in full version */}
177-
{!isSpeedMode && (
178-
<motion.div
179-
initial={{ opacity: 0, y: 20 }}
180-
animate={{ opacity: 1, y: 0 }}
181-
transition={{ duration: 0.8, delay: 0.5 }}
182-
className="mt-12 flex items-center justify-center gap-2 text-sm text-slate-500 dark:text-slate-400"
183-
>
184-
<AlertTriangle className="h-4 w-4" />
185-
<span>{t("page.dataProtection")}</span>
186-
</motion.div>
187-
)}
188-
</section>
189-
190-
{/* Feature cards */}
191-
<motion.section
192-
initial={{ opacity: 0, y: 30 }}
193-
animate={{ opacity: 1, y: 0 }}
194-
transition={{ duration: 0.8, delay: 0.6 }}
195-
className="max-w-7xl mx-auto px-4 mb-6"
196-
>
197-
<motion.h3
198-
initial={{ opacity: 0, y: -20 }}
199-
animate={{ opacity: 1, y: 0 }}
200-
transition={{ duration: 0.8, delay: 0.7 }}
201-
className="text-2xl font-bold text-slate-900 dark:text-white mb-8 text-center"
202-
>
203-
{t("page.coreFeatures")}
204-
</motion.h3>
205-
<motion.div
206-
initial={{ opacity: 0 }}
207-
animate={{ opacity: 1 }}
208-
transition={{ duration: 0.8, delay: 0.8 }}
209-
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 items-stretch"
210-
>
211-
{(
212-
t("page.features", { returnObjects: true }) as Array<{
213-
title: string;
214-
description: string;
215-
}>
216-
).map((feature, index: number) => {
217-
const icons = [
218-
<Bot key={0} className="h-8 w-8 text-blue-500" />,
219-
<TextQuote key={1} className="h-8 w-8 text-green-500" />,
220-
<Zap key={2} className="h-8 w-8 text-blue-500" />,
221-
<Globe key={3} className="h-8 w-8 text-emerald-500" />,
222-
<Unplug key={4} className="h-8 w-8 text-amber-500" />,
223-
<MessagesSquare
224-
key={5}
225-
className="h-8 w-8 text-purple-500"
226-
/>,
227-
];
228-
229-
return (
230-
<motion.div
231-
key={index}
232-
initial={{ opacity: 0, y: 20 }}
233-
animate={{ opacity: 1, y: 0 }}
234-
transition={{
235-
duration: 0.6,
236-
delay: 0.9 + index * 0.1,
237-
}}
238-
>
239-
<FeatureCard
240-
icon={
241-
icons[index] || (
242-
<Bot className="h-8 w-8 text-blue-500" />
243-
)
244-
}
245-
title={feature.title}
246-
description={feature.description}
247-
/>
248-
</motion.div>
249-
);
250-
})}
251-
</motion.div>
252-
</motion.section>
253-
</main>
254-
255-
{/* Footer */}
256-
<footer
257-
className="w-full py-4 px-4 flex items-center justify-center border-t border-slate-200 dark:border-slate-700 bg-white/80 dark:bg-slate-900/80 backdrop-blur-sm"
258-
style={{ height: FOOTER_CONFIG.HEIGHT }}
259-
>
260-
<div className="max-w-7xl mx-auto w-full">
261-
<div className="flex flex-col md:flex-row justify-between items-center h-full">
262-
<div className="flex items-center gap-8">
263-
<span className="text-sm text-slate-900 dark:text-white">
264-
{t("page.copyright", { year: new Date().getFullYear() })}
265-
<span className="ml-1">· {appVersion || APP_VERSION}</span>
266-
</span>
267-
</div>
268-
<div className="flex items-center gap-6">
269-
<Link
270-
href="https://github.com/nexent-hub/nexent?tab=License-1-ov-file#readme"
271-
className="text-sm text-slate-600 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white"
272-
>
273-
{t("page.termsOfUse")}
274-
</Link>
275-
<Link
276-
href="http://nexent.tech/contact"
277-
className="text-sm text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white transition-colors"
278-
>
279-
{t("page.contactUs")}
280-
</Link>
281-
<Link
282-
href="http://nexent.tech/about"
283-
className="text-sm text-slate-600 dark:text-slate-300 dark:hover:text-white transition-colors"
284-
>
285-
{t("page.aboutUs")}
286-
</Link>
287-
</div>
288-
</div>
289-
</div>
290-
</footer>
81+
<NavigationLayout
82+
onAuthRequired={handleAuthRequired}
83+
onAdminRequired={handleAdminRequired}
84+
showFooter={true}
85+
contentMode="centered"
86+
>
87+
<HomepageContent
88+
onAuthRequired={handleAuthRequired}
89+
onAdminRequired={handleAdminRequired}
90+
/>
29191

29292
{/* Login prompt dialog - only shown in full version */}
29393
{!isSpeedMode && (
@@ -459,32 +259,7 @@ export default function Home() {
459259
</div>
460260
</Modal>
461261
)}
462-
</div>
262+
</NavigationLayout>
463263
);
464264
}
465265
}
466-
467-
// Feature card component
468-
interface FeatureCardProps {
469-
icon: React.ReactNode;
470-
title: string;
471-
description: string;
472-
}
473-
474-
function FeatureCard({ icon, title, description }: FeatureCardProps) {
475-
return (
476-
<Card className="overflow-hidden border border-slate-200 dark:border-slate-700 transition-all duration-300 hover:shadow-md hover:border-blue-200 dark:hover:border-blue-900 group h-full">
477-
<CardContent className="p-6 h-full flex flex-col">
478-
<div className="mb-4 p-3 bg-slate-100 dark:bg-slate-800 rounded-full w-fit group-hover:bg-blue-100 dark:group-hover:bg-blue-900/30 transition-colors">
479-
{icon}
480-
</div>
481-
<h4 className="text-lg font-semibold text-slate-900 dark:text-white mb-2">
482-
{title}
483-
</h4>
484-
<p className="text-slate-600 dark:text-slate-300 flex-grow">
485-
{description}
486-
</p>
487-
</CardContent>
488-
</Card>
489-
);
490-
}

0 commit comments

Comments
 (0)