@coffic/cosy-ui 0.9.16 → 0.9.18

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.
@@ -29,6 +29,7 @@ export * from './src-astro/layout-basic';
29
29
  export * from './src-astro/layout-basic/BaseLayout.astro';
30
30
  export * from './src-astro/layout-dashboard';
31
31
  export * from './src-astro/link';
32
+ export * from './src-astro/loading-overlay';
32
33
  export * from './src-astro/login';
33
34
  export * from './src-astro/logout';
34
35
  export * from './src-astro/main';
@@ -175,7 +175,6 @@ import {
175
175
  Main,
176
176
  Sidebar,
177
177
  } from '../../index-astro';
178
- import { ClientRouter } from 'astro:transitions';
179
178
 
180
179
  interface Props extends IAppLayoutProps {}
181
180
 
@@ -196,7 +195,6 @@ const {
196
195
  ---
197
196
 
198
197
  <BaseLayout {...metaConfig} debug={debug}>
199
- <ClientRouter />
200
198
  {
201
199
  showHeader && (
202
200
  <Header {...headerConfig} debug={debug} transition:persist>
@@ -51,6 +51,8 @@
51
51
 
52
52
  import '../../style.ts';
53
53
  import { type IMetaProps } from '../../index-astro';
54
+ import { ClientRouter } from 'astro:transitions';
55
+ import { LoadingOverlay } from '../loading-overlay';
54
56
 
55
57
  export interface Props extends IMetaProps {}
56
58
 
@@ -67,6 +69,7 @@ const {
67
69
  favicon,
68
70
  'class:list': classList,
69
71
  background = 'default',
72
+ loadingDelay = 1000,
70
73
  } = Astro.props;
71
74
 
72
75
  // 处理背景色 class
@@ -111,9 +114,12 @@ let bodyClasses = [
111
114
  <!-- 自定义头部内容 -->
112
115
  {head && <div set:html={head} />}
113
116
 
117
+ <ClientRouter />
118
+
114
119
  <slot name="head" />
115
120
  </head>
116
121
  <body class:list={[bodyClasses, classList, 'min-h-screen']}>
117
122
  <slot />
123
+ <LoadingOverlay loadingDelay={loadingDelay} />
118
124
  </body>
119
125
  </html>
@@ -0,0 +1,178 @@
1
+ ---
2
+ /**
3
+ * @component LoadingOverlay
4
+ *
5
+ * @description
6
+ * LoadingOverlay 组件是一个全屏加载弹出层,用于在页面跳转时显示加载状态。
7
+ * 它监听 Astro 的页面过渡事件,在跳转开始时延迟显示,跳转完成后隐藏。
8
+ * 为了避免频繁的视觉干扰,只有在加载时间超过指定延迟时间(默认1秒)时才显示。
9
+ *
10
+ * @design
11
+ * 设计理念:
12
+ * 1. 全屏覆盖 - 使用固定定位覆盖整个视口
13
+ * 2. 居中显示 - 加载指示器在屏幕中央显示
14
+ * 3. 平滑动画 - 使用淡入淡出动画效果
15
+ * 4. 延迟显示 - 避免短时间加载的视觉干扰
16
+ * 5. 可定制性 - 支持自定义加载文本、样式和延迟时间
17
+ *
18
+ * @usage
19
+ * 基本用法:
20
+ * ```astro
21
+ * ---
22
+ * import { LoadingOverlay } from '@coffic/cosy-ui';
23
+ * ---
24
+ *
25
+ * <LoadingOverlay />
26
+ * ```
27
+ *
28
+ * 自定义延迟时间:
29
+ * ```astro
30
+ * <LoadingOverlay delay={2000} text="页面加载中..." />
31
+ * ```
32
+ *
33
+ * 自定义样式:
34
+ * ```astro
35
+ * <LoadingOverlay
36
+ * text="正在跳转..."
37
+ * class="custom-loading-overlay"
38
+ * delay={1500}
39
+ * />
40
+ * ```
41
+ */
42
+
43
+ import '../../style.ts';
44
+
45
+ export interface Props {
46
+ /** 加载文本 */
47
+ text?: string;
48
+ /** 自定义 CSS 类名 */
49
+ class?: string;
50
+ /** 是否显示加载动画 */
51
+ showSpinner?: boolean;
52
+ /** 加载动画类型 */
53
+ spinnerType?: 'dots' | 'spinner' | 'pulse';
54
+ /** 延迟显示时间(毫秒),默认1000ms */
55
+ loadingDelay?: number;
56
+ }
57
+
58
+ const {
59
+ text = 'Loading...',
60
+ class: className,
61
+ showSpinner = true,
62
+ spinnerType = 'dots',
63
+ loadingDelay = 1000,
64
+ } = Astro.props;
65
+
66
+ // 生成唯一的 ID
67
+ const overlayId = `loading-overlay-${Math.random().toString(36).substr(2, 9)}`;
68
+ ---
69
+
70
+ <div
71
+ id={overlayId}
72
+ class:list={[
73
+ 'cosy:fixed cosy:inset-0 cosy:z-[9999] cosy:bg-black/50 cosy:backdrop-blur-sm',
74
+ 'cosy:flex cosy:items-center cosy:justify-center',
75
+ 'cosy:opacity-0 cosy:pointer-events-none cosy:transition-opacity cosy:duration-300',
76
+ className,
77
+ ]}
78
+ data-loading-overlay>
79
+ <div
80
+ class="cosy:bg-white cosy:dark:bg-gray-800 cosy:rounded-lg cosy:shadow-xl cosy:p-6 cosy:max-w-sm cosy:w-full cosy:mx-4">
81
+ <div class="cosy:flex cosy:flex-col cosy:items-center cosy:space-y-4">
82
+ {
83
+ showSpinner && (
84
+ <div class="cosy:flex cosy:justify-center">
85
+ {spinnerType === 'dots' && (
86
+ <div class="cosy:flex cosy:space-x-1">
87
+ <div class="cosy:w-2 cosy:h-2 cosy:bg-blue-500 cosy:rounded-full cosy:animate-bounce" />
88
+ <div
89
+ class="cosy:w-2 cosy:h-2 cosy:bg-blue-500 cosy:rounded-full cosy:animate-bounce"
90
+ style="animation-delay: 0.1s;"
91
+ />
92
+ <div
93
+ class="cosy:w-2 cosy:h-2 cosy:bg-blue-500 cosy:rounded-full cosy:animate-bounce"
94
+ style="animation-delay: 0.2s;"
95
+ />
96
+ </div>
97
+ )}
98
+ {spinnerType === 'spinner' && (
99
+ <div class="cosy:w-8 cosy:h-8 cosy:border-4 cosy:border-blue-200 cosy:border-t-blue-500 cosy:rounded-full cosy:animate-spin" />
100
+ )}
101
+ {spinnerType === 'pulse' && (
102
+ <div class="cosy:w-8 cosy:h-8 cosy:bg-blue-500 cosy:rounded-full cosy:animate-pulse" />
103
+ )}
104
+ </div>
105
+ )
106
+ }
107
+ <p
108
+ class="cosy:text-gray-700 cosy:dark:text-gray-300 cosy:text-center cosy:font-medium">
109
+ {text}
110
+ </p>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <script define:vars={{ overlayId, loadingDelay }}>
116
+ // 获取加载弹出层元素
117
+ const overlay = document.getElementById(overlayId);
118
+
119
+ if (overlay) {
120
+ let loadingStartTime = null;
121
+ let showTimeout = null;
122
+ let isLoading = false;
123
+
124
+ // 显示加载弹出层的函数
125
+ const showOverlay = () => {
126
+ if (isLoading) return;
127
+
128
+ isLoading = true;
129
+ loadingStartTime = Date.now();
130
+
131
+ // 延迟显示,避免短时间加载的视觉干扰
132
+ showTimeout = window.setTimeout(() => {
133
+ overlay.style.opacity = '1';
134
+ overlay.style.pointerEvents = 'auto';
135
+ }, loadingDelay);
136
+ };
137
+
138
+ // 隐藏加载弹出层的函数
139
+ const hideOverlay = () => {
140
+ if (showTimeout) {
141
+ clearTimeout(showTimeout);
142
+ showTimeout = null;
143
+ }
144
+
145
+ isLoading = false;
146
+ loadingStartTime = null;
147
+
148
+ overlay.style.opacity = '0';
149
+ overlay.style.pointerEvents = 'none';
150
+ };
151
+
152
+ // 监听 Astro 页面过渡事件
153
+ document.addEventListener('astro:page-load', () => {
154
+ hideOverlay();
155
+ });
156
+
157
+ document.addEventListener('astro:before-preparation', () => {
158
+ showOverlay();
159
+ });
160
+
161
+ // 监听路由变化
162
+ document.addEventListener('astro:before-swap', () => {
163
+ showOverlay();
164
+ });
165
+
166
+ document.addEventListener('astro:after-swap', () => {
167
+ // 如果加载时间很短,立即隐藏
168
+ if (loadingStartTime && Date.now() - loadingStartTime < loadingDelay) {
169
+ hideOverlay();
170
+ } else {
171
+ // 否则延迟隐藏,给用户一个视觉反馈
172
+ setTimeout(() => {
173
+ hideOverlay();
174
+ }, 100);
175
+ }
176
+ });
177
+ }
178
+ </script>
@@ -0,0 +1,2 @@
1
+ export { default as LoadingOverlay } from './LoadingOverlay.astro';
2
+ export type { LoadingOverlayProps } from './types';
@@ -0,0 +1,12 @@
1
+ export interface LoadingOverlayProps {
2
+ /** 加载文本 */
3
+ text?: string;
4
+ /** 自定义 CSS 类名 */
5
+ class?: string;
6
+ /** 是否显示加载动画 */
7
+ showSpinner?: boolean;
8
+ /** 加载动画类型 */
9
+ spinnerType?: 'dots' | 'spinner' | 'pulse';
10
+ /** 延迟显示时间(毫秒),默认1000ms */
11
+ delay?: number;
12
+ }
@@ -66,4 +66,10 @@ export interface IMetaProps {
66
66
  * @default 'default'
67
67
  */
68
68
  background?: 'default' | 'white' | 'gray' | 'dark' | 'gradient-blue' | 'gradient-pink' | 'gradient-green';
69
+
70
+ /**
71
+ * 加载延迟时间(毫秒),默认1000ms
72
+ * @default 1000
73
+ */
74
+ loadingDelay?: number;
69
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffic/cosy-ui",
3
- "version": "0.9.16",
3
+ "version": "0.9.18",
4
4
  "description": "An astro component library",
5
5
  "author": {
6
6
  "name": "nookery",