@coffic/cosy-ui 0.8.10 → 0.8.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/app.css +1 -1
  2. package/dist/src-astro/alert/index.ts +7 -15
  3. package/dist/src-astro/assets/iconData.ts +100 -0
  4. package/dist/src-astro/button/index_astro.ts +2 -56
  5. package/dist/src-astro/card/CardCourse.astro +31 -11
  6. package/dist/src-astro/card/index.ts +15 -25
  7. package/dist/src-astro/code-container/CodeContainer.astro +205 -5
  8. package/dist/src-astro/code-container/index.ts +9 -13
  9. package/dist/src-astro/contact/index.ts +16 -20
  10. package/dist/src-astro/errors/index.ts +0 -62
  11. package/dist/src-astro/footer/index.ts +1 -30
  12. package/dist/src-astro/header/Header.astro +1 -2
  13. package/dist/src-astro/header/index.ts +1 -40
  14. package/dist/src-astro/hero/index.ts +1 -39
  15. package/dist/src-astro/icons/ChartIcon.astro +28 -0
  16. package/dist/src-astro/icons/DashboardIcon.astro +28 -0
  17. package/dist/src-astro/icons/DeleteIcon.astro +28 -0
  18. package/dist/src-astro/icons/DocumentIcon.astro +28 -0
  19. package/dist/src-astro/icons/DownloadIcon.astro +28 -0
  20. package/dist/src-astro/icons/EditIcon.astro +28 -0
  21. package/dist/src-astro/icons/FolderIcon.astro +28 -0
  22. package/dist/src-astro/icons/HeartIcon.astro +28 -0
  23. package/dist/src-astro/icons/HomeIcon.astro +28 -0
  24. package/dist/src-astro/icons/MailIcon.astro +28 -0
  25. package/dist/src-astro/icons/MessageIcon.astro +28 -0
  26. package/dist/src-astro/icons/NotificationIcon.astro +28 -0
  27. package/dist/src-astro/icons/ReportIcon.astro +28 -0
  28. package/dist/src-astro/icons/SaveIcon.astro +28 -0
  29. package/dist/src-astro/icons/SecurityIcon.astro +28 -0
  30. package/dist/src-astro/icons/StarIcon.astro +28 -0
  31. package/dist/src-astro/icons/ToolsIcon.astro +28 -0
  32. package/dist/src-astro/icons/UploadIcon.astro +28 -0
  33. package/dist/src-astro/icons/UsersIcon.astro +28 -0
  34. package/dist/src-astro/icons/WalletIcon.astro +28 -0
  35. package/dist/src-astro/icons/index.ts +20 -0
  36. package/dist/src-astro/layout-app/index.ts +5 -9
  37. package/dist/src-astro/layout-dashboard/DashboardLayout.astro +101 -555
  38. package/dist/src-astro/layout-dashboard/DashboardSidebar.astro +206 -0
  39. package/dist/src-astro/layout-dashboard/DashboardTopNavbar.astro +132 -0
  40. package/dist/src-astro/layout-dashboard/index.ts +14 -8
  41. package/dist/src-astro/layout-dashboard/tools.ts +0 -0
  42. package/dist/src-astro/layout-dashboard/types.ts +313 -0
  43. package/package.json +1 -1
  44. package/dist/src-astro/alert/EAlertBasic.astro +0 -11
  45. package/dist/src-astro/alert/EAlertBasicContainer.astro +0 -11
  46. package/dist/src-astro/alert/EAlertCustomStyle.astro +0 -16
  47. package/dist/src-astro/alert/EAlertCustomStyleContainer.astro +0 -11
  48. package/dist/src-astro/alert/EAlertError.astro +0 -6
  49. package/dist/src-astro/alert/EAlertInfo.astro +0 -6
  50. package/dist/src-astro/alert/EAlertSuccess.astro +0 -6
  51. package/dist/src-astro/alert/EAlertTypesContainer.astro +0 -43
  52. package/dist/src-astro/alert/EAlertWarning.astro +0 -6
  53. package/dist/src-astro/alert/EAlertWithTitle.astro +0 -12
  54. package/dist/src-astro/alert/EAlertWithTitleContainer.astro +0 -11
  55. package/dist/src-astro/button/ButtonBasic.astro +0 -18
  56. package/dist/src-astro/button/ButtonBasicContainer.astro +0 -11
  57. package/dist/src-astro/button/ButtonBlock.astro +0 -5
  58. package/dist/src-astro/button/ButtonError.astro +0 -5
  59. package/dist/src-astro/button/ButtonGhost.astro +0 -5
  60. package/dist/src-astro/button/ButtonIconBoth.astro +0 -9
  61. package/dist/src-astro/button/ButtonIconLeft.astro +0 -8
  62. package/dist/src-astro/button/ButtonIconRight.astro +0 -8
  63. package/dist/src-astro/button/ButtonInfo.astro +0 -5
  64. package/dist/src-astro/button/ButtonLinkContainer.astro +0 -19
  65. package/dist/src-astro/button/ButtonNeutral.astro +0 -5
  66. package/dist/src-astro/button/ButtonOutline.astro +0 -5
  67. package/dist/src-astro/button/ButtonShapeCircle.astro +0 -5
  68. package/dist/src-astro/button/ButtonShapeDefault.astro +0 -5
  69. package/dist/src-astro/button/ButtonShapeSquare.astro +0 -5
  70. package/dist/src-astro/button/ButtonShapes.astro +0 -23
  71. package/dist/src-astro/button/ButtonShapesContainer.astro +0 -29
  72. package/dist/src-astro/button/ButtonSizes.astro +0 -15
  73. package/dist/src-astro/button/ButtonSizesContainer.astro +0 -11
  74. package/dist/src-astro/button/ButtonStates.astro +0 -12
  75. package/dist/src-astro/button/ButtonStatesContainer.astro +0 -11
  76. package/dist/src-astro/button/ButtonSuccess.astro +0 -5
  77. package/dist/src-astro/button/ButtonVariantsContainer.astro +0 -73
  78. package/dist/src-astro/button/ButtonWarning.astro +0 -5
  79. package/dist/src-astro/button/ButtonWide.astro +0 -5
  80. package/dist/src-astro/button/ButtonWidth.astro +0 -8
  81. package/dist/src-astro/button/ButtonWidthContainer.astro +0 -19
  82. package/dist/src-astro/button/ButtonWithIcons.astro +0 -25
  83. package/dist/src-astro/button/ButtonWithIconsContainer.astro +0 -29
  84. package/dist/src-astro/card/CardBasic.astro +0 -5
  85. package/dist/src-astro/card/ECardBasic.astro +0 -13
  86. package/dist/src-astro/card/ECardBasicContainer.astro +0 -11
  87. package/dist/src-astro/card/ECardClickable.astro +0 -16
  88. package/dist/src-astro/card/ECardClickableContainer.astro +0 -11
  89. package/dist/src-astro/card/ECardCompact.astro +0 -13
  90. package/dist/src-astro/card/ECardCompactContainer.astro +0 -11
  91. package/dist/src-astro/card/ECardCustomStyle.astro +0 -17
  92. package/dist/src-astro/card/ECardCustomStyleContainer.astro +0 -11
  93. package/dist/src-astro/card/ECardWithImage.astro +0 -16
  94. package/dist/src-astro/card/ECardWithImageContainer.astro +0 -11
  95. package/dist/src-astro/card/ECardWithSubtitle.astro +0 -13
  96. package/dist/src-astro/card/ECardWithSubtitleContainer.astro +0 -11
  97. package/dist/src-astro/code-container/ECodeContainerBasic.astro +0 -19
  98. package/dist/src-astro/code-container/ECodeContainerMultiple.astro +0 -49
  99. package/dist/src-astro/contact/EContactBasic.astro +0 -15
  100. package/dist/src-astro/contact/EContactBasicContainer.astro +0 -11
  101. package/dist/src-astro/contact/EContactCompact.astro +0 -11
  102. package/dist/src-astro/contact/EContactCompactContainer.astro +0 -11
  103. package/dist/src-astro/contact/EContactCustomStyle.astro +0 -21
  104. package/dist/src-astro/contact/EContactCustomStyleContainer.astro +0 -11
  105. package/dist/src-astro/contact/EContactSocial.astro +0 -20
  106. package/dist/src-astro/contact/EContactSocialContainer.astro +0 -11
  107. package/dist/src-astro/contact/EContactWithTitle.astro +0 -17
  108. package/dist/src-astro/contact/EContactWithTitleContainer.astro +0 -11
  109. package/dist/src-astro/errors/E403Basic.astro +0 -11
  110. package/dist/src-astro/errors/E403BasicContainer.astro +0 -20
  111. package/dist/src-astro/errors/E404Basic.astro +0 -11
  112. package/dist/src-astro/errors/E404BasicContainer.astro +0 -20
  113. package/dist/src-astro/errors/E404WithDebug.astro +0 -18
  114. package/dist/src-astro/errors/E500Basic.astro +0 -11
  115. package/dist/src-astro/errors/E500BasicContainer.astro +0 -20
  116. package/dist/src-astro/errors/E503Maintenance.astro +0 -20
  117. package/dist/src-astro/errors/E503MaintenanceContainer.astro +0 -21
  118. package/dist/src-astro/errors/EErrorPageCustomStyle.astro +0 -21
  119. package/dist/src-astro/errors/EErrorPageCustomStyleContainer.astro +0 -21
  120. package/dist/src-astro/errors/EErrorPageShowcase.astro +0 -68
  121. package/dist/src-astro/errors/EErrorPageShowcaseContainer.astro +0 -21
  122. package/dist/src-astro/footer/EFooterBasic.astro +0 -18
  123. package/dist/src-astro/footer/EFooterBasicContainer.astro +0 -11
  124. package/dist/src-astro/footer/EFooterComplete.astro +0 -50
  125. package/dist/src-astro/footer/EFooterCompleteContainer.astro +0 -11
  126. package/dist/src-astro/footer/EFooterFeaturesContainer.astro +0 -40
  127. package/dist/src-astro/footer/EFooterWithLogo.astro +0 -28
  128. package/dist/src-astro/footer/EFooterWithLogoContainer.astro +0 -11
  129. package/dist/src-astro/footer/EFooterWithNavigation.astro +0 -24
  130. package/dist/src-astro/footer/EFooterWithNavigationContainer.astro +0 -11
  131. package/dist/src-astro/footer/EFooterWithProducts.astro +0 -24
  132. package/dist/src-astro/footer/EFooterWithProductsContainer.astro +0 -11
  133. package/dist/src-astro/footer/EFooterWithSocial.astro +0 -24
  134. package/dist/src-astro/footer/EFooterWithSocialContainer.astro +0 -11
  135. package/dist/src-astro/header/HeaderBasic.astro +0 -19
  136. package/dist/src-astro/header/HeaderCustomNavbarCenter.astro +0 -28
  137. package/dist/src-astro/header/HeaderCustomNavbarEnd.astro +0 -25
  138. package/dist/src-astro/header/HeaderCustomNavbarStart.astro +0 -27
  139. package/dist/src-astro/header/HeaderCustomPosition.astro +0 -34
  140. package/dist/src-astro/header/HeaderWithNavigation.astro +0 -27
  141. package/dist/src-astro/hero/EHeroAlignCenter.astro +0 -13
  142. package/dist/src-astro/hero/EHeroAlignContainer.astro +0 -27
  143. package/dist/src-astro/hero/EHeroAlignLeft.astro +0 -13
  144. package/dist/src-astro/hero/EHeroAlignRight.astro +0 -13
  145. package/dist/src-astro/hero/EHeroBackgroundContainer.astro +0 -18
  146. package/dist/src-astro/hero/EHeroBackgroundImage.astro +0 -16
  147. package/dist/src-astro/hero/EHeroBackgroundImageContainer.astro +0 -11
  148. package/dist/src-astro/hero/EHeroBasic.astro +0 -12
  149. package/dist/src-astro/hero/EHeroBasicContainer.astro +0 -11
  150. package/dist/src-astro/hero/EHeroGradientBackground.astro +0 -10
  151. package/dist/src-astro/hero/EHeroPlainBackground.astro +0 -10
  152. package/dist/src-astro/hero/EHeroWithButton.astro +0 -14
  153. package/dist/src-astro/hero/EHeroWithButtonContainer.astro +0 -11
  154. package/dist/src-astro/hero/EHeroWithImage.astro +0 -16
  155. package/dist/src-astro/hero/EHeroWithImageContainer.astro +0 -11
  156. package/dist/src-astro/layout-app/AppLayoutBasic.astro +0 -54
  157. package/dist/src-astro/layout-dashboard/DashboardLayoutBasic.astro +0 -51
