7ef81079d5
Deploy / Build Production Runtime Images (push) Has been skipped
Deploy / Deploy Production (push) Has been skipped
Deploy / Production Browser E2E (push) Has been skipped
Deploy / Deploy Staging (push) Failing after 207h46m15s
CI/CD Pipeline / Frontend Lint (push) Failing after 207h46m43s
CI/CD Pipeline / Validate Code Quality And Tests (push) Failing after 207h46m52s
- 新增 AppLayout.tsx:语义化布局壳(header + sidebar slot + main content) - 重写 MainLayout.tsx:侧边栏 240px/64px 折叠,SidebarContext 共享状态 - 重写 MainLayout.css:完整响应式布局样式 - 桌面端:侧边栏默认展开 240px - 平板端(769-1024px):侧边栏默认折叠 64px 图标栏 - 移动端(≤768px):侧边栏隐藏,transform 滑入 + 遮罩层 - 所有尺寸/颜色使用 global.css 设计系统变量 - 语义化 HTML:header/aside/main/nav 标签 - 侧边栏/导航具体内容 deferred to Tasks 1.3, 1.4
257 lines
7.2 KiB
CSS
257 lines
7.2 KiB
CSS
/* ============================================================
|
||
MainLayout.css - 主布局样式(Task 1.2)
|
||
|
||
结构:
|
||
.xx-app-shell 全屏 flex 容器
|
||
├── header (xx-top-nav) 顶部导航(Header.tsx 管理)
|
||
└── .xx-app-body 水平 flex 行
|
||
├── .xx-app-sidebar 左侧侧边栏(240px / 64px 折叠)
|
||
└── .xx-app-content 主内容区(自适应)
|
||
|
||
所有尺寸/颜色均使用 global.css 设计系统变量
|
||
============================================================ */
|
||
|
||
/* ── 应用外壳 ─────────────────────────────────────────────── */
|
||
.xx-app-shell {
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 100vh;
|
||
background: var(--bg-secondary);
|
||
color: var(--text-primary);
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* ── 主体区域(侧边栏 + 内容) ────────────────────────────── */
|
||
.xx-app-body {
|
||
display: flex;
|
||
flex: 1;
|
||
min-height: 0; /* 允许子元素收缩,防止溢出 */
|
||
}
|
||
|
||
/* ── 侧边栏 ───────────────────────────────────────────────── */
|
||
.xx-app-sidebar {
|
||
width: 240px;
|
||
flex-shrink: 0;
|
||
background: var(--bg-primary);
|
||
border-right: 1px solid var(--border-color);
|
||
display: flex;
|
||
flex-direction: column;
|
||
transition: width var(--transition-slow);
|
||
overflow: hidden;
|
||
z-index: var(--z-fixed);
|
||
}
|
||
|
||
/* 折叠态 —— 64px 图标栏 */
|
||
.xx-app-sidebar.xx-collapsed {
|
||
width: 64px;
|
||
}
|
||
|
||
/* ── 侧边栏折叠按钮 ───────────────────────────────────────── */
|
||
.xx-sidebar-toggle {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
padding: var(--space-sm) var(--space-md);
|
||
border-bottom: 1px solid var(--border-light);
|
||
height: 48px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.xx-sidebar-toggle button {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--space-sm);
|
||
border: none;
|
||
background: none;
|
||
cursor: pointer;
|
||
color: var(--text-secondary);
|
||
padding: var(--space-xs) var(--space-sm);
|
||
border-radius: var(--radius-xs);
|
||
font-size: var(--font-size-sm);
|
||
font-weight: var(--font-weight-medium);
|
||
transition: var(--transition-colors);
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.xx-sidebar-toggle button:hover {
|
||
color: var(--text-primary);
|
||
background: var(--bg-tertiary);
|
||
}
|
||
|
||
/* 折叠时隐藏文字标签,仅保留图标居中 */
|
||
.xx-app-sidebar.xx-collapsed .xx-sidebar-toggle {
|
||
justify-content: center;
|
||
padding: var(--space-sm) var(--space-xs);
|
||
}
|
||
|
||
.xx-app-sidebar.xx-collapsed .xx-sidebar-toggle-label {
|
||
display: none;
|
||
}
|
||
|
||
/* ── 侧边栏内容区 ─────────────────────────────────────────── */
|
||
.xx-sidebar-content {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
overflow-x: hidden;
|
||
padding: var(--space-sm);
|
||
}
|
||
|
||
/* 占位区域 —— Task 1.3 将替换为实际导航 */
|
||
.xx-sidebar-placeholder {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: var(--space-2xl) var(--space-md);
|
||
color: var(--text-tertiary);
|
||
font-size: var(--font-size-sm);
|
||
text-align: center;
|
||
min-height: 120px;
|
||
border: 1px dashed var(--border-light);
|
||
border-radius: var(--radius-sm);
|
||
margin: var(--space-sm);
|
||
}
|
||
|
||
.xx-sidebar-placeholder::before {
|
||
content: "📋";
|
||
font-size: var(--font-size-3xl);
|
||
margin-bottom: var(--space-sm);
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.xx-sidebar-placeholder::after {
|
||
content: "侧边栏导航区域";
|
||
display: block;
|
||
}
|
||
|
||
/* 折叠时隐藏占位文字 */
|
||
.xx-app-sidebar.xx-collapsed .xx-sidebar-placeholder {
|
||
min-height: 48px;
|
||
padding: var(--space-md) var(--space-xs);
|
||
margin: var(--space-xs);
|
||
}
|
||
|
||
.xx-app-sidebar.xx-collapsed .xx-sidebar-placeholder::before,
|
||
.xx-app-sidebar.xx-collapsed .xx-sidebar-placeholder::after {
|
||
display: none;
|
||
}
|
||
|
||
/* ── 主内容区 ─────────────────────────────────────────────── */
|
||
.xx-app-content {
|
||
flex: 1;
|
||
min-width: 0; /* 防止内容溢出 */
|
||
overflow-y: auto;
|
||
padding: var(--space-lg);
|
||
}
|
||
|
||
/* ── 移动端遮罩层(默认隐藏) ─────────────────────────────── */
|
||
.xx-sidebar-overlay {
|
||
display: none;
|
||
}
|
||
|
||
/* ============================================================
|
||
响应式 —— 平板(769px ~ 1024px)
|
||
侧边栏默认折叠为图标栏
|
||
============================================================ */
|
||
@media (min-width: 769px) and (max-width: 1024px) {
|
||
.xx-app-sidebar {
|
||
width: 64px;
|
||
}
|
||
|
||
.xx-app-sidebar .xx-sidebar-toggle {
|
||
justify-content: center;
|
||
padding: var(--space-sm) var(--space-xs);
|
||
}
|
||
|
||
.xx-app-sidebar .xx-sidebar-toggle-label {
|
||
display: none;
|
||
}
|
||
|
||
.xx-app-sidebar .xx-sidebar-placeholder {
|
||
min-height: 48px;
|
||
padding: var(--space-md) var(--space-xs);
|
||
margin: var(--space-xs);
|
||
}
|
||
|
||
.xx-app-sidebar .xx-sidebar-placeholder::before,
|
||
.xx-app-sidebar .xx-sidebar-placeholder::after {
|
||
display: none;
|
||
}
|
||
|
||
/* 展开态恢复完整宽度 */
|
||
.xx-app-sidebar:not(.xx-collapsed) {
|
||
width: 240px;
|
||
}
|
||
|
||
.xx-app-sidebar:not(.xx-collapsed) .xx-sidebar-toggle {
|
||
justify-content: flex-end;
|
||
padding: var(--space-sm) var(--space-md);
|
||
}
|
||
|
||
.xx-app-sidebar:not(.xx-collapsed) .xx-sidebar-toggle-label {
|
||
display: inline;
|
||
}
|
||
|
||
.xx-app-sidebar:not(.xx-collapsed) .xx-sidebar-placeholder {
|
||
min-height: 120px;
|
||
padding: var(--space-2xl) var(--space-md);
|
||
margin: var(--space-sm);
|
||
}
|
||
|
||
.xx-app-sidebar:not(.xx-collapsed) .xx-sidebar-placeholder::before,
|
||
.xx-app-sidebar:not(.xx-collapsed) .xx-sidebar-placeholder::after {
|
||
display: block;
|
||
}
|
||
}
|
||
|
||
/* ============================================================
|
||
响应式 —— 移动端(≤768px)
|
||
侧边栏隐藏,由 Header 汉堡菜单控制显示
|
||
============================================================ */
|
||
@media (max-width: 768px) {
|
||
.xx-app-sidebar {
|
||
position: fixed;
|
||
top: 56px; /* 移动端 Header 高度 */
|
||
left: 0;
|
||
bottom: 0;
|
||
width: 240px;
|
||
transform: translateX(-100%);
|
||
transition: transform var(--transition-slow);
|
||
box-shadow: none;
|
||
z-index: calc(var(--z-fixed) - 1); /* 低于 Header 的汉堡按钮 */
|
||
}
|
||
|
||
/* 展开态:滑入 */
|
||
.xx-app-sidebar:not(.xx-collapsed) {
|
||
transform: translateX(0);
|
||
box-shadow: var(--shadow-lg);
|
||
}
|
||
|
||
/* 展开时显示遮罩 */
|
||
.xx-app-sidebar:not(.xx-collapsed) ~ .xx-sidebar-overlay,
|
||
.xx-app-sidebar:not(.xx-collapsed) + .xx-app-content::before {
|
||
display: none;
|
||
}
|
||
|
||
/* 遮罩层 —— 使用独立选择器 */
|
||
.xx-sidebar-overlay {
|
||
display: none;
|
||
position: fixed;
|
||
inset: 0;
|
||
background: var(--bg-overlay);
|
||
z-index: calc(var(--z-fixed) - 2);
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* 通过父级控制遮罩显示 */
|
||
.xx-app-body:has(.xx-app-sidebar:not(.xx-collapsed)) > .xx-sidebar-overlay {
|
||
display: block;
|
||
}
|
||
|
||
.xx-app-content {
|
||
padding: var(--space-md);
|
||
}
|
||
}
|