6e30a96f6d
CI/CD Pipeline / Build Production Runtime Images (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Failing after 65h49m33s
CI/CD Pipeline / Deploy Staging (push) Failing after 65h51m39s
CI/CD Pipeline / Frontend Lint (push) Failing after 65h53m10s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 65h54m47s
- Remove unused eslint-disable in MainLayout.tsx (react-refresh/only-export-components) - Format client.ts, ClipPropertiesPanel.tsx, TimelinePanel.tsx, EditingPlanner.tsx with prettier
74 lines
2.2 KiB
TypeScript
74 lines
2.2 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;
|