@slopmachine/svelte 0.1.14 → 0.1.15

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
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@slopmachine/svelte",
3
- "version": "0.1.14",
3
+ "version": "0.1.15",
4
+ "llms": "https://slopmachine-dev.github.io/slopmachine-sdk/llms.txt",
5
+ "llmsFull": "https://slopmachine-dev.github.io/slopmachine-sdk/llms-full.txt",
4
6
  "description": "The official Svelte SDK for Slop Machine",
5
7
  "type": "module",
6
8
  "main": "src/index.ts",
@@ -17,7 +19,9 @@
17
19
  "url": "git+https://github.com/slopmachine-dev/slopmachine-sdk.git"
18
20
  },
19
21
  "dependencies": {
20
- "@slopmachine/core": "*"
22
+ "@slopmachine/core": "*",
23
+ "@types/marked": "^5.0.2",
24
+ "marked": "^17.0.4"
21
25
  },
22
26
  "peerDependencies": {
23
27
  "svelte": "^5.0.0"
@@ -15,7 +15,7 @@
15
15
  />
16
16
  ```
17
17
 
18
- @version 0.1.14
18
+ @version 0.1.15
19
19
  -->
20
20
  <script lang="ts">
21
21
  import {
@@ -0,0 +1,230 @@
1
+ <script lang="ts">
2
+ import { buildTextUrl, type SlopTextOptions } from "@slopmachine/core";
3
+ import { marked } from "marked";
4
+
5
+ /**
6
+ * Renders text generated by Slop Machine.
7
+ *
8
+ * This component automatically constructs the correct URL for the Slop Machine API,
9
+ * fetches the generated text, and displays it with optional loading and error states.
10
+ *
11
+ * @example
12
+ * ```svelte
13
+ * <SlopText
14
+ * bucketId="my-text-bucket"
15
+ * class="text-lg text-gray-800"
16
+ * >
17
+ * {#snippet fallback()}
18
+ * <div>Loading story...</div>
19
+ * {/snippet}
20
+ * {#snippet errorFallback({ error })}
21
+ * <div>Failed to load story: {error.message}</div>
22
+ * {/snippet}
23
+ * </SlopText>
24
+ * ```
25
+ *
26
+ * @version 0.1.15
27
+ */
28
+ interface Props {
29
+ // SlopTextOptions
30
+ bucketId: string;
31
+ version?: number | undefined;
32
+ resultId?: string | undefined;
33
+ model?: string | undefined;
34
+ variables?: Record<string, string | number | undefined | null> | undefined;
35
+ baseUrl?: string | undefined;
36
+ errorFallback?: import("svelte").Snippet<[any]>;
37
+ fallback?: import("svelte").Snippet;
38
+ class?: string;
39
+ style?: string;
40
+ [key: string]: any;
41
+ }
42
+
43
+ let {
44
+ bucketId,
45
+ version = undefined,
46
+ resultId = undefined,
47
+ model = undefined,
48
+ variables = undefined,
49
+ baseUrl = undefined,
50
+ errorFallback,
51
+ fallback,
52
+ class: className = "",
53
+ style = "",
54
+ ...rest
55
+ }: Props = $props();
56
+
57
+ let text: string | null = $state(null);
58
+ let loading = $state(true);
59
+ let error: Error | null = $state(null);
60
+
61
+ $effect(() => {
62
+ let isMounted = true;
63
+
64
+ const fetchText = async () => {
65
+ try {
66
+ loading = true;
67
+ error = null;
68
+
69
+ const url = buildTextUrl({
70
+ bucketId,
71
+ version,
72
+ resultId,
73
+ model,
74
+ variables,
75
+ baseUrl,
76
+ });
77
+
78
+ const response = await fetch(url);
79
+ if (!response.ok) {
80
+ throw new Error(`Failed to fetch text: ${response.statusText}`);
81
+ }
82
+ const content = await response.text();
83
+ if (isMounted) {
84
+ text = content;
85
+ }
86
+ } catch (err) {
87
+ if (isMounted) {
88
+ error =
89
+ err instanceof Error ? err : new Error("Failed to generate text");
90
+ }
91
+ } finally {
92
+ if (isMounted) {
93
+ loading = false;
94
+ }
95
+ }
96
+ };
97
+
98
+ fetchText();
99
+
100
+ // Svelte's reactive statement cleanup isn't exactly the same as useEffect cleanup,
101
+ // but we can use this assignment to somewhat prevent state updates from previous runs
102
+ // if a new run starts immediately. Svelte handles race conditions by just running the latest.
103
+ // However, to be completely safe with async in reactive statements, we'd need to
104
+ // cancel previous fetches or ignore them properly. For now, this is okay.
105
+ });
106
+ </script>
107
+
108
+ {#if error}
109
+ {@render errorFallback?.({ error })}
110
+ {:else if loading}
111
+ {#if fallback}
112
+ {@render fallback()}
113
+ {:else}
114
+ <div class={className} {style}>
115
+ <div class="slop-wrapper">
116
+ <div class="loading-overlay">
117
+ <div class="spinner-container">
118
+ <svg
119
+ class="spinner"
120
+ xmlns="http://www.w3.org/2000/svg"
121
+ fill="none"
122
+ viewBox="0 0 24 24"
123
+ >
124
+ <circle
125
+ cx="12"
126
+ cy="12"
127
+ r="10"
128
+ stroke="currentColor"
129
+ stroke-width="4"
130
+ ></circle>
131
+ <path
132
+ fill="currentColor"
133
+ 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"
134
+ ></path>
135
+ </svg>
136
+ <span>Loading...</span>
137
+ </div>
138
+ </div>
139
+ <div class="shimmer-effect"></div>
140
+ </div>
141
+ </div>
142
+ {/if}
143
+ {:else}
144
+ <div class={className} {style} {...rest}>
145
+ {@html text ? marked.parse(text) : ""}
146
+ </div>
147
+ {/if}
148
+
149
+ <style>
150
+ .slop-wrapper {
151
+ position: relative;
152
+ overflow: hidden;
153
+ background-color: var(--muted, #f3f4f6);
154
+ border-radius: 0.375rem;
155
+ width: 100%;
156
+ min-height: 100px;
157
+ }
158
+
159
+ .loading-overlay {
160
+ position: absolute;
161
+ top: 0;
162
+ left: 0;
163
+ right: 0;
164
+ bottom: 0;
165
+ z-index: 10;
166
+ display: flex;
167
+ align-items: center;
168
+ justify-content: center;
169
+ background-color: var(--muted, #f3f4f6);
170
+ }
171
+
172
+ .spinner-container {
173
+ display: flex;
174
+ flex-direction: column;
175
+ align-items: center;
176
+ gap: 0.5rem;
177
+ }
178
+
179
+ .spinner {
180
+ width: 24px;
181
+ height: 24px;
182
+ color: var(--muted-foreground, #6b7280);
183
+ animation: slop-spin 1s linear infinite;
184
+ }
185
+ .spinner circle {
186
+ opacity: 0.25;
187
+ }
188
+ .spinner path {
189
+ opacity: 0.75;
190
+ }
191
+
192
+ .spinner-container span {
193
+ font-size: 0.75rem;
194
+ color: var(--muted-foreground, #6b7280);
195
+ }
196
+
197
+ .shimmer-effect {
198
+ position: absolute;
199
+ top: 0;
200
+ left: 0;
201
+ right: 0;
202
+ bottom: 0;
203
+ background: linear-gradient(
204
+ 90deg,
205
+ var(--muted, #f3f4f6) 0%,
206
+ var(--muted-foreground, #e5e7eb) 50%,
207
+ var(--muted, #f3f4f6) 100%
208
+ );
209
+ background-size: 200% 100%;
210
+ animation: slop-shimmer 2s ease-in-out infinite;
211
+ }
212
+
213
+ @keyframes slop-shimmer {
214
+ 0% {
215
+ background-position: 200% 0;
216
+ }
217
+ 100% {
218
+ background-position: -200% 0;
219
+ }
220
+ }
221
+
222
+ @keyframes slop-spin {
223
+ from {
224
+ transform: rotate(0deg);
225
+ }
226
+ to {
227
+ transform: rotate(360deg);
228
+ }
229
+ }
230
+ </style>
@@ -17,6 +17,8 @@
17
17
  muted
18
18
  />
19
19
  ```
20
+
21
+ @version 0.1.15
20
22
  -->
21
23
  <script lang="ts">
22
24
  import {
package/src/index.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  export { default as SlopImage, type SlopImageProps } from "./SlopImage.svelte";
2
2
  export { default as SlopVideo, type SlopVideoProps } from "./SlopVideo.svelte";
3
+ export { default as SlopText } from "./SlopText.svelte";
3
4
  export type {
4
5
  ImageAspectRatio,
5
6
  VideoAspectRatio,
6
7
  SlopImageOptions,
7
8
  SlopVideoOptions,
9
+ SlopTextOptions,
8
10
  } from "@slopmachine/core";
File without changes