@coffic/cosy-ui 0.1.29 → 0.2.2

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 (84) hide show
  1. package/README.md +43 -22
  2. package/dist/app.css +1 -0
  3. package/dist/assets/logo-rounded.png +0 -0
  4. package/dist/assets/logo.png +0 -0
  5. package/dist/components/base/Alert.astro +186 -0
  6. package/dist/components/base/Button.astro +103 -0
  7. package/dist/components/base/Image.astro +291 -0
  8. package/dist/components/base/Link.astro +131 -0
  9. package/dist/components/containers/Container.astro +103 -0
  10. package/dist/components/containers/Main.astro +167 -0
  11. package/dist/components/containers/Section.astro +145 -0
  12. package/dist/components/containers/index.ts +3 -0
  13. package/dist/components/data-display/Blog.astro +195 -0
  14. package/dist/components/data-display/TeamMember.astro +135 -0
  15. package/dist/components/data-display/TeamMembers.astro +101 -0
  16. package/dist/components/display/Banner.astro +57 -0
  17. package/dist/components/display/Card.astro +135 -0
  18. package/dist/components/display/CodeBlock.astro +147 -0
  19. package/dist/components/display/CodeExample.astro +330 -0
  20. package/dist/components/display/Hero.astro +119 -0
  21. package/dist/components/display/Modal.astro +115 -0
  22. package/dist/components/icons/AlertTriangle.astro +35 -0
  23. package/dist/components/icons/CalendarIcon.astro +38 -0
  24. package/dist/components/icons/CheckCircle.astro +36 -0
  25. package/dist/components/icons/CheckIcon.astro +38 -0
  26. package/dist/components/icons/ClipboardIcon.astro +39 -0
  27. package/dist/components/icons/CloseIcon.astro +38 -0
  28. package/dist/components/icons/ErrorIcon.astro +35 -0
  29. package/dist/components/icons/GithubIcon.astro +31 -0
  30. package/dist/components/icons/InfoCircle.astro +37 -0
  31. package/dist/components/icons/InfoIcon.astro +38 -0
  32. package/dist/components/icons/LinkIcon.astro +39 -0
  33. package/dist/components/icons/LinkedinIcon.astro +31 -0
  34. package/dist/components/icons/MenuIcon.astro +41 -0
  35. package/dist/components/icons/SearchIcon.astro +40 -0
  36. package/dist/components/icons/SocialIcon.astro +100 -0
  37. package/dist/components/icons/SuccessIcon.astro +35 -0
  38. package/dist/components/icons/SunCloudyIcon.astro +45 -0
  39. package/dist/components/icons/TwitterIcon.astro +31 -0
  40. package/dist/components/icons/UserIcon.astro +35 -0
  41. package/dist/components/icons/WarningIcon.astro +38 -0
  42. package/dist/components/icons/XCircle.astro +37 -0
  43. package/dist/components/layouts/BaseLayout.astro +144 -0
  44. package/dist/components/layouts/DashboardLayout.astro +660 -0
  45. package/dist/components/layouts/DefaultLayout.astro +170 -0
  46. package/dist/components/layouts/DocumentationLayout.astro +469 -0
  47. package/dist/components/layouts/Flex.astro +138 -0
  48. package/dist/components/layouts/Footer.astro +284 -0
  49. package/dist/components/layouts/Grid.astro +182 -0
  50. package/dist/components/layouts/Header.astro +114 -0
  51. package/dist/components/layouts/LandingLayout.astro +388 -0
  52. package/dist/components/layouts/Stack.astro +149 -0
  53. package/dist/components/navigation/LanguageSwitcher.astro +81 -0
  54. package/dist/components/navigation/TableOfContents.astro +352 -0
  55. package/dist/components/navigation/ThemeSwitcher.astro +89 -0
  56. package/dist/components/typography/Article.astro +144 -0
  57. package/dist/components/typography/Heading.astro +205 -0
  58. package/dist/components/typography/Text.astro +187 -0
  59. package/dist/index.ts +70 -0
  60. package/dist/integration.ts +14 -0
  61. package/dist/style.ts +1 -0
  62. package/{src → dist}/types/footer.ts +1 -0
  63. package/dist/utils/theme.ts +55 -0
  64. package/package.json +67 -59
  65. package/index.ts +0 -18
  66. package/src/components/Alert.astro +0 -78
  67. package/src/components/Article.astro +0 -11
  68. package/src/components/Banner.astro +0 -49
  69. package/src/components/Blog.astro +0 -115
  70. package/src/components/Button.astro +0 -49
  71. package/src/components/Card.astro +0 -113
  72. package/src/components/CodeBlock.astro +0 -186
  73. package/src/components/Footer.astro +0 -148
  74. package/src/components/Header.astro +0 -305
  75. package/src/components/Hero.astro +0 -69
  76. package/src/components/Image.astro +0 -251
  77. package/src/components/Link.astro +0 -82
  78. package/src/components/Modal.astro +0 -67
  79. package/src/components/SocialIcon.astro +0 -36
  80. package/src/components/TeamMember.astro +0 -68
  81. package/src/components/TeamMembers.astro +0 -43
  82. package/src/env.d.ts +0 -0
  83. /package/{src/components → dist/components/base}/ThemeItem.astro +0 -0
  84. /package/{src → dist}/utils/social.ts +0 -0
