Fix Layout

This commit is contained in:
Thanakarn Klangkasame
2025-10-09 11:03:59 +07:00
parent f8b661b466
commit 515eec2393
2 changed files with 40 additions and 51 deletions

View File

@@ -1,4 +1,3 @@
// File: src/app/component/layout/AppShell.tsx
"use client"; "use client";
import { ReactNode, useMemo, useState } from "react"; import { ReactNode, useMemo, useState } from "react";
@@ -24,11 +23,11 @@ export default function AppShell({user, nav, children}: Props) {
Boolean((item.match && item.match.test(pathname)) || pathname === item.href); Boolean((item.match && item.match.test(pathname)) || pathname === item.href);
return ( return (
<div className="flex min-h-screen bg-gradient-to-b from-neutral-50 to-white text-neutral-900"> <div className="grid min-h-dvh grid-cols-[auto_minmax(0,1fr)] bg-gradient-to-b from-neutral-50 to-white text-neutral-900">
{/* Sidebar (desktop) */} {/* Sidebar (desktop) */}
<aside <aside
className={[ className={[
"hidden md:flex sticky top-0 h-screen flex-col min-h-0 border-r border-neutral-200/70 bg-white/70 backdrop-blur", "hidden md:flex sticky top-0 h-dvh flex-col min-h-0 border-r border-neutral-200/70 bg-white/70 backdrop-blur",
"transition-[width] duration-300 ease-out", "transition-[width] duration-300 ease-out",
sidebarOpen ? "w-72" : "w-20", sidebarOpen ? "w-72" : "w-20",
"shadow-[inset_-1px_0_0_rgba(0,0,0,0.03)]", "shadow-[inset_-1px_0_0_rgba(0,0,0,0.03)]",
@@ -37,8 +36,7 @@ export default function AppShell({user, nav, children}: Props) {
{/* Brand */} {/* Brand */}
<div className="h-16 flex items-center px-4"> <div className="h-16 flex items-center px-4">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<div <div className="h-9 w-9 rounded-2xl bg-neutral-900 text-white grid place-items-center font-semibold shadow-sm">
className="h-9 w-9 rounded-2xl bg-neutral-900 text-white grid place-items-center font-semibold shadow-sm">
E E
</div> </div>
{sidebarOpen && ( {sidebarOpen && (
@@ -62,8 +60,7 @@ export default function AppShell({user, nav, children}: Props) {
].join(" ")} ].join(" ")}
title="Current tenant" title="Current tenant"
> >
<span <span className="inline-block h-2.5 w-2.5 rounded-full bg-emerald-500/90 shadow-[0_0_0_3px_rgba(16,185,129,0.12)]" />
className="inline-block h-2.5 w-2.5 rounded-full bg-emerald-500/90 shadow-[0_0_0_3px_rgba(16,185,129,0.12)]"/>
{sidebarOpen ? ( {sidebarOpen ? (
<span className="truncate text-xs text-neutral-700">{user?.tenantKey ?? "—"}</span> <span className="truncate text-xs text-neutral-700">{user?.tenantKey ?? "—"}</span>
) : ( ) : (
@@ -108,10 +105,10 @@ export default function AppShell({user, nav, children}: Props) {
</aside> </aside>
{/* Main */} {/* Main */}
<div className="flex min-h-screen flex-1 flex-col"> <div className="flex min-h-dvh flex-1 flex-col min-w-0">
{/* Topbar */} {/* Topbar */}
<header className="sticky top-0 z-40 border-b border-neutral-200/70 bg-white/70 backdrop-blur"> <header className="sticky top-0 z-40 border-b border-neutral-200/70 bg-white/70 backdrop-blur">
<div className="mx-auto flex h-16 max-w-screen-2xl items-center justify-between px-4"> <div className="mx-auto flex h-16 w-full max-w-[1280px] items-center justify-between px-4">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<button <button
onClick={() => setSidebarOpen((v) => !v)} onClick={() => setSidebarOpen((v) => !v)}
@@ -129,10 +126,8 @@ export default function AppShell({user, nav, children}: Props) {
</div> </div>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div <div className="flex items-center gap-2 rounded-2xl border border-neutral-200/70 bg-white/70 px-2.5 py-1.5 shadow-sm">
className="flex items-center gap-2 rounded-2xl border border-neutral-200/70 bg-white/70 px-2.5 py-1.5 shadow-sm"> <div className="grid h-7 w-7 place-items-center rounded-xl bg-neutral-900 text-[11px] font-semibold text-white shadow-sm">
<div
className="grid h-7 w-7 place-items-center rounded-xl bg-neutral-900 text-[11px] font-semibold text-white shadow-sm">
{initials} {initials}
</div> </div>
<div className="hidden leading-tight sm:block"> <div className="hidden leading-tight sm:block">
@@ -145,17 +140,15 @@ export default function AppShell({user, nav, children}: Props) {
</header> </header>
{/* Content */} {/* Content */}
<main id="main" className="mx-auto w-full max-w-screen-2xl flex-1 p-4 sm:p-6"> <main id="main" className="mx-auto w-full max-w-[1280px] flex-1 p-4 sm:p-6 min-w-0">
<div <div className="rounded-3xl border border-neutral-200/70 bg-white/80 p-4 shadow-[0_10px_30px_-12px_rgba(0,0,0,0.08)] sm:p-6">
className="rounded-3xl border border-neutral-200/70 bg-white/80 p-4 shadow-[0_10px_30px_-12px_rgba(0,0,0,0.08)] sm:p-6">
{children} {children}
</div> </div>
</main> </main>
{/* Footer */} {/* Footer */}
<footer className="mt-auto border-t border-neutral-200/70 bg-white/60 backdrop-blur"> <footer className="mt-auto border-t border-neutral-200/70 bg-white/60 backdrop-blur">
<div <div className="mx-auto flex h-12 w-full max-w-[1280px] items-center justify-between px-4 text-xs text-neutral-500">
className="mx-auto flex h-12 max-w-screen-2xl items-center justify-between px-4 text-xs text-neutral-500">
<span>© {year} EOP</span> <span>© {year} EOP</span>
<span className="hidden sm:inline">Built for enterprise operations</span> <span className="hidden sm:inline">Built for enterprise operations</span>
</div> </div>

View File

@@ -1,32 +1,28 @@
import type { Metadata } from "next"; import "./globals.css";
import type { Metadata, Viewport } from "next";
import { Geist, Geist_Mono } from "next/font/google"; import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css"; import "./globals.css";
import React from "react";
const geistSans = Geist({ const geistSans = Geist({ subsets: ["latin"], variable: "--font-geist-sans" });
variable: "--font-geist-sans", const geistMono = Geist_Mono({ subsets: ["latin"], variable: "--font-geist-mono" });
subsets: ["latin"],
});
const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Create Next App", title: "Enterprise Orchestration Platform",
description: "Generated by create next app", description: "Enterprise Orchestration Platform",
}; };
export default function RootLayout({ export const viewport: Viewport = {
children, width: "device-width",
}: Readonly<{ initialScale: 1,
children: React.ReactNode; viewportFit: "cover",
}>) { };
export default function RootLayout({ children }: { children: React.ReactNode }) {
return ( return (
<html lang="en"> <html lang="en" className="h-full">
<body {/* ใช้ className ของฟอนต์จริง ไม่ใช่แค่วางเป็น variable */}
className={`${geistSans.variable} ${geistMono.variable} antialiased min-h-screen overflow-x-clip`} <body className={`${geistSans.className} ${geistMono.variable} antialiased min-h-dvh overflow-x-hidden`}>
>
{children} {children}
</body> </body>
</html> </html>