@@ -13,15 +13,16 @@
13
13
  * 3. 可定制性 - 支持自定义导航项、系统名称和用户信息
14
14
  * 4. 状态保持 - 记住用户的侧边栏折叠状态
15
15
  *
16
- * @example
16
+ * @usage
17
17
  * ```astro
18
18
  * ---
19
- * import DashboardLayout from '../layouts/DashboardLayout.astro';
19
+ * import { DashboardLayout } from '@coffic/cosy-ui';
20
20
  *
21
21
  * const navItems = [
22
- * { href: "/dashboard", icon: "home", text: "仪表盘" },
23
- * { href: "/dashboard/users", icon: "user", text: "用户管理" },
24
- * { href: "/dashboard/settings", icon: "settings", text: "系统设置" }
22
+ * { href: "/dashboard", text: "仪表盘" }, // 自动匹配 dashboard 图标
23
+ * { href: "/dashboard/users", text: "用户管理" }, // 自动匹配 users 图标
24
+ * { href: "/dashboard/settings", text: "系统设置" }, // 自动匹配 settings 图标
25
+ * { href: "/dashboard/reports", icon: "chart", text: "报表" } // 手动指定图标
25
26
  * ];
26
27
  * ---
27
28
  *
@@ -29,23 +30,43 @@
29
30
  * title="管理后台"
30
31
  * navItems={navItems}
31
32
  * userName="管理员"
33
+ * sidebarSize="lg"
32
34
  * >
33
35
  * <h1>仪表盘内容</h1>
34
36
  * <p>这是仪表盘的主要内容</p>
35
37
  * </DashboardLayout>
36
38
  * ```
