@at-flux/astroflare 1.0.12 → 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,11 +14,24 @@
|
|
|
14
14
|
* choose its `object-fit` with your own classes, exactly as you would without
|
|
15
15
|
* this wrapper.
|
|
16
16
|
*
|
|
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.
|
|
21
|
+
*
|
|
17
22
|
* @example
|
|
18
23
|
* <ImageFade aspectRatio="16/9" rounded="rounded-2xl">
|
|
19
24
|
* <Image src={hero} alt="…" />
|
|
20
25
|
* </ImageFade>
|
|
26
|
+
*
|
|
27
|
+
* @example Custom indicator
|
|
28
|
+
* <ImageFade aspectRatio="16/9">
|
|
29
|
+
* <LoadingSpinner slot="placeholder" dual size="3rem" color="var(--brand)" />
|
|
30
|
+
* <Image src={hero} alt="…" />
|
|
31
|
+
* </ImageFade>
|
|
21
32
|
*/
|
|
33
|
+
import LoadingSpinner from './LoadingSpinner.astro';
|
|
34
|
+
|
|
22
35
|
interface Props {
|
|
23
36
|
/** Extra classes merged onto the wrapper. */
|
|
24
37
|
class?: string;
|
|
@@ -28,12 +41,8 @@ interface Props {
|
|
|
28
41
|
aspectRatio?: string;
|
|
29
42
|
/** Fade-in duration in ms. */
|
|
30
43
|
duration?: number;
|
|
31
|
-
/**
|
|
44
|
+
/** Accent for the default spinner, the skeleton shimmer and the wrapper tint. */
|
|
32
45
|
spinnerColor?: string;
|
|
33
|
-
/** Second accent, used by the counter-rotating inner ring (defaults to `spinnerColor`). */
|
|
34
|
-
spinnerColorSecondary?: string;
|
|
35
|
-
/** Outer ring diameter, any CSS length. */
|
|
36
|
-
spinnerSize?: string;
|
|
37
46
|
/** Wrapper background shown behind the image. Pass `"transparent"` for `object-contain` images. */
|
|
38
47
|
background?: string;
|
|
39
48
|
/** Show a shimmer skeleton instead of a spinner. */
|
|
@@ -46,8 +55,6 @@ const {
|
|
|
46
55
|
aspectRatio,
|
|
47
56
|
duration = 500,
|
|
48
57
|
spinnerColor,
|
|
49
|
-
spinnerColorSecondary,
|
|
50
|
-
spinnerSize,
|
|
51
58
|
background,
|
|
52
59
|
skeleton = false,
|
|
53
60
|
} = Astro.props;
|
|
@@ -55,8 +62,6 @@ const {
|
|
|
55
62
|
const style = [
|
|
56
63
|
aspectRatio ? `aspect-ratio:${aspectRatio}` : '',
|
|
57
64
|
spinnerColor ? `--if-accent:${spinnerColor}` : '',
|
|
58
|
-
spinnerColorSecondary ? `--if-accent-2:${spinnerColorSecondary}` : '',
|
|
59
|
-
spinnerSize ? `--if-size:${spinnerSize}` : '',
|
|
60
65
|
background ? `--if-bg:${background}` : '',
|
|
61
66
|
`--if-duration:${duration}ms`,
|
|
62
67
|
]
|
|
@@ -66,13 +71,9 @@ const style = [
|
|
|
66
71
|
|
|
67
72
|
<image-fade class:list={['image-fade', skeleton && 'is-skeleton', rounded, className]} style={style}>
|
|
68
73
|
<span class='image-fade__placeholder' aria-hidden='true'>
|
|
69
|
-
|
|
70
|
-
!skeleton &&
|
|
71
|
-
|
|
72
|
-
<span class='image-fade__ring-inner' />
|
|
73
|
-
</span>
|
|
74
|
-
)
|
|
75
|
-
}
|
|
74
|
+
<slot name='placeholder'>
|
|
75
|
+
{!skeleton && <LoadingSpinner color={spinnerColor} />}
|
|
76
|
+
</slot>
|
|
76
77
|
</span>
|
|
77
78
|
<slot />
|
|
78
79
|
</image-fade>
|
|
@@ -116,43 +117,6 @@ const style = [
|
|
|
116
117
|
opacity: 0;
|
|
117
118
|
}
|
|
118
119
|
|
|
119
|
-
.image-fade__ring {
|
|
120
|
-
position: relative;
|
|
121
|
-
display: block;
|
|
122
|
-
width: var(--if-size, 2.5rem);
|
|
123
|
-
height: var(--if-size, 2.5rem);
|
|
124
|
-
border: 3px solid transparent;
|
|
125
|
-
border-top-color: var(--if-accent, var(--color-brand, #7c5cff));
|
|
126
|
-
border-right-color: color-mix(
|
|
127
|
-
in oklab,
|
|
128
|
-
var(--if-accent, var(--color-brand, #7c5cff)) 50%,
|
|
129
|
-
transparent
|
|
130
|
-
);
|
|
131
|
-
border-radius: 50%;
|
|
132
|
-
/* `transform` is reset explicitly: a host page may set a base transform on
|
|
133
|
-
every element (e.g. a `* { transform: translateZ(0) }` GPU hint), which
|
|
134
|
-
would otherwise make the keyframes interpolate as matrices and cancel the
|
|
135
|
-
full turn out to no visible rotation. */
|
|
136
|
-
transform: rotate(0deg);
|
|
137
|
-
animation: image-fade-spin 1.2s linear infinite;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
.image-fade__ring-inner {
|
|
141
|
-
position: absolute;
|
|
142
|
-
top: 50%;
|
|
143
|
-
left: 50%;
|
|
144
|
-
display: block;
|
|
145
|
-
width: 60%;
|
|
146
|
-
height: 60%;
|
|
147
|
-
margin: -30% 0 0 -30%;
|
|
148
|
-
border: 2px solid transparent;
|
|
149
|
-
border-top-color: var(--if-accent-2, var(--if-accent, var(--color-brand, #7c5cff)));
|
|
150
|
-
border-right-color: var(--if-accent-2, var(--if-accent, var(--color-brand, #7c5cff)));
|
|
151
|
-
border-radius: 50%;
|
|
152
|
-
transform: rotate(0deg);
|
|
153
|
-
animation: image-fade-spin 0.8s linear infinite reverse;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
120
|
/* Skeleton variant: shimmer sweep instead of a spinner */
|
|
157
121
|
image-fade.image-fade.is-skeleton .image-fade__placeholder {
|
|
158
122
|
background: linear-gradient(
|
|
@@ -165,36 +129,12 @@ const style = [
|
|
|
165
129
|
animation: image-fade-shimmer 1.4s ease-in-out infinite;
|
|
166
130
|
}
|
|
167
131
|
|
|
168
|
-
/* Both frames are explicit so the interpolation stays angular. An implicit
|
|
169
|
-
`from` would be taken from the element's computed transform, which is not
|
|
170
|
-
guaranteed to be `none` on every host page. */
|
|
171
|
-
@keyframes image-fade-spin {
|
|
172
|
-
from {
|
|
173
|
-
transform: rotate(0deg);
|
|
174
|
-
}
|
|
175
|
-
to {
|
|
176
|
-
transform: rotate(360deg);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
@keyframes image-fade-shimmer {
|
|
180
|
-
from {
|
|
181
|
-
background-position: 200% 0;
|
|
182
|
-
}
|
|
183
|
-
to {
|
|
184
|
-
background-position: -200% 0;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
132
|
@media (prefers-reduced-motion: reduce) {
|
|
189
133
|
image-fade.image-fade > img,
|
|
190
134
|
image-fade.image-fade > picture > img,
|
|
191
135
|
.image-fade__placeholder {
|
|
192
136
|
transition: none;
|
|
193
137
|
}
|
|
194
|
-
.image-fade__ring,
|
|
195
|
-
.image-fade__ring-inner {
|
|
196
|
-
animation: none;
|
|
197
|
-
}
|
|
198
138
|
image-fade.image-fade.is-skeleton .image-fade__placeholder {
|
|
199
139
|
animation: none;
|
|
200
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>
|