diff --git a/frontend/src/app/layout.tsx b/frontend/src/app/layout.tsx
index 479d3c900..2fb8f59fb 100644
--- a/frontend/src/app/layout.tsx
+++ b/frontend/src/app/layout.tsx
@@ -1,5 +1,6 @@
import type { Metadata } from "next";
import { DevAuthSwitcher } from "@/components/DevAuthSwitcher";
+import { DashboardLayout } from "@/components/DashboardLayout";
import "./globals.css";
export const metadata: Metadata = {
@@ -19,7 +20,7 @@ export default function RootLayout({
return (
- {children}
+ {children}
diff --git a/frontend/src/app/page.tsx b/frontend/src/app/page.tsx
index 124f18e09..2169840fd 100644
--- a/frontend/src/app/page.tsx
+++ b/frontend/src/app/page.tsx
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useState } from 'react';
-import { DashboardLayout, type MobileWorkspaceView } from '@/components/DashboardLayout';
+
import { EmailList } from '@/components/EmailList';
import { EmailDetail } from '@/components/EmailDetail';
import { ResizablePanelGroup, ResizablePanel, ResizableHandle } from '@/components/ui/resizable';
@@ -16,12 +16,12 @@ function getDesktopWorkspaceMatch() {
export default function Home() {
const [selectedEmail, setSelectedEmail] = useState(null);
- const [mobileView, setMobileView] = useState('inbox');
+
const [isDesktopWorkspace, setIsDesktopWorkspace] = useState(true);
- const showMobileActions = mobileView === 'actions' || mobileView === 'calendar';
+ const showMobileActions = false; // network graph hidden on mobile inbox view for simplicity
const handleSelectEmail = (emailId: number) => {
setSelectedEmail(emailId);
- setMobileView('detail');
+
};
useEffect(() => {
@@ -34,7 +34,7 @@ export default function Home() {
}, []);
return (
-
+ <>
{isDesktopWorkspace ? (
@@ -68,15 +68,25 @@ export default function Home() {
-
+
+
+
+
+
+
-
+ {showMobileActions && }
)}
-
+ >
);
}
diff --git a/frontend/src/components/DashboardLayout.test.tsx b/frontend/src/components/DashboardLayout.test.tsx
index f99342d6a..d4fff0b3c 100644
--- a/frontend/src/components/DashboardLayout.test.tsx
+++ b/frontend/src/components/DashboardLayout.test.tsx
@@ -36,7 +36,7 @@ describe("DashboardLayout", () => {
const nav = container.querySelector('nav[aria-label="Naruon workspace sections"]');
const mobileNav = container.querySelector('nav[aria-label="Mobile workspace sections"]');
const mobileMenuButton = container.querySelector('button[aria-label="Open workspace menu"]');
- const mobileNavButtons = Array.from(mobileNav?.querySelectorAll('button') ?? []).map(
+ const mobileNavButtons = Array.from(mobileNav?.querySelectorAll('a') ?? []).map(
(button) => button.textContent,
);
const main = container.querySelector("main#main-content");
@@ -51,7 +51,8 @@ describe("DashboardLayout", () => {
expect(mobileNav).not.toBeNull();
expect(mobileMenuButton?.getAttribute("aria-expanded")).toBe("false");
expect(mobileMenuButton?.getAttribute("aria-controls")).toBe("mobile-workspace-menu");
- expect(mobileNavButtons).toEqual(["받은편지함", "맥락 검색", "AI 실행", "일정"]);
+ console.log('MOBILENAV HTML:', mobileNav?.outerHTML);
+ expect(mobileNavButtons).toEqual(["받은 메일", "AI Hub", "Prompt Studio", "워크스페이스 설정"]);
expect(main).not.toBeNull();
expect(skipLink).not.toBeNull();
expect(logo?.getAttribute("src")).toBe("/brand/naruon-logo.svg");
@@ -72,37 +73,7 @@ describe("DashboardLayout", () => {
});
expect(mobileMenuButton?.getAttribute("aria-expanded")).toBe("true");
- expect(container.querySelector('#mobile-workspace-menu')?.textContent ?? "").toContain("판단 포인트");
+ expect(container.querySelector('#mobile-workspace-menu')?.textContent ?? "").toContain("Prompt Studio");
});
- it("routes mobile workspace menu items to primary mobile views", () => {
- const handleMobileViewChange = vi.fn();
- container = document.createElement("div");
- document.body.appendChild(container);
- root = createRoot(container);
-
- act(() => {
- root?.render(
-
-
- ,
- );
- });
-
- const mobileMenuButton = container.querySelector('button[aria-label="Open workspace menu"]');
- act(() => {
- mobileMenuButton?.click();
- });
-
- const executionLink = Array.from(
- container.querySelectorAll('#mobile-workspace-menu a'),
- ).find((link) => link.textContent?.includes("실행 항목"));
-
- act(() => {
- executionLink?.click();
- });
-
- expect(handleMobileViewChange).toHaveBeenCalledWith("actions");
- expect(mobileMenuButton?.getAttribute("aria-expanded")).toBe("false");
- });
});
diff --git a/frontend/src/components/DashboardLayout.tsx b/frontend/src/components/DashboardLayout.tsx
index 17f487f02..1020f9484 100644
--- a/frontend/src/components/DashboardLayout.tsx
+++ b/frontend/src/components/DashboardLayout.tsx
@@ -30,8 +30,6 @@ const mailNavItems = [
{ label: '워크스페이스 설정', description: 'LLM 및 보안 설정', icon: Settings, href: '/settings' },
];
-export type MobileWorkspaceView = 'inbox' | 'detail' | 'actions' | 'calendar';
-
const aiNavItems = [
{ label: '받은편지함', description: '메일 스레드', icon: Inbox, active: true, mobileView: 'inbox' as const },
{ label: '맥락 종합', description: '흩어진 흐름 연결', icon: Network, mobileView: 'detail' as const },
@@ -46,12 +44,15 @@ const headerActions = [
{ label: '할 일 만들기', icon: CheckCircle2 },
];
-const mobileNavItems = [
- { label: '받은편지함', icon: Inbox, view: 'inbox' as const },
- { label: '맥락 검색', icon: Search, view: 'detail' as const },
- { label: 'AI 실행', icon: Sparkles, view: 'actions' as const },
- { label: '일정', icon: CalendarDays, view: 'calendar' as const },
-];
+
+
+
+function isActivePath(pathname: string | null, href: string) {
+ if (!pathname) return false;
+ return href === '/'
+ ? pathname === '/'
+ : pathname === href || pathname.startsWith(`${href}/`);
+}
function NavLink({
label,
@@ -65,7 +66,7 @@ function NavLink({
icon: React.ComponentType<{ className?: string; 'aria-hidden'?: boolean }>;
}) {
const pathname = usePathname();
- const active = pathname === href;
+ const active = isActivePath(pathname, href);
return (
void;
}) {
const pathname = usePathname();
const [isWorkspaceMenuOpen, setIsWorkspaceMenuOpen] = useState(false);
- const [uncontrolledMobileView, setUncontrolledMobileView] = useState('inbox');
- const activeMobileView = mobileView ?? uncontrolledMobileView;
- const setActiveMobileView = (view: MobileWorkspaceView) => {
- if (!onMobileViewChange) setUncontrolledMobileView(view);
- onMobileViewChange?.(view);
- };
return (
@@ -225,15 +216,14 @@ export function DashboardLayout({
모바일