39
+ *
40
+ * @props
41
+ * - title: string - 页面标题
42
+ * - description?: string - 页面描述
43
+ * - systemName?: string - 系统名称,默认为"管理系统"
44
+ * - navItems: NavItem[] - 导航项目
45
+ * - userName?: string - 用户名
46
+ * - userAvatar?: string - 用户头像
47
+ * - sidebarCollapsed?: boolean - 是否折叠侧边栏,默认为false
48
+ * - sidebarSize?: 'sm' | 'md' | 'lg' | 'xl' - 侧边栏尺寸,默认为"md"
49
+ * - sidebarTheme?: SidebarTheme - 侧边栏主题,默认为"default"
50
+ * - contentTheme?: ContentTheme - 内容区域主题,默认为"card"
51
+ * - head?: astroHTML.JSX.Element - 自定义头部内容
52
+ * - class?: string - 页面类名
53
+ * - class:list?: any - 类名列表
54
+ *
55
+ * @slots
56
+ * - default - 主要内容区域
37
57
  */
38
58
 
39
59
  import { BaseLayout } from '../../index-astro';
60
+ import DashboardSidebar from './DashboardSidebar.astro';
61
+ import DashboardTopNavbar from './DashboardTopNavbar.astro';
40
62
  import '../../style.ts';
