Files
xiaoxia-saas/apps/web/src/components/layout/MainLayout.css
T
CI Bot 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
feat(ui): 创建主布局组件 AppLayout
- 新增 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
2026-06-30 21:07:36 +08:00

257 lines
7.2 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ============================================================
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);
}
}