@at-flux/astroflare 1.0.13 → 1.0.14
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.
package/package.json
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
* Loading spinner for Astro view transitions.
|
|
4
4
|
* Uses native <dialog> shown during page transitions.
|
|
5
5
|
* Override styles via CSS custom properties or by targeting #loading.
|
|
6
|
+
*
|
|
7
|
+
* The indicator itself is `LoadingSpinner`; fill the default slot to replace it.
|
|
6
8
|
*/
|
|
9
|
+
import LoadingSpinner from './LoadingSpinner.astro';
|
|
7
10
|
---
|
|
8
11
|
|
|
9
12
|
<dialog
|
|
@@ -13,7 +16,7 @@
|
|
|
13
16
|
<div class='flex items-center justify-center min-h-full p-0'>
|
|
14
17
|
<div class='loading-spinner'>
|
|
15
18
|
<slot>
|
|
16
|
-
<
|
|
19
|
+
<LoadingSpinner size='3rem' />
|
|
17
20
|
</slot>
|
|
18
21
|
</div>
|
|
19
22
|
</div>
|
|
@@ -37,23 +40,8 @@
|
|
|
37
40
|
transition: opacity 0.15s ease-out, transform 0.15s ease-out;
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
.loading-ring {
|
|
41
|
-
width: 3rem;
|
|
42
|
-
height: 3rem;
|
|
43
|
-
border: 3px solid transparent;
|
|
44
|
-
border-top-color: var(--color-brand, #7c5cff);
|
|
45
|
-
border-right-color: color-mix(in oklab, var(--color-brand, #7c5cff) 50%, transparent);
|
|
46
|
-
border-radius: 50%;
|
|
47
|
-
animation: spin 1s linear infinite;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@keyframes spin {
|
|
51
|
-
to { transform: rotate(360deg); }
|
|
52
|
-
}
|
|
53
|
-
|
|
54
43
|
@media (prefers-reduced-motion: reduce) {
|
|
55
44
|
.loading-spinner { transition: none; }
|
|
56
|
-
.loading-ring { animation: none; border-top-color: var(--color-brand, #7c5cff); }
|
|
57
45
|
}
|
|
58
46
|
</style>
|
|
59
47
|
|
|
@@ -14,9 +14,10 @@
|
|
|
14
14
|
* choose its `object-fit` with your own classes, exactly as you would without
|
|
15
15
|
* this wrapper.
|
|
16
16
|
*
|
|
17
|
-
* The
|
|
18
|
-
*
|
|
19
|
-
* frame and faded out on load exactly
|
|
17
|
+
* The default placeholder is a plain `LoadingSpinner` (or a shimmer skeleton).
|
|
18
|
+
* Anything fancier belongs in the `placeholder` slot rather than in props —
|
|
19
|
+
* whatever you put there is centred in the frame and faded out on load exactly
|
|
20
|
+
* like the default.
|
|
20
21
|
*
|
|
21
22
|
* @example
|
|
22
23
|
* <ImageFade aspectRatio="16/9" rounded="rounded-2xl">
|
|
@@ -25,10 +26,12 @@
|
|
|
25
26
|
*
|
|
26
27
|
* @example Custom indicator
|
|
27
28
|
* <ImageFade aspectRatio="16/9">
|
|
28
|
-
* <
|
|
29
|
+
* <LoadingSpinner slot="placeholder" dual size="3rem" color="var(--brand)" />
|
|
29
30
|
* <Image src={hero} alt="…" />
|
|
30
31
|
* </ImageFade>
|
|
31
32
|
*/
|
|
33
|
+
import LoadingSpinner from './LoadingSpinner.astro';
|
|
34
|
+
|
|
32
35
|
interface Props {
|
|
33
36
|
/** Extra classes merged onto the wrapper. */
|
|
34
37
|
class?: string;
|
|
@@ -38,12 +41,8 @@ interface Props {
|
|
|
38
41
|
aspectRatio?: string;
|
|
39
42
|
/** Fade-in duration in ms. */
|
|
40
43
|
duration?: number;
|
|
41
|
-
/**
|
|
44
|
+
/** Accent for the default spinner, the skeleton shimmer and the wrapper tint. */
|
|
42
45
|
spinnerColor?: string;
|
|
43
|
-
/** Second accent, used by the counter-rotating inner ring (defaults to `spinnerColor`). */
|
|
44
|
-
spinnerColorSecondary?: string;
|
|
45
|
-
/** Outer ring diameter, any CSS length. */
|
|
46
|
-
spinnerSize?: string;
|
|
47
46
|
/** Wrapper background shown behind the image. Pass `"transparent"` for `object-contain` images. */
|
|
48
47
|
background?: string;
|
|
49
48
|
/** Show a shimmer skeleton instead of a spinner. */
|
|
@@ -56,8 +55,6 @@ const {
|
|
|
56
55
|
aspectRatio,
|
|
57
56
|
duration = 500,
|
|
58
57
|
spinnerColor,
|
|
59
|
-
spinnerColorSecondary,
|
|
60
|
-
spinnerSize,
|
|
61
58
|
background,
|
|
62
59
|
skeleton = false,
|
|
63
60
|
} = Astro.props;
|
|
@@ -65,8 +62,6 @@ const {
|
|
|
65
62
|
const style = [
|
|
66
63
|
aspectRatio ? `aspect-ratio:${aspectRatio}` : '',
|
|
67
64
|
spinnerColor ? `--if-accent:${spinnerColor}` : '',
|
|
68
|
-
spinnerColorSecondary ? `--if-accent-2:${spinnerColorSecondary}` : '',
|
|
69
|
-
spinnerSize ? `--if-size:${spinnerSize}` : '',
|
|
70
65
|
background ? `--if-bg:${background}` : '',
|
|
71
66
|
`--if-duration:${duration}ms`,
|
|
72
67
|
]
|
|
@@ -77,13 +72,7 @@ const style = [
|
|
|
77
72
|
<image-fade class:list={['image-fade', skeleton && 'is-skeleton', rounded, className]} style={style}>
|
|
78
73
|
<span class='image-fade__placeholder' aria-hidden='true'>
|
|
79
74
|
<slot name='placeholder'>
|
|
80
|
-
{
|
|
81
|
-
!skeleton && (
|
|
82
|
-
<span class='image-fade__ring'>
|
|
83
|
-
<span class='image-fade__ring-inner' />
|
|
84
|
-
</span>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
75
|
+
{!skeleton && <LoadingSpinner color={spinnerColor} />}
|
|
87
76
|
</slot>
|
|
88
77
|
</span>
|
|
89
78
|
<slot />
|
|
@@ -128,43 +117,6 @@ const style = [
|
|
|
128
117
|
opacity: 0;
|
|
129
118
|
}
|
|
130
119
|
|
|
131
|
-
.image-fade__ring {
|
|
132
|
-
position: relative;
|
|
133
|
-
display: block;
|
|
134
|
-
width: var(--if-size, 2.5rem);
|
|
135
|
-
height: var(--if-size, 2.5rem);
|
|
136
|
-
border: 3px solid transparent;
|
|
137
|
-
border-top-color: var(--if-accent, var(--color-brand, #7c5cff));
|
|
138
|
-
border-right-color: color-mix(
|
|
139
|
-
in oklab,
|
|
140
|
-
var(--if-accent, var(--color-brand, #7c5cff)) 50%,
|
|
141
|
-
transparent
|
|
142
|
-
);
|
|
143
|
-
border-radius: 50%;
|
|
144
|
-
/* `transform` is reset explicitly: a host page may set a base transform on
|
|
145
|
-
every element (e.g. a `* { transform: translateZ(0) }` GPU hint), which
|
|
146
|
-
would otherwise make the keyframes interpolate as matrices and cancel the
|
|
147
|
-
full turn out to no visible rotation. */
|
|
148
|
-
transform: rotate(0deg);
|
|
149
|
-
animation: image-fade-spin 1.2s linear infinite;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.image-fade__ring-inner {
|
|
153
|
-
position: absolute;
|
|
154
|
-
top: 50%;
|
|
155
|
-
left: 50%;
|
|
156
|
-
display: block;
|
|
157
|
-
width: 60%;
|
|
158
|
-
height: 60%;
|
|
159
|
-
margin: -30% 0 0 -30%;
|
|
160
|
-
border: 2px solid transparent;
|
|
161
|
-
border-top-color: var(--if-accent-2, var(--if-accent, var(--color-brand, #7c5cff)));
|
|
162
|
-
border-right-color: var(--if-accent-2, var(--if-accent, var(--color-brand, #7c5cff)));
|
|
163
|
-
border-radius: 50%;
|
|
164
|
-
transform: rotate(0deg);
|
|
165
|
-
animation: image-fade-spin 0.8s linear infinite reverse;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
120
|
/* Skeleton variant: shimmer sweep instead of a spinner */
|
|
169
121
|
image-fade.image-fade.is-skeleton .image-fade__placeholder {
|
|
170
122
|
background: linear-gradient(
|
|
@@ -177,36 +129,12 @@ const style = [
|
|
|
177
129
|
animation: image-fade-shimmer 1.4s ease-in-out infinite;
|
|
178
130
|
}
|
|
179
131
|
|
|
180
|
-
/* Both frames are explicit so the interpolation stays angular. An implicit
|
|
181
|
-
`from` would be taken from the element's computed transform, which is not
|
|
182
|
-
guaranteed to be `none` on every host page. */
|
|
183
|
-
@keyframes image-fade-spin {
|
|
184
|
-
from {
|
|
185
|
-
transform: rotate(0deg);
|
|
186
|
-
}
|
|
187
|
-
to {
|
|
188
|
-
transform: rotate(360deg);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
@keyframes image-fade-shimmer {
|
|
192
|
-
from {
|
|
193
|
-
background-position: 200% 0;
|
|
194
|
-
}
|
|
195
|
-
to {
|
|
196
|
-
background-position: -200% 0;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
132
|
@media (prefers-reduced-motion: reduce) {
|
|
201
133
|
image-fade.image-fade > img,
|
|
202
134
|
image-fade.image-fade > picture > img,
|
|
203
135
|
.image-fade__placeholder {
|
|
204
136
|
transition: none;
|
|
205
137
|
}
|
|
206
|
-
.image-fade__ring,
|
|
207
|
-
.image-fade__ring-inner {
|
|
208
|
-
animation: none;
|
|
209
|
-
}
|
|
210
138
|
image-fade.image-fade.is-skeleton .image-fade__placeholder {
|
|
211
139
|
animation: none;
|
|
212
140
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* LoadingSpinner — a plain rotating ring.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately unopinionated: one ring, brand colour, no flourish. Use it
|
|
6
|
+
* anywhere something is pending. `ClientRouterLoadingSpinner` and `ImageFade`
|
|
7
|
+
* both fall back to it, and both let you replace it via a slot.
|
|
8
|
+
*
|
|
9
|
+
* Set `dual` for a second, counter-rotating inner ring.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* <LoadingSpinner size="3rem" />
|
|
13
|
+
* <LoadingSpinner dual color="var(--brand)" colorSecondary="var(--brand-light)" />
|
|
14
|
+
*/
|
|
15
|
+
interface Props {
|
|
16
|
+
/** Outer ring diameter, any CSS length. */
|
|
17
|
+
size?: string;
|
|
18
|
+
/** Ring colour (defaults to `--color-brand`). */
|
|
19
|
+
color?: string;
|
|
20
|
+
/** Inner ring colour when `dual` is set (defaults to `color`). */
|
|
21
|
+
colorSecondary?: string;
|
|
22
|
+
/** Seconds for one full outer rotation. */
|
|
23
|
+
speed?: number;
|
|
24
|
+
/** Add a counter-rotating inner ring. */
|
|
25
|
+
dual?: boolean;
|
|
26
|
+
/** Extra classes on the ring element. */
|
|
27
|
+
class?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const {
|
|
31
|
+
size,
|
|
32
|
+
color,
|
|
33
|
+
colorSecondary,
|
|
34
|
+
speed = 1,
|
|
35
|
+
dual = false,
|
|
36
|
+
class: className = '',
|
|
37
|
+
} = Astro.props;
|
|
38
|
+
|
|
39
|
+
const style = [
|
|
40
|
+
size ? `--ls-size:${size}` : '',
|
|
41
|
+
color ? `--ls-color:${color}` : '',
|
|
42
|
+
colorSecondary ? `--ls-color-2:${colorSecondary}` : '',
|
|
43
|
+
`--ls-speed:${speed}s`,
|
|
44
|
+
]
|
|
45
|
+
.filter(Boolean)
|
|
46
|
+
.join(';');
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
<span class:list={['loading-spinner-ring', className]} style={style} aria-hidden='true'>
|
|
50
|
+
{dual && <span class='loading-spinner-ring__inner' />}
|
|
51
|
+
</span>
|
|
52
|
+
|
|
53
|
+
<style is:global>
|
|
54
|
+
.loading-spinner-ring {
|
|
55
|
+
position: relative;
|
|
56
|
+
display: block;
|
|
57
|
+
width: var(--ls-size, 2.5rem);
|
|
58
|
+
height: var(--ls-size, 2.5rem);
|
|
59
|
+
border: 3px solid transparent;
|
|
60
|
+
border-top-color: var(--ls-color, var(--color-brand, #7c5cff));
|
|
61
|
+
border-right-color: color-mix(
|
|
62
|
+
in oklab,
|
|
63
|
+
var(--ls-color, var(--color-brand, #7c5cff)) 50%,
|
|
64
|
+
transparent
|
|
65
|
+
);
|
|
66
|
+
border-radius: 50%;
|
|
67
|
+
/* Reset explicitly: a host page may set a base transform on every element
|
|
68
|
+
(a `* { transform: translateZ(0) }` GPU hint is common), which would make
|
|
69
|
+
the keyframes interpolate as matrices and cancel the full turn out to no
|
|
70
|
+
visible rotation. */
|
|
71
|
+
transform: rotate(0deg);
|
|
72
|
+
animation: loading-spinner-spin var(--ls-speed, 1s) linear infinite;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.loading-spinner-ring__inner {
|
|
76
|
+
position: absolute;
|
|
77
|
+
top: 50%;
|
|
78
|
+
left: 50%;
|
|
79
|
+
display: block;
|
|
80
|
+
width: 60%;
|
|
81
|
+
height: 60%;
|
|
82
|
+
margin: -30% 0 0 -30%;
|
|
83
|
+
border: 2px solid transparent;
|
|
84
|
+
border-top-color: var(--ls-color-2, var(--ls-color, var(--color-brand, #7c5cff)));
|
|
85
|
+
border-right-color: var(--ls-color-2, var(--ls-color, var(--color-brand, #7c5cff)));
|
|
86
|
+
border-radius: 50%;
|
|
87
|
+
transform: rotate(0deg);
|
|
88
|
+
animation: loading-spinner-spin calc(var(--ls-speed, 1s) * 0.7) linear infinite reverse;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Both frames are explicit so the interpolation stays angular. An implicit
|
|
92
|
+
`from` would be taken from the element's computed transform, which is not
|
|
93
|
+
guaranteed to be `none` on every host page. */
|
|
94
|
+
@keyframes loading-spinner-spin {
|
|
95
|
+
from {
|
|
96
|
+
transform: rotate(0deg);
|
|
97
|
+
}
|
|
98
|
+
to {
|
|
99
|
+
transform: rotate(360deg);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@media (prefers-reduced-motion: reduce) {
|
|
104
|
+
.loading-spinner-ring,
|
|
105
|
+
.loading-spinner-ring__inner {
|
|
106
|
+
animation: none;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
</style>
|