0fcb77b991
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Successful in 1m6s
CI Build & Deploy Pipeline / Build Staging Web Image (push) Successful in 1m49s
CI Build & Deploy Pipeline / Build Production API Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Web Image (push) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (push) Has been skipped
CI Build & Deploy Pipeline / Deploy Production (push) Has been skipped
CI Build & Deploy Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Validate Code Quality And Tests (push) Successful in 3m1s
CI/CD Pipeline / Unit Tests (push) Successful in 3m20s
CI/CD Pipeline / Integration Tests (push) Successful in 1m29s
CI Build & Deploy Pipeline / Build Staging API Image (push) Successful in 7m4s
CI Build & Deploy Pipeline / Build Staging Worker Image (push) Successful in 7m54s
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 45s
CI Build & Deploy Pipeline / Staging E2E Tests (push) Failing after 2m50s
CI Build & Deploy Pipeline / Staging API Integration Tests (push) Successful in 3m28s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
/**
|
||
* MainLayout - 主布局组件(Task 1.2)
|
||
*
|
||
* 三栏布局:左侧侧边栏 + 顶部导航栏 + 主内容区
|
||
* - 侧边栏:240px 固定宽度,可折叠至 64px 图标栏
|
||
* - 顶部导航:复用 Header 组件(68px 固定高度)
|
||
* - 主内容区:自适应填充剩余空间
|
||
* - 响应式:移动端(<768px)隐藏侧边栏
|
||
*
|
||
* 侧边栏/导航具体内容 deferred to Tasks 1.3, 1.4
|
||
*/
|
||
import React, { useState } from "react"
|
||
import { MenuFoldOutlined, MenuUnfoldOutlined } from "@ant-design/icons"
|
||
import AppLayout from "./AppLayout"
|
||
import Sidebar from "./Sidebar"
|
||
import "./MainLayout.css"
|
||
|
||
/** 侧边栏上下文 —— 子组件可读取折叠状态 */
|
||
export interface SidebarContextValue {
|
||
collapsed: boolean
|
||
}
|
||
|
||
// eslint-disable-next-line react-refresh/only-export-components
|
||
export const SidebarContext = React.createContext<SidebarContextValue>({
|
||
collapsed: false,
|
||
})
|
||
|
||
const MainLayout: React.FC = () => {
|
||
// 移动端默认折叠,桌面端默认展开
|
||
const [collapsed, setCollapsed] = useState(() => window.innerWidth <= 768)
|
||
|
||
const sidebar = (
|
||
<>
|
||
{/* 移动端遮罩层 —— 仅在侧边栏展开时由 CSS 显示 */}
|
||
<div className="xx-sidebar-overlay" onClick={() => setCollapsed(true)} aria-hidden="true" />
|
||
|
||
<aside className={`xx-app-sidebar${collapsed ? " xx-collapsed" : ""}`} aria-label="侧边栏">
|
||
<div className="xx-sidebar-toggle">
|
||
<button
|
||
type="button"
|
||
onClick={() => setCollapsed((prev) => !prev)}
|
||
aria-label={collapsed ? "展开侧边栏" : "收起侧边栏"}
|
||
>
|
||
{collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
|
||
<span className="xx-sidebar-toggle-label">{collapsed ? "展开" : "收起"}</span>
|
||
</button>
|
||
</div>
|
||
|
||
{/* 侧边栏导航 */}
|
||
<nav className="xx-sidebar-content" aria-label="侧边栏导航">
|
||
<Sidebar />
|
||
</nav>
|
||
</aside>
|
||
</>
|
||
)
|
||
|
||
return (
|
||
<SidebarContext.Provider value={{ collapsed }}>
|
||
<AppLayout sidebar={sidebar} />
|
||
</SidebarContext.Provider>
|
||
)
|
||
}
|
||
|
||
export default MainLayout
|