@slopmachine/svelte 0.1.1 → 0.1.3
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 +1 -1
- package/src/SlopImage.svelte +73 -22
package/package.json
CHANGED
package/src/SlopImage.svelte
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { buildImageUrl,
|
|
2
|
+
import { buildImageUrl, type SlopImageOptions } from "@slopmachine/core";
|
|
3
3
|
|
|
4
|
-
interface Props extends
|
|
4
|
+
interface Props extends SlopImageOptions {
|
|
5
5
|
class?: string;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
let {
|
|
9
9
|
bucketId,
|
|
10
|
-
prompt,
|
|
11
10
|
aspectRatio = "1:1",
|
|
11
|
+
version,
|
|
12
|
+
resultId,
|
|
12
13
|
model,
|
|
13
14
|
variables = {},
|
|
14
15
|
baseUrl = undefined,
|
|
@@ -18,9 +19,31 @@
|
|
|
18
19
|
|
|
19
20
|
let isLoading = $state(true);
|
|
20
21
|
|
|
21
|
-
let
|
|
22
|
+
let computedSrc = $derived(
|
|
23
|
+
buildImageUrl({
|
|
24
|
+
bucketId,
|
|
25
|
+
aspectRatio,
|
|
26
|
+
version,
|
|
27
|
+
resultId,
|
|
28
|
+
variables,
|
|
29
|
+
baseUrl,
|
|
30
|
+
model,
|
|
31
|
+
}),
|
|
32
|
+
);
|
|
33
|
+
let src = $state("");
|
|
22
34
|
let prevSrc = $state("");
|
|
23
|
-
let alt =
|
|
35
|
+
let alt = "Generated image";
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
const currentComputedSrc = computedSrc;
|
|
39
|
+
const timeout = setTimeout(() => {
|
|
40
|
+
if (src !== currentComputedSrc) {
|
|
41
|
+
src = currentComputedSrc;
|
|
42
|
+
}
|
|
43
|
+
}, 50);
|
|
44
|
+
|
|
45
|
+
return () => clearTimeout(timeout);
|
|
46
|
+
});
|
|
24
47
|
|
|
25
48
|
$effect(() => {
|
|
26
49
|
if (src !== prevSrc) {
|
|
@@ -31,24 +54,33 @@
|
|
|
31
54
|
|
|
32
55
|
$effect(() => {
|
|
33
56
|
if (src) {
|
|
34
|
-
|
|
57
|
+
const abortController = new AbortController();
|
|
58
|
+
fetch(src, { method: "HEAD", signal: abortController.signal })
|
|
35
59
|
.then(async (res) => {
|
|
36
60
|
if (!res.ok) {
|
|
37
61
|
// console.error(`Failed to load image from ${src}. Status: ${res.status} ${res.statusText}`);
|
|
38
62
|
try {
|
|
39
|
-
const errRes = await fetch(src
|
|
63
|
+
const errRes = await fetch(src, {
|
|
64
|
+
signal: abortController.signal,
|
|
65
|
+
});
|
|
40
66
|
const errJson = await errRes.json();
|
|
41
|
-
console.error("SlopImage error:",res.status, errJson.error);
|
|
42
|
-
} catch (e) {
|
|
43
|
-
|
|
67
|
+
console.error("SlopImage error:", res.status, errJson.error);
|
|
68
|
+
} catch (e: any) {
|
|
69
|
+
if (e.name !== "AbortError") {
|
|
70
|
+
// Failed to fetch or parse error details
|
|
71
|
+
}
|
|
44
72
|
}
|
|
45
73
|
isLoading = false;
|
|
46
74
|
}
|
|
47
75
|
})
|
|
48
76
|
.catch((err) => {
|
|
49
|
-
|
|
50
|
-
|
|
77
|
+
if (err.name !== "AbortError") {
|
|
78
|
+
console.error(`Error fetching image from ${src}:`, err);
|
|
79
|
+
isLoading = false;
|
|
80
|
+
}
|
|
51
81
|
});
|
|
82
|
+
|
|
83
|
+
return () => abortController.abort();
|
|
52
84
|
}
|
|
53
85
|
});
|
|
54
86
|
|
|
@@ -74,7 +106,8 @@
|
|
|
74
106
|
fill="none"
|
|
75
107
|
viewBox="0 0 24 24"
|
|
76
108
|
>
|
|
77
|
-
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"
|
|
109
|
+
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"
|
|
110
|
+
></circle>
|
|
78
111
|
<path
|
|
79
112
|
fill="currentColor"
|
|
80
113
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
@@ -107,7 +140,10 @@
|
|
|
107
140
|
|
|
108
141
|
.loading-overlay {
|
|
109
142
|
position: absolute;
|
|
110
|
-
top: 0;
|
|
143
|
+
top: 0;
|
|
144
|
+
left: 0;
|
|
145
|
+
right: 0;
|
|
146
|
+
bottom: 0;
|
|
111
147
|
z-index: 10;
|
|
112
148
|
display: flex;
|
|
113
149
|
align-items: center;
|
|
@@ -129,8 +165,12 @@
|
|
|
129
165
|
color: var(--muted-foreground, #6b7280);
|
|
130
166
|
animation: slop-spin 1s linear infinite;
|
|
131
167
|
}
|
|
132
|
-
.spinner circle {
|
|
133
|
-
|
|
168
|
+
.spinner circle {
|
|
169
|
+
opacity: 0.25;
|
|
170
|
+
}
|
|
171
|
+
.spinner path {
|
|
172
|
+
opacity: 0.75;
|
|
173
|
+
}
|
|
134
174
|
|
|
135
175
|
.spinner-container span {
|
|
136
176
|
font-size: 0.75rem;
|
|
@@ -139,7 +179,10 @@
|
|
|
139
179
|
|
|
140
180
|
.shimmer-effect {
|
|
141
181
|
position: absolute;
|
|
142
|
-
top: 0;
|
|
182
|
+
top: 0;
|
|
183
|
+
left: 0;
|
|
184
|
+
right: 0;
|
|
185
|
+
bottom: 0;
|
|
143
186
|
background: linear-gradient(
|
|
144
187
|
90deg,
|
|
145
188
|
var(--muted, #f3f4f6) 0%,
|
|
@@ -163,12 +206,20 @@
|
|
|
163
206
|
}
|
|
164
207
|
|
|
165
208
|
@keyframes slop-shimmer {
|
|
166
|
-
0% {
|
|
167
|
-
|
|
209
|
+
0% {
|
|
210
|
+
background-position: 200% 0;
|
|
211
|
+
}
|
|
212
|
+
100% {
|
|
213
|
+
background-position: -200% 0;
|
|
214
|
+
}
|
|
168
215
|
}
|
|
169
216
|
|
|
170
217
|
@keyframes slop-spin {
|
|
171
|
-
from {
|
|
172
|
-
|
|
218
|
+
from {
|
|
219
|
+
transform: rotate(0deg);
|
|
220
|
+
}
|
|
221
|
+
to {
|
|
222
|
+
transform: rotate(360deg);
|
|
223
|
+
}
|
|
173
224
|
}
|
|
174
|
-
</style>
|
|
225
|
+
</style>
|