41
-
42
- export interface NavItem {
43
- href: string;
44
- icon: string;
45
- text: string;
46
- badge?: string | number;
47
- items?: NavItem[];
48
- }
63
+ import {
64
+ type NavItem,
65
+ type SidebarSize,
66
+ type SidebarTheme,
67
+ type ContentTheme,
68
+ getContentTheme,
69
+ } from './types';
49
70
 
50
71
  export interface Props {
51
72
  /**
@@ -85,6 +106,24 @@ export interface Props {
85
106
  */
86
107
  sidebarCollapsed?: boolean;
87
108
 
109
+ /**
110
+ * 侧边栏尺寸
111
+ * @default "md"
112
+ */
113
+ sidebarSize?: SidebarSize;
114
+
115
+ /**
116
+ * 侧边栏主题
117
+ * @default "default"
118
+ */
119
+ sidebarTheme?: SidebarTheme;
120
+
121
+ /**
122
+ * 内容区域主题
123
+ * @default "card"
124
+ */
125
+ contentTheme?: ContentTheme;
126
+
88
127
  /**
89
128
  * 自定义头部内容
90
129
  */
@@ -109,6 +148,9 @@ const {
109
148
  userName,
110
149
  userAvatar,
111
150
  sidebarCollapsed = false,
151
+ sidebarSize = 'md',
152
+ sidebarTheme = 'default',
153
+ contentTheme = 'card',
112
154
  head,
113
155
  class: className,
114
156
  'class:list': classList,
@@ -116,23 +158,7 @@ const {
116
158
  } = Astro.props;
117
159
 
118
160
  const currentPath = Astro.url.pathname;
119
-
120
- // 图标映射
121
- const iconMap: Record<string, string> = {
122
- home: '🏠',
123
- user: '👤',
124
- users: '👥',
125
- settings: '⚙️',
126
- chart: '📊',
127
- document: '📄',
128
- calendar: '📅',
129
- notification: '🔔',
130
- message: '💬',
131
- search: '🔍',
132
- star: '⭐',
133
- heart: '❤️',
134
- menu: '☰',
135
- };
161
+ const contentStyles = getContentTheme(contentTheme);
136
162
  ---
137
163
 
138
164
  <BaseLayout
@@ -142,545 +168,65 @@ const iconMap: Record<string, string> = {
142
168
  keywords=""
143
169
  author=""
144
170
  robots=""
145
- class="dashboard-layout"
171
+ class:list={['cosy:min-h-screen cosy:bg-base-200', className, classList]}
146
172
  {...rest}>
147
- <div class:list={['dashboard-container', { collapsed: sidebarCollapsed }]}>
148
- <!-- 侧边栏 -->
149
- <aside class="sidebar">
150
- <div class="sidebar-header">
151
- <a href="/dashboard" class="logo">
152
- <span class="logo-icon">⚡</span>
153
- <span class="logo-text">{systemName}</span>
154
- </a>
155
- <button class="collapse-button" id="collapse-sidebar">
156
- <span class="collapse-icon">{iconMap.menu}</span>
157
- </button>
158
- </div>
159
-
160
- <nav class="sidebar-nav">
161
- <ul class="nav-list">
162
- {
163
- navItems.map((item: NavItem) => {
164
- const isActive =
165
- currentPath === item.href ||
166
- (item.items &&
167
- item.items.some(
168
- (subitem: NavItem) => currentPath === subitem.href
169
- ));
173
+ <div class:list={['cosy:drawer', { 'cosy:drawer-open': !sidebarCollapsed }]}>
174
+ <input id="dashboard-drawer" type="checkbox" class="cosy:drawer-toggle" />
170
175
 
171
- return (
172
- <li class:list={['nav-item', { active: isActive }]}>
173
- <a href={item.href} class="nav-link">
174
- <span class="nav-icon">{iconMap[item.icon] || '📁'}</span>
175
- <span class="nav-text">{item.text}</span>
176
- {item.badge && <span class="nav-badge">{item.badge}</span>}
177
- </a>
178
-
179
- {item.items && (
180
- <ul class="subnav-list">
181
- {item.items.map((subitem: NavItem) => {
182
- const isSubActive = currentPath === subitem.href;
183
- return (
184
- <li
185
- class:list={[
186
- 'subnav-item',
187
- { active: isSubActive },
188
- ]}>
189
- <a href={subitem.href} class="subnav-link">
190
- <span class="subnav-icon">
191
- {iconMap[subitem.icon] || '📄'}
192
- </span>
193
- <span class="subnav-text">{subitem.text}</span>
194
- {subitem.badge && (
195
- <span class="subnav-badge">
196
- {subitem.badge}
197
- </span>
198
- )}
199
- </a>
200
- </li>
201
- );
202
- })}
203
- </ul>
204
- )}
205
- </li>
206
- );
207
- })
208
- }
209
- </ul>
210
- </nav>
211
- </aside>
176
+ <!-- 侧边栏 -->
177
+ <div class="cosy:drawer-side">
178
+ <label
179
+ for="dashboard-drawer"
180
+ aria-label="close sidebar"
181
+ class="cosy:drawer-overlay"></label>
182
+ <DashboardSidebar
183
+ systemName={systemName}
184
+ navItems={navItems}
185
+ currentPath={currentPath}
186
+ size={sidebarSize}
187
+ theme={sidebarTheme}
188
+ />
189
+ </div>
212
190
 
213
191
  <!-- 主内容区 -->
214
- <div class="main-content">
192
+ <div class="cosy:drawer-content cosy:flex cosy:flex-col">
215
193
  <!-- 顶部导航栏 -->
216
- <header class="top-navbar">
217
- <div class="navbar-left">
218
- <button class="menu-button" id="toggle-sidebar">
219
- <span class="menu-icon">{iconMap.menu}</span>
220
- </button>
221
-
222
- <div class="breadcrumb">
223
- <span class="breadcrumb-item">{title}</span>
224
- </div>
225
- </div>
226
-
227
- <div class="navbar-right">
228
- <div class="search-box">
229
- <input type="text" placeholder="搜索..." class="search-input" />
230
- <span class="search-icon">{iconMap.search}</span>
231
- </div>
232
-
233
- <button class="notification-button">
234
- <span class="notification-icon">{iconMap.notification}</span>
235
- <span class="notification-badge">3</span>
236
- </button>
237
-
238
- {
239
- userName && (
240
- <div class="user-dropdown">
241
- <button class="user-button">
242
- {userAvatar ? (
243
- <img src={userAvatar} alt={userName} class="user-avatar" />
244
- ) : (
245
- <span class="user-avatar-placeholder">
246
- {userName.charAt(0)}
247
- </span>
248
- )}
249
- <span class="user-name">{userName}</span>
250
- </button>
251
- </div>
252
- )
253
- }
254
- </div>
255
- </header>
194
+ <DashboardTopNavbar
195
+ title={title}
196
+ userName={userName}
197
+ userAvatar={userAvatar}
198
+ />
256
199
 
257
200
  <!-- 页面内容 -->
258
- <main class="page-content">
259
- <div class="content-container">
260
- <slot />
261
- </div>
201
+ <main class="cosy:flex-1 cosy:p-4 cosy:lg:p-6">
202
+ {
203
+ contentStyles.container ? (
204
+ <div class={`${contentStyles.container} ${contentStyles.shadow}`}>
205
+ <div class="cosy:card-body">
206
+ <slot />
207
+ </div>
208
+ </div>
209
+ ) : (
210
+ <slot />
211
+ )
212
+ }
262
213
  </main>
263
214
  </div>
264
215
  </div>
265
216
  </BaseLayout>
266
217
 
267
218
  <script>
268
- // 侧边栏折叠/展开功能
219
+ // 从本地存储恢复状态
269
220
  document.addEventListener('DOMContentLoaded', () => {
270
- const toggleSidebarBtn = document.getElementById('toggle-sidebar');
271
- const collapseSidebarBtn = document.getElementById('collapse-sidebar');
272
- const dashboardContainer = document.querySelector('.dashboard-container');
273
-
274
- if (toggleSidebarBtn && dashboardContainer) {
275
- toggleSidebarBtn.addEventListener('click', () => {
276
- dashboardContainer.classList.toggle('collapsed');
277
- // 保存状态到本地存储
278
- localStorage.setItem(
279
- 'sidebarCollapsed',
280
- dashboardContainer.classList.contains('collapsed') ? 'true' : 'false'
281
- );
282
- });
283
- }
284
-
285
- if (collapseSidebarBtn && dashboardContainer) {
286
- collapseSidebarBtn.addEventListener('click', () => {
287
- dashboardContainer.classList.toggle('collapsed');
288
- // 保存状态到本地存储
289
- localStorage.setItem(
290
- 'sidebarCollapsed',
291
- dashboardContainer.classList.contains('collapsed') ? 'true' : 'false'
292
- );
293
- });
294
- }
295
-
296
- // 从本地存储恢复状态
297
- const savedState = localStorage.getItem('sidebarCollapsed');
298
- if (savedState === 'true' && dashboardContainer) {
299
- dashboardContainer.classList.add('collapsed');
221
+ const drawerToggle = document.getElementById(
222
+ 'dashboard-drawer'
223
+ ) as HTMLInputElement;
224
+
225
+ if (drawerToggle) {
226
+ const savedState = localStorage.getItem('sidebarCollapsed');
227
+ if (savedState) {
228
+ drawerToggle.checked = savedState === 'true';
229
+ }
300
230
  }
301
231
  });
302
232
  </script>
303
-
304
- <style>
305
- /* 基础布局 */
306
- .dashboard-layout {
307
- min-height: 100vh;
308
- background-color: #f5f7fa;
309
- }
310
-
311
- .dashboard-container {
312
- display: flex;
313
- min-height: 100vh;
314
- }
315
-
316
- /* 侧边栏 */
317
- .sidebar {
318
- width: 260px;
319
- background-color: #1e293b;
320
- color: #e2e8f0;
321
- transition: width 0.3s ease;
322
- display: flex;
323
- flex-direction: column;
324
- position: fixed;
325
- top: 0;
326
- left: 0;
327
- bottom: 0;
328
- z-index: 50;
329
- overflow-y: auto;
330
- }
331
-
332
- .sidebar-header {
333
- display: flex;
334
- align-items: center;
335
- justify-content: space-between;
336
- padding: 1rem;
337
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
338
- }
339
-
340
- .logo {
341
- display: flex;
342
- align-items: center;
343
- gap: 0.75rem;
344
- color: #fff;
345
- text-decoration: none;
346
- }
347
-
348
- .logo-icon {
349
- font-size: 1.5rem;
350
- }
351
-
352
- .logo-text {
353
- font-size: 1.25rem;
354
- font-weight: 600;
355
- white-space: nowrap;
356
- }
357
-
358
- .collapse-button {
359
- background: none;
360
- border: none;
361
- color: #e2e8f0;
362
- cursor: pointer;
363
- padding: 0.5rem;
364
- border-radius: 0.375rem;
365
- }
366
-
367
- .collapse-button:hover {
368
- background-color: rgba(255, 255, 255, 0.1);
369
- }
370
-
371
- .sidebar-nav {
372
- flex: 1;
373
- padding: 1rem 0;
374
- }
375
-
376
- .nav-list {
377
- list-style: none;
378
- padding: 0;
379
- margin: 0;
380
- }
381
-
382
- .nav-item {
383
- margin-bottom: 0.25rem;
384
- }
385
-
386
- .nav-link {
387
- display: flex;
388
- align-items: center;
389
- padding: 0.75rem 1rem;
390
- color: #e2e8f0;
391
- text-decoration: none;
392
- border-radius: 0.375rem;
393
- margin: 0 0.5rem;
394
- gap: 0.75rem;
395
- }
396
-
397
- .nav-link:hover {
398
- background-color: rgba(255, 255, 255, 0.1);
399
- }
400
-
401
- .nav-item.active .nav-link {
402
- background-color: rgba(59, 130, 246, 0.5);
403
- color: #fff;
404
- }
405
-
406
- .nav-icon {
407
- font-size: 1.25rem;
408
- width: 1.5rem;
409
- text-align: center;
410
- }
411
-
412
- .nav-text {
413
- flex: 1;
414
- white-space: nowrap;
415
- }
416
-
417
- .nav-badge {
418
- background-color: #ef4444;
419
- color: #fff;
420
- font-size: 0.75rem;
421
- padding: 0.125rem 0.375rem;
422
- border-radius: 9999px;
423
- }
424
-
425
- .subnav-list {
426
- list-style: none;
427
- padding: 0;
428
- margin: 0.25rem 0 0.5rem 2.5rem;
429
- }
430
-
431
- .subnav-link {
432
- display: flex;
433
- align-items: center;
434
- padding: 0.5rem 1rem;
435
- color: #cbd5e1;
436
- text-decoration: none;
437
- border-radius: 0.375rem;
438
- gap: 0.5rem;
439
- font-size: 0.875rem;
440
- }
441
-
442
- .subnav-link:hover {
443
- background-color: rgba(255, 255, 255, 0.05);
444
- }
445
-
446
- .subnav-item.active .subnav-link {
447
- color: #3b82f6;
448
- font-weight: 500;
449
- }
450
-
451
- .subnav-icon {
452
- font-size: 1rem;
453
- width: 1.25rem;
454
- text-align: center;
455
- }
456
-
457
- /* 主内容区 */
458
- .main-content {
459
- flex: 1;
460
- margin-left: 260px;
461
- transition: margin-left 0.3s ease;
462
- display: flex;
463
- flex-direction: column;
464
- min-height: 100vh;
465
- }
466
-
467
- /* 顶部导航栏 */
468
- .top-navbar {
469
- display: flex;
470
- justify-content: space-between;
471
- align-items: center;
472
- padding: 0.75rem 1.5rem;
473
- background-color: #fff;
474
- border-bottom: 1px solid #e2e8f0;
475
- height: 64px;
476
- position: sticky;
477
- top: 0;
478
- z-index: 40;
479
- }
480
-
481
- .navbar-left {
482
- display: flex;
483
- align-items: center;
484
- gap: 1rem;
485
- }
486
-
487
- .menu-button {
488
- background: none;
489
- border: none;
490
- color: #64748b;
491
- cursor: pointer;
492
- padding: 0.5rem;
493
- border-radius: 0.375rem;
494
- display: flex;
495
- align-items: center;
496
- justify-content: center;
497
- }
498
-
499
- .menu-button:hover {
500
- background-color: #f1f5f9;
501
- }
502
-
503
- .breadcrumb {
504
- color: #64748b;
505
- font-size: 0.875rem;
506
- }
507
-
508
- .navbar-right {
509
- display: flex;
510
- align-items: center;
511
- gap: 1rem;
512
- }
513
-
514
- .search-box {
515
- position: relative;
516
- }
517
-
518
- .search-input {
519
- padding: 0.5rem 1rem 0.5rem 2.5rem;
520
- border: 1px solid #e2e8f0;
521
- border-radius: 0.375rem;
522
- background-color: #f8fafc;
523
- width: 240px;
524
- font-size: 0.875rem;
525
- }
526
-
527
- .search-icon {
528
- position: absolute;
529
- left: 0.75rem;
530
- top: 50%;
531
- transform: translateY(-50%);
532
- color: #94a3b8;
533
- }
534
-
535
- .notification-button {
536
- background: none;
537
- border: none;
538
- color: #64748b;
539
- cursor: pointer;
540
- padding: 0.5rem;
541
- border-radius: 0.375rem;
542
- position: relative;
543
- }
544
-
545
- .notification-button:hover {
546
- background-color: #f1f5f9;
547
- }
548
-
549
- .notification-badge {
550
- position: absolute;
551
- top: 0;
552
- right: 0;
553
- background-color: #ef4444;
554
- color: #fff;
555
- font-size: 0.75rem;
556
- width: 1rem;
557
- height: 1rem;
558
- border-radius: 9999px;
559
- display: flex;
560
- align-items: center;
561
- justify-content: center;
562
- }
563
-
564
- .user-dropdown {
565
- position: relative;
566
- }
567
-
568
- .user-button {
569
- display: flex;
570
- align-items: center;
571
- gap: 0.5rem;
572
- background: none;
573
- border: none;
574
- cursor: pointer;
575
- padding: 0.5rem;
576
- border-radius: 0.375rem;
577
- }
578
-
579
- .user-button:hover {
580
- background-color: #f1f5f9;
581
- }
582
-
583
- .user-avatar {
584
- width: 2rem;
585
- height: 2rem;
586
- border-radius: 9999px;
587
- object-fit: cover;
588
- }
589
-
590
- .user-avatar-placeholder {
591
- width: 2rem;
592
- height: 2rem;
593
- border-radius: 9999px;
594
- background-color: #3b82f6;
595
- color: #fff;
596
- display: flex;
597
- align-items: center;
598
- justify-content: center;
599
- font-weight: 600;
600
- }
601
-
602
- .user-name {
603
- color: #334155;
604
- font-weight: 500;
605
- }
606
-
607
- /* 页面内容 */
608
- .page-content {
609
- flex: 1;
610
- padding: 1.5rem;
611
- }
612
-
613
- .content-container {
614
- background-color: #fff;
615
- border-radius: 0.5rem;
616
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
617
- padding: 1.5rem;
618
- }
619
-
620
- /* 折叠状态 */
621
- .dashboard-container.collapsed .sidebar {
622
- width: 80px;
623
- }
624
-
625
- .dashboard-container.collapsed .logo-text,
626
- .dashboard-container.collapsed .nav-text,
627
- .dashboard-container.collapsed .nav-badge,
628
- .dashboard-container.collapsed .subnav-list {
629
- display: none;
630
- }
631
-
632
- .dashboard-container.collapsed .nav-link {
633
- justify-content: center;
634
- padding: 0.75rem;
635
- }
636
-
637
- .dashboard-container.collapsed .nav-icon {
638
- margin: 0;
639
- }
640
-
641
- .dashboard-container.collapsed .main-content {
642
- margin-left: 80px;
643
- }
644
-
645
- /* 响应式调整 */
646
- @media (max-width: 1024px) {
647
- .sidebar {
648
- transform: translateX(-100%);
649
- width: 260px;
650
- }
651
-
652
- .main-content {
653
- margin-left: 0;
654
- }
655
-
656
- .dashboard-container.collapsed .sidebar {
657
- transform: translateX(0);
658
- }
659
-
660
- .dashboard-container:not(.collapsed) .sidebar {
661
- transform: translateX(-100%);
662
- }
663
- }
664
-
665
- @media (max-width: 640px) {
666
- .search-box {
667
- display: none;
668
- }
669
-
670
- .user-name {
671
- display: none;
672
- }
673
-
674
- .top-navbar {
675
- padding: 0.75rem 1rem;
676
- }
677
-
678
- .page-content {
679
- padding: 1rem;
680
- }
681
-
682
- .content-container {
683
- padding: 1rem;
684
- }
685
- }
686
- </style>