Skip to content

Commit cb7c776

Browse files
authored
⭐️ Agent Space
2 parents 9412414 + aa52193 commit cb7c776

File tree

15 files changed

+1849
-1301
lines changed

15 files changed

+1849
-1301
lines changed

frontend/app/[locale]/chat/components/chatLeftSidebar.tsx

Lines changed: 58 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Box,
1414
Bot,
1515
} from "lucide-react";
16+
import { useRouter } from "next/navigation";
1617

1718
import { Button } from "@/components/ui/button";
1819
import {
@@ -132,7 +133,8 @@ export function ChatSidebar({
132133
userAvatarUrl,
133134
userRole = USER_ROLES.USER,
134135
}: ChatSidebarProps) {
135-
const { t } = useTranslation();
136+
const { t, i18n } = useTranslation();
137+
const router = useRouter();
136138
const { today, week, older } = categorizeDialogs(conversationList);
137139
const [editingId, setEditingId] = useState<number | null>(null);
138140
const [editingTitle, setEditingTitle] = useState("");
@@ -260,10 +262,10 @@ export function ChatSidebar({
260262
<Button
261263
variant="ghost"
262264
size="icon"
263-
className={isCollapsed ? "h-10 w-10 rounded-full hover:bg-slate-100" : "size-10 rounded-full hover:bg-slate-100"}
265+
className="h-10 w-10 rounded-full hover:bg-slate-100"
264266
onClick={settingsMenuItems ? undefined : onSettingsClick}
265267
>
266-
<Settings className={isCollapsed ? "h-6 w-6" : "size-5"} />
268+
<Settings className="h-6 w-6" strokeWidth={2.5} />
267269
</Button>
268270
);
269271

@@ -305,9 +307,7 @@ export function ChatSidebar({
305307
}}
306308
>
307309
<Dropdown menu={menuProps} placement="topRight" trigger={["click"]}>
308-
<div className={isCollapsed ? "flex justify-center" : ""}>
309-
{buttonContent}
310-
</div>
310+
<div>{buttonContent}</div>
311311
</Dropdown>
312312
</ConfigProvider>
313313
</TooltipTrigger>
@@ -324,9 +324,7 @@ export function ChatSidebar({
324324
<TooltipProvider>
325325
<Tooltip>
326326
<TooltipTrigger asChild>
327-
<div className={isCollapsed ? "flex justify-center" : ""}>
328-
{buttonContent}
329-
</div>
327+
<div>{buttonContent}</div>
330328
</TooltipTrigger>
331329
<TooltipContent side={isCollapsed ? "right" : "top"}>
332330
{t("chatLeftSidebar.settings")}
@@ -457,62 +455,60 @@ export function ChatSidebar({
457455
const renderCollapsedSidebar = () => {
458456
return (
459457
<>
460-
{/* Application icon */}
461-
<TooltipProvider>
462-
<Tooltip>
463-
<TooltipTrigger asChild>
464-
<div
465-
className="flex justify-start p-4 cursor-pointer"
466-
onClick={onToggleSidebar}
467-
>
468-
<div className="h-8 w-8 rounded-full overflow-hidden">
469-
<img
470-
src={collapsedAvatarUrl}
471-
alt={appConfig.appName}
472-
className="h-full w-full object-cover"
473-
/>
474-
</div>
475-
</div>
476-
</TooltipTrigger>
477-
<TooltipContent side="right">{appConfig.appName}</TooltipContent>
478-
</Tooltip>
479-
</TooltipProvider>
480-
481-
<div className="flex flex-col flex-1 items-center">
458+
{/* Expand/Collapse button */}
459+
<div className="py-3 flex justify-center">
482460
<TooltipProvider>
483461
<Tooltip>
484462
<TooltipTrigger asChild>
485463
<Button
486464
variant="ghost"
487465
size="icon"
488-
className="h-14 w-14 rounded-full hover:bg-slate-100"
466+
className="h-10 w-10 rounded-full hover:bg-slate-100"
489467
onClick={onToggleSidebar}
490468
>
491-
<ChevronRight
492-
className="h-6 w-6"
493-
style={{ height: "28px", width: "28px" }}
494-
/>
469+
<ChevronRight className="h-6 w-6" strokeWidth={2.5} />
495470
</Button>
496471
</TooltipTrigger>
497472
<TooltipContent side="right">
498473
{t("chatLeftSidebar.expandSidebar")}
499474
</TooltipContent>
500475
</Tooltip>
501476
</TooltipProvider>
477+
</div>
502478

479+
{/* Application icon */}
480+
<div className="py-3 flex justify-center">
481+
<TooltipProvider>
482+
<Tooltip>
483+
<TooltipTrigger asChild>
484+
<div
485+
className="h-8 w-8 rounded-full overflow-hidden cursor-pointer"
486+
onClick={() => router.push(`/${i18n.language}`)}
487+
>
488+
<img
489+
src={collapsedAvatarUrl}
490+
alt={appConfig.appName}
491+
className="h-full w-full object-cover"
492+
/>
493+
</div>
494+
</TooltipTrigger>
495+
<TooltipContent side="right">{appConfig.appName}</TooltipContent>
496+
</Tooltip>
497+
</TooltipProvider>
498+
</div>
499+
500+
{/* New conversation button */}
501+
<div className="py-3 flex justify-center">
503502
<TooltipProvider>
504503
<Tooltip>
505504
<TooltipTrigger asChild>
506505
<Button
507506
variant="ghost"
508507
size="icon"
509-
className="h-14 w-14 rounded-full hover:bg-slate-100"
508+
className="h-10 w-10 rounded-full hover:bg-slate-100"
510509
onClick={onNewConversation}
511510
>
512-
<Plus
513-
className="h-6 w-6"
514-
style={{ height: "20px", width: "20px" }}
515-
/>
511+
<Plus className="h-6 w-6" strokeWidth={2.5} />
516512
</Button>
517513
</TooltipTrigger>
518514
<TooltipContent side="right">
@@ -522,20 +518,23 @@ export function ChatSidebar({
522518
</TooltipProvider>
523519
</div>
524520

525-
{/* Bottom area */}
521+
{/* Spacer */}
522+
<div className="flex-1" />
523+
524+
{/* Bottom area - User avatar */}
526525
{userAuthLoading ? (
527-
<div className="py-2 flex justify-center">
526+
<div className="py-3 flex justify-center">
528527
<div className="h-8 w-8 flex items-center justify-center">
529528
<Spin size="default" />
530529
</div>
531530
</div>
532531
) : !isSpeedMode ? (
533-
<TooltipProvider>
534-
<Tooltip>
535-
<TooltipTrigger asChild>
536-
<div className="py-2 flex justify-center cursor-pointer">
532+
<div className="py-3 flex justify-center">
533+
<TooltipProvider>
534+
<Tooltip>
535+
<TooltipTrigger asChild>
537536
<div
538-
className="h-8 w-8 rounded-full overflow-hidden"
537+
className="h-8 w-8 rounded-full overflow-hidden cursor-pointer"
539538
style={{ backgroundColor: "#f0f2f5" }}
540539
>
541540
{userAvatarUrl ? (
@@ -550,17 +549,19 @@ export function ChatSidebar({
550549
</div>
551550
)}
552551
</div>
553-
</div>
554-
</TooltipTrigger>
555-
{userEmail && (
556-
<TooltipContent side="right">{userEmail}</TooltipContent>
557-
)}
558-
</Tooltip>
559-
</TooltipProvider>
552+
</TooltipTrigger>
553+
{userEmail && (
554+
<TooltipContent side="right">{userEmail}</TooltipContent>
555+
)}
556+
</Tooltip>
557+
</TooltipProvider>
558+
</div>
560559
) : null}
561560

562561
{/* Settings button */}
563-
{renderSettingsButton(true)}
562+
<div className="py-3 flex justify-center">
563+
{renderSettingsButton(true)}
564+
</div>
564565
</>
565566
);
566567
};
@@ -581,7 +582,7 @@ export function ChatSidebar({
581582
<div className="flex items-center p-2">
582583
<div
583584
className="flex-1 min-w-0 flex items-center justify-start cursor-pointer"
584-
onClick={onToggleSidebar}
585+
onClick={() => router.push(`/${i18n.language}`)}
585586
>
586587
<div>{renderAppIcon()}</div>
587588
<h1

frontend/app/[locale]/page.tsx

Lines changed: 30 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,20 @@ import {
1313
} from "lucide-react";
1414
import { Button } from "@/components/ui/button";
1515
import { Card, CardContent } from "@/components/ui/card";
16+
import { Navbar } from "@/components/ui/navbar";
1617
import Link from "next/link";
17-
import { AvatarDropdown } from "@/components/auth/avatarDropdown";
1818
import { LoginModal } from "@/components/auth/loginModal";
1919
import { RegisterModal } from "@/components/auth/registerModal";
2020
import { useAuth } from "@/hooks/useAuth";
21-
import { Modal, ConfigProvider, Dropdown } from "antd";
21+
import { Modal, ConfigProvider } from "antd";
2222
import { motion } from "framer-motion";
23-
import {APP_VERSION, languageOptions } from "@/const/constants";
24-
import { useLanguageSwitch } from "@/lib/language";
25-
import { HEADER_CONFIG, FOOTER_CONFIG } from "@/const/layoutConstants";
26-
import { DownOutlined } from "@ant-design/icons";
23+
import { APP_VERSION } from "@/const/constants";
24+
import { FOOTER_CONFIG } from "@/const/layoutConstants";
2725
import { versionService } from "@/services/versionService";
2826
import log from "@/lib/logger";
2927

3028
export default function Home() {
3129
const [mounted, setMounted] = useState(false);
32-
const { currentLanguage, handleLanguageChange } = useLanguageSwitch();
3330

3431
// Prevent hydration errors
3532
useEffect(() => {
@@ -116,100 +113,7 @@ export default function Home() {
116113
return (
117114
<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">
118115
{/* Top navigation bar */}
119-
<header
120-
className="w-full py-4 px-6 flex items-center justify-between border-b border-slate-200 dark:border-slate-700 bg-white/80 dark:bg-slate-900/80 backdrop-blur-sm fixed top-0 z-10"
121-
style={{ height: HEADER_CONFIG.HEIGHT }}
122-
>
123-
<div className="flex items-center gap-2">
124-
<h1 className="text-xl font-bold text-slate-900 dark:text-white flex items-start">
125-
<img
126-
src="/modelengine-logo2.png"
127-
alt="ModelEngine"
128-
className="h-6"
129-
/>
130-
<span className="text-blue-600 dark:text-blue-500 ml-2">
131-
{t("assistant.name")}
132-
</span>
133-
</h1>
134-
</div>
135-
<div className="hidden md:flex items-center gap-6">
136-
{/* Github button */}
137-
<Link
138-
href="https://github.com/ModelEngine-Group/nexent"
139-
target="_blank"
140-
rel="noopener noreferrer"
141-
className="text-sm font-medium text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white transition-colors flex items-center gap-1"
142-
>
143-
<svg
144-
height="18"
145-
width="18"
146-
viewBox="0 0 16 16"
147-
fill="currentColor"
148-
aria-hidden="true"
149-
>
150-
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82a7.65 7.65 0 0 1 2-.27c.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.19 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path>
151-
</svg>
152-
Github
153-
</Link>
154-
{/* ModelEngine link always visible */}
155-
<Link
156-
href="http://modelengine-ai.net"
157-
className="text-sm font-medium text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white transition-colors"
158-
>
159-
ModelEngine
160-
</Link>
161-
<Dropdown
162-
menu={{
163-
items: languageOptions.map((opt) => ({
164-
key: opt.value,
165-
label: opt.label,
166-
})),
167-
onClick: ({ key }) => handleLanguageChange(key as string),
168-
}}
169-
>
170-
<a className="ant-dropdown-link text-sm font-medium text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white transition-colors flex items-center gap-2 cursor-pointer w-[100px] border-0 shadow-none bg-transparent text-left">
171-
<Globe className="h-4 w-4" />
172-
{languageOptions.find((o) => o.value === currentLanguage)
173-
?.label || currentLanguage}
174-
<DownOutlined className="text-[10px]" />
175-
</a>
176-
</Dropdown>
177-
{/* Login status toggle display - only shown in full version */}
178-
{!isSpeedMode && (
179-
<>
180-
{userLoading ? (
181-
<span className="text-sm font-medium text-slate-600">
182-
{t("common.loading")}...
183-
</span>
184-
) : user ? (
185-
<span className="text-sm font-medium text-slate-600">
186-
{user.email}
187-
</span>
188-
) : null}
189-
<AvatarDropdown />
190-
</>
191-
)}
192-
</div>
193-
{/* Right hamburger button reserved for mobile version */}
194-
<Button variant="ghost" size="icon" className="md:hidden">
195-
<svg
196-
xmlns="http://www.w3.org/2000/svg"
197-
width="24"
198-
height="24"
199-
viewBox="0 0 24 24"
200-
fill="none"
201-
stroke="currentColor"
202-
strokeWidth="2"
203-
strokeLinecap="round"
204-
strokeLinejoin="round"
205-
className="h-6 w-6"
206-
>
207-
<line x1="4" x2="20" y1="12" y2="12" />
208-
<line x1="4" x2="20" y1="6" y2="6" />
209-
<line x1="4" x2="20" y1="18" y2="18" />
210-
</svg>
211-
</Button>
212-
</header>
116+
<Navbar />
213117

214118
{/* Main content */}
215119
<main className="flex-1 pt-8 pb-8 flex flex-col justify-center my-8">
@@ -237,7 +141,7 @@ export default function Home() {
237141
{t("page.description")}
238142
</motion.p>
239143

240-
{/* Two parallel buttons */}
144+
{/* Three parallel buttons */}
241145
<motion.div
242146
initial={{ opacity: 0, y: 20 }}
243147
animate={{ opacity: 1, y: 0 }}
@@ -260,6 +164,13 @@ export default function Home() {
260164
{t("page.quickConfig")}
261165
</Button>
262166
</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>
263174
</motion.div>
264175

265176
{/* Data protection notice - only shown in full version */}
@@ -467,11 +378,25 @@ export default function Home() {
467378
onCancel={handleCloseAdminPrompt}
468379
footer={[
469380
<Button
470-
key="close"
471-
onClick={handleCloseAdminPrompt}
381+
key="register"
382+
variant="link"
383+
onClick={() => {
384+
setAdminRequiredPromptOpen(false);
385+
openRegisterModal();
386+
}}
387+
className="bg-white mr-2"
388+
>
389+
{t("page.loginPrompt.register")}
390+
</Button>,
391+
<Button
392+
key="login"
393+
onClick={() => {
394+
setAdminRequiredPromptOpen(false);
395+
openLoginModal();
396+
}}
472397
className="bg-blue-600 text-white hover:bg-blue-700"
473398
>
474-
{t("page.adminPrompt.close")}
399+
{t("page.loginPrompt.login")}
475400
</Button>,
476401
]}
477402
centered

0 commit comments

Comments
 (0)