@@ -0,0 +1,660 @@
1
+ ---
2
+ /**
3
+ * @component DashboardLayout
4
+ *
5
+ * @description
6
+ * DashboardLayout 组件适用于管理后台的布局,包含侧边栏导航和顶部导航栏。
7
+ * 提供了完整的管理界面框架,包括响应式设计和暗色主题支持。
8
+ *
9
+ * @design
10
+ * 设计理念:
11
+ * 1. 清晰的信息层次 - 通过侧边栏和顶部导航提供明确的导航结构
12
+ * 2. 响应式布局 - 在不同设备上提供良好的用户体验
13
+ * 3. 可定制性 - 支持自定义导航项、系统名称和用户信息
14
+ * 4. 状态保持 - 记住用户的侧边栏折叠状态
15
+ *
16
+ * @example
17
+ * ```astro
18
+ * ---
19
+ * import DashboardLayout from '../layouts/DashboardLayout.astro';
20
+ *
21
+ * const navItems = [
22
+ * { href: "/dashboard", icon: "home", text: "仪表盘" },
23
+ * { href: "/dashboard/users", icon: "user", text: "用户管理" },
24
+ * { href: "/dashboard/settings", icon: "settings", text: "系统设置" }
25
+ * ];
26
+ * ---
27
+ *
28
+ * <DashboardLayout
29
+ * title="管理后台"
30
+ * navItems={navItems}
31
+ * userName="管理员"
32
+ * >
33
+ * <h1>仪表盘内容</h1>
34
+ * <p>这是仪表盘的主要内容</p>
35
+ * </DashboardLayout>
36
+ * ```
37
+ */
38
+
39
+ import BaseLayout from './BaseLayout.astro';
40
+ import '../../app.css';
41
+
42
+ export interface NavItem {
43
+ href: string;
44
+ icon: string;
45
+ text: string;
46
+ badge?: string | number;
47
+ items?: NavItem[];
48
+ }
49
+
50
+ export interface Props {
51
+ /**
52
+ * 页面标题
53
+ */
54
+ title: string;
55
+
56
+ /**
57
+ * 页面描述
58
+ */
59
+ description?: string;
60
+
61
+ /**
62
+ * 系统名称
63
+ * @default "管理系统"
64
+ */
65
+ systemName?: string;
66
+
67
+ /**
68
+ * 导航项目
69
+ */
70
+ navItems: NavItem[];
71
+
72
+ /**
73
+ * 用户名
74
+ */
75
+ userName?: string;
76
+
77
+ /**
78
+ * 用户头像
79
+ */
80
+ userAvatar?: string;
81
+
82
+ /**
83
+ * 是否折叠侧边栏
84
+ * @default false
85
+ */
86
+ sidebarCollapsed?: boolean;
87
+
88
+ /**
89
+ * 自定义头部内容
90
+ */
91
+ head?: astroHTML.JSX.Element;
92
+
93
+ /**
94
+ * 页面类名
95
+ */
96
+ class?: string;
97
+
98
+ /**
99
+ * 类名列表
100
+ */
101
+ 'class:list'?: any;
102
+ }
103
+
104
+ const {
105
+ title,
106
+ description,
107
+ systemName = "管理系统",
108
+ navItems,
109
+ userName,
110
+ userAvatar,
111
+ sidebarCollapsed = false,
112
+ head,
113
+ class: className,
114
+ 'class:list': classList,
115
+ ...rest
116
+ } = Astro.props;
117
+
118
+ 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
+ };
136
+ ---
137
+
138
+ <BaseLayout
139
+ title={title}
140
+ description={description}
141
+ head={head}
142
+ class="dashboard-layout"
143
+ {...rest}
144
+ >
145
+ <div class:list={["dashboard-container", { collapsed: sidebarCollapsed }]}>
146
+ <!-- 侧边栏 -->
147
+ <aside class="sidebar">
148
+ <div class="sidebar-header">
149
+ <a href="/dashboard" class="logo">
150
+ <span class="logo-icon">⚡</span>
151
+ <span class="logo-text">{systemName}</span>
152
+ </a>
153
+ <button class="collapse-button" id="collapse-sidebar">
154
+ <span class="collapse-icon">{iconMap.menu}</span>
155
+ </button>
156
+ </div>
157
+
158
+ <nav class="sidebar-nav">
159
+ <ul class="nav-list">
160
+ {navItems.map((item: NavItem) => {
161
+ const isActive = currentPath === item.href ||
162
+ (item.items && item.items.some((subitem: NavItem) => currentPath === subitem.href));
163
+
164
+ return (
165
+ <li class:list={["nav-item", { active: isActive }]}>
166
+ <a href={item.href} class="nav-link">
167
+ <span class="nav-icon">{iconMap[item.icon] || "📁"}</span>
168
+ <span class="nav-text">{item.text}</span>
169
+ {item.badge && <span class="nav-badge">{item.badge}</span>}
170
+ </a>
171
+
172
+ {item.items && (
173
+ <ul class="subnav-list">
174
+ {item.items.map((subitem: NavItem) => {
175
+ const isSubActive = currentPath === subitem.href;
176
+ return (
177
+ <li class:list={["subnav-item", { active: isSubActive }]}>
178
+ <a href={subitem.href} class="subnav-link">
179
+ <span class="subnav-icon">{iconMap[subitem.icon] || "📄"}</span>
180
+ <span class="subnav-text">{subitem.text}</span>
181
+ {subitem.badge && <span class="subnav-badge">{subitem.badge}</span>}
182
+ </a>
183
+ </li>
184
+ );
185
+ })}
186
+ </ul>
187
+ )}
188
+ </li>
189
+ );
190
+ })}
191
+ </ul>
192
+ </nav>
193
+ </aside>
194
+
195
+ <!-- 主内容区 -->
196
+ <div class="main-content">
197
+ <!-- 顶部导航栏 -->
198
+ <header class="top-navbar">
199
+ <div class="navbar-left">
200
+ <button class="menu-button" id="toggle-sidebar">
201
+ <span class="menu-icon">{iconMap.menu}</span>
202
+ </button>
203
+
204
+ <div class="breadcrumb">
205
+ <span class="breadcrumb-item">{title}</span>
206
+ </div>
207
+ </div>
208
+
209
+ <div class="navbar-right">
210
+ <div class="search-box">
211
+ <input type="text" placeholder="搜索..." class="search-input" />
212
+ <span class="search-icon">{iconMap.search}</span>
213
+ </div>
214
+
215
+ <button class="notification-button">
216
+ <span class="notification-icon">{iconMap.notification}</span>
217
+ <span class="notification-badge">3</span>
218
+ </button>
219
+
220
+ {userName && (
221
+ <div class="user-dropdown">
222
+ <button class="user-button">
223
+ {userAvatar ? (
224
+ <img src={userAvatar} alt={userName} class="user-avatar" />
225
+ ) : (
226
+ <span class="user-avatar-placeholder">{userName.charAt(0)}</span>
227
+ )}
228
+ <span class="user-name">{userName}</span>
229
+ </button>
230
+ </div>
231
+ )}
232
+ </div>
233
+ </header>
234
+
235
+ <!-- 页面内容 -->
236
+ <main class="page-content">
237
+ <div class="content-container">
238
+ <slot />
239
+ </div>
240
+ </main>
241
+ </div>
242
+ </div>
243
+ </BaseLayout>
244
+
245
+ <script>
246
+ // 侧边栏折叠/展开功能
247
+ document.addEventListener('DOMContentLoaded', () => {
248
+ const toggleSidebarBtn = document.getElementById('toggle-sidebar');
249
+ const collapseSidebarBtn = document.getElementById('collapse-sidebar');
250
+ const dashboardContainer = document.querySelector('.dashboard-container');
251
+
252
+ if (toggleSidebarBtn && dashboardContainer) {
253
+ toggleSidebarBtn.addEventListener('click', () => {
254
+ dashboardContainer.classList.toggle('collapsed');
255
+ // 保存状态到本地存储
256
+ localStorage.setItem('sidebarCollapsed',
257
+ dashboardContainer.classList.contains('collapsed') ? 'true' : 'false');
258
+ });
259
+ }
260
+
261
+ if (collapseSidebarBtn && dashboardContainer) {
262
+ collapseSidebarBtn.addEventListener('click', () => {
263
+ dashboardContainer.classList.toggle('collapsed');
264
+ // 保存状态到本地存储
265
+ localStorage.setItem('sidebarCollapsed',
266
+ dashboardContainer.classList.contains('collapsed') ? 'true' : 'false');
267
+ });
268
+ }
269
+
270
+ // 从本地存储恢复状态
271
+ const savedState = localStorage.getItem('sidebarCollapsed');
272
+ if (savedState === 'true' && dashboardContainer) {
273
+ dashboardContainer.classList.add('collapsed');
274
+ }
275
+ });
276
+ </script>
277
+
278
+ <style>
279
+ /* 基础布局 */
280
+ .dashboard-layout {
281
+ min-height: 100vh;
282
+ background-color: #f5f7fa;
283
+ }
284
+
285
+ .dashboard-container {
286
+ display: flex;
287
+ min-height: 100vh;
288
+ }
289
+
290
+ /* 侧边栏 */
291
+ .sidebar {
292
+ width: 260px;
293
+ background-color: #1e293b;
294
+ color: #e2e8f0;
295
+ transition: width 0.3s ease;
296
+ display: flex;
297
+ flex-direction: column;
298
+ position: fixed;
299
+ top: 0;
300
+ left: 0;
301
+ bottom: 0;
302
+ z-index: 50;
303
+ overflow-y: auto;
304
+ }
305
+
306
+ .sidebar-header {
307
+ display: flex;
308
+ align-items: center;
309
+ justify-content: space-between;
310
+ padding: 1rem;
311
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
312
+ }
313
+
314
+ .logo {
315
+ display: flex;
316
+ align-items: center;
317
+ gap: 0.75rem;
318
+ color: #fff;
319
+ text-decoration: none;
320
+ }
321
+
322
+ .logo-icon {
323
+ font-size: 1.5rem;
324
+ }
325
+
326
+ .logo-text {
327
+ font-size: 1.25rem;
328
+ font-weight: 600;
329
+ white-space: nowrap;
330
+ }
331
+
332
+ .collapse-button {
333
+ background: none;
334
+ border: none;
335
+ color: #e2e8f0;
336
+ cursor: pointer;
337
+ padding: 0.5rem;
338
+ border-radius: 0.375rem;
339
+ }
340
+
341
+ .collapse-button:hover {
342
+ background-color: rgba(255, 255, 255, 0.1);
343
+ }
344
+
345
+ .sidebar-nav {
346
+ flex: 1;
347
+ padding: 1rem 0;
348
+ }
349
+
350
+ .nav-list {
351
+ list-style: none;
352
+ padding: 0;
353
+ margin: 0;
354
+ }
355
+
356
+ .nav-item {
357
+ margin-bottom: 0.25rem;
358
+ }
359
+
360
+ .nav-link {
361
+ display: flex;
362
+ align-items: center;
363
+ padding: 0.75rem 1rem;
364
+ color: #e2e8f0;
365
+ text-decoration: none;
366
+ border-radius: 0.375rem;
367
+ margin: 0 0.5rem;
368
+ gap: 0.75rem;
369
+ }
370
+
371
+ .nav-link:hover {
372
+ background-color: rgba(255, 255, 255, 0.1);
373
+ }
374
+
375
+ .nav-item.active .nav-link {
376
+ background-color: rgba(59, 130, 246, 0.5);
377
+ color: #fff;
378
+ }
379
+
380
+ .nav-icon {
381
+ font-size: 1.25rem;
382
+ width: 1.5rem;
383
+ text-align: center;
384
+ }
385
+
386
+ .nav-text {
387
+ flex: 1;
388
+ white-space: nowrap;
389
+ }
390
+
391
+ .nav-badge {
392
+ background-color: #ef4444;
393
+ color: #fff;
394
+ font-size: 0.75rem;
395
+ padding: 0.125rem 0.375rem;
396
+ border-radius: 9999px;
397
+ }
398
+
399
+ .subnav-list {
400
+ list-style: none;
401
+ padding: 0;
402
+ margin: 0.25rem 0 0.5rem 2.5rem;
403
+ }
404
+
405
+ .subnav-link {
406
+ display: flex;
407
+ align-items: center;
408
+ padding: 0.5rem 1rem;
409
+ color: #cbd5e1;
410
+ text-decoration: none;
411
+ border-radius: 0.375rem;
412
+ gap: 0.5rem;
413
+ font-size: 0.875rem;
414
+ }
415
+
416
+ .subnav-link:hover {
417
+ background-color: rgba(255, 255, 255, 0.05);
418
+ }
419
+
420
+ .subnav-item.active .subnav-link {
421
+ color: #3b82f6;
422
+ font-weight: 500;
423
+ }
424
+
425
+ .subnav-icon {
426
+ font-size: 1rem;
427
+ width: 1.25rem;
428
+ text-align: center;
429
+ }
430
+
431
+ /* 主内容区 */
432
+ .main-content {
433
+ flex: 1;
434
+ margin-left: 260px;
435
+ transition: margin-left 0.3s ease;
436
+ display: flex;
437
+ flex-direction: column;
438
+ min-height: 100vh;
439
+ }
440
+
441
+ /* 顶部导航栏 */
442
+ .top-navbar {
443
+ display: flex;
444
+ justify-content: space-between;
445
+ align-items: center;
446
+ padding: 0.75rem 1.5rem;
447
+ background-color: #fff;
448
+ border-bottom: 1px solid #e2e8f0;
449
+ height: 64px;
450
+ position: sticky;
451
+ top: 0;
452
+ z-index: 40;
453
+ }
454
+
455
+ .navbar-left {
456
+ display: flex;
457
+ align-items: center;
458
+ gap: 1rem;
459
+ }
460
+
461
+ .menu-button {
462
+ background: none;
463
+ border: none;
464
+ color: #64748b;
465
+ cursor: pointer;
466
+ padding: 0.5rem;
467
+ border-radius: 0.375rem;
468
+ display: flex;
469
+ align-items: center;
470
+ justify-content: center;
471
+ }
472
+
473
+ .menu-button:hover {
474
+ background-color: #f1f5f9;
475
+ }
476
+
477
+ .breadcrumb {
478
+ color: #64748b;
479
+ font-size: 0.875rem;
480
+ }
481
+
482
+ .navbar-right {
483
+ display: flex;
484
+ align-items: center;
485
+ gap: 1rem;
486
+ }
487
+
488
+ .search-box {
489
+ position: relative;
490
+ }
491
+
492
+ .search-input {
493
+ padding: 0.5rem 1rem 0.5rem 2.5rem;
494
+ border: 1px solid #e2e8f0;
495
+ border-radius: 0.375rem;
496
+ background-color: #f8fafc;
497
+ width: 240px;
498
+ font-size: 0.875rem;
499
+ }
500
+
501
+ .search-icon {
502
+ position: absolute;
503
+ left: 0.75rem;
504
+ top: 50%;
505
+ transform: translateY(-50%);
506
+ color: #94a3b8;
507
+ }
508
+
509
+ .notification-button {
510
+ background: none;
511
+ border: none;
512
+ color: #64748b;
513
+ cursor: pointer;
514
+ padding: 0.5rem;
515
+ border-radius: 0.375rem;
516
+ position: relative;
517
+ }
518
+
519
+ .notification-button:hover {
520
+ background-color: #f1f5f9;
521
+ }
522
+
523
+ .notification-badge {
524
+ position: absolute;
525
+ top: 0;
526
+ right: 0;
527
+ background-color: #ef4444;
528
+ color: #fff;
529
+ font-size: 0.75rem;
530
+ width: 1rem;
531
+ height: 1rem;
532
+ border-radius: 9999px;
533
+ display: flex;
534
+ align-items: center;
535
+ justify-content: center;
536
+ }
537
+
538
+ .user-dropdown {
539
+ position: relative;
540
+ }
541
+
542
+ .user-button {
543
+ display: flex;
544
+ align-items: center;
545
+ gap: 0.5rem;
546
+ background: none;
547
+ border: none;
548
+ cursor: pointer;
549
+ padding: 0.5rem;
550
+ border-radius: 0.375rem;
551
+ }
552
+
553
+ .user-button:hover {
554
+ background-color: #f1f5f9;
555
+ }
556
+
557
+ .user-avatar {
558
+ width: 2rem;
559
+ height: 2rem;
560
+ border-radius: 9999px;
561
+ object-fit: cover;
562
+ }
563
+
564
+ .user-avatar-placeholder {
565
+ width: 2rem;
566
+ height: 2rem;
567
+ border-radius: 9999px;
568
+ background-color: #3b82f6;
569
+ color: #fff;
570
+ display: flex;
571
+ align-items: center;
572
+ justify-content: center;
573
+ font-weight: 600;
574
+ }
575
+
576
+ .user-name {
577
+ color: #334155;
578
+ font-weight: 500;
579
+ }
580
+
581
+ /* 页面内容 */
582
+ .page-content {
583
+ flex: 1;
584
+ padding: 1.5rem;
585
+ }
586
+
587
+ .content-container {
588
+ background-color: #fff;
589
+ border-radius: 0.5rem;
590
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
591
+ padding: 1.5rem;
592
+ }
593
+
594
+ /* 折叠状态 */
595
+ .dashboard-container.collapsed .sidebar {
596
+ width: 80px;
597
+ }
598
+
599
+ .dashboard-container.collapsed .logo-text,
600
+ .dashboard-container.collapsed .nav-text,
601
+ .dashboard-container.collapsed .nav-badge,
602
+ .dashboard-container.collapsed .subnav-list {
603
+ display: none;
604
+ }
605
+
606
+ .dashboard-container.collapsed .nav-link {
607
+ justify-content: center;
608
+ padding: 0.75rem;
609
+ }
610
+
611
+ .dashboard-container.collapsed .nav-icon {
612
+ margin: 0;
613
+ }
614
+
615
+ .dashboard-container.collapsed .main-content {
616
+ margin-left: 80px;
617
+ }
618
+
619
+ /* 响应式调整 */
620
+ @media (max-width: 1024px) {
621
+ .sidebar {
622
+ transform: translateX(-100%);
623
+ width: 260px;
624
+ }
625
+
626
+ .main-content {
627
+ margin-left: 0;
628
+ }
629
+
630
+ .dashboard-container.collapsed .sidebar {
631
+ transform: translateX(0);
632
+ }
633
+
634
+ .dashboard-container:not(.collapsed) .sidebar {
635
+ transform: translateX(-100%);
636
+ }
637
+ }
638
+
639
+ @media (max-width: 640px) {
640
+ .search-box {
641
+ display: none;
642
+ }
643
+
644
+ .user-name {
645
+ display: none;
646
+ }
647
+
648
+ .top-navbar {
649
+ padding: 0.75rem 1rem;
650
+ }
651
+
652
+ .page-content {
653
+ padding: 1rem;
654
+ }
655
+
656
+ .content-container {
657
+ padding: 1rem;
658
+ }
659
+ }
660
+ </style>