@farming-labs/svelte-theme 0.0.2-beta.23 → 0.0.2-beta.24

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,6 @@
1
1
  {
2
2
  "name": "@farming-labs/svelte-theme",
3
- "version": "0.0.2-beta.23",
3
+ "version": "0.0.2-beta.24",
4
4
  "description": "Svelte UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "docs",
@@ -72,8 +72,8 @@
72
72
  "dependencies": {
73
73
  "gray-matter": "^4.0.3",
74
74
  "sugar-high": "^0.9.5",
75
- "@farming-labs/docs": "0.0.2-beta.23",
76
- "@farming-labs/svelte": "0.0.2-beta.23"
75
+ "@farming-labs/docs": "0.0.2-beta.24",
76
+ "@farming-labs/svelte": "0.0.2-beta.24"
77
77
  },
78
78
  "peerDependencies": {
79
79
  "svelte": ">=5.0.0"
@@ -213,10 +213,10 @@
213
213
  onkeydown={handleSearchKeydown}
214
214
  />
215
215
  {#if isSearching}
216
- <span class="fd-ai-loading-dots">
217
- <span class="fd-ai-loading-dot"></span>
218
- <span class="fd-ai-loading-dot"></span>
219
- <span class="fd-ai-loading-dot"></span>
216
+ <span class="fd-ai-loader-typing-dots" style="margin-left:0">
217
+ <span class="fd-ai-loader-typing-dot"></span>
218
+ <span class="fd-ai-loader-typing-dot"></span>
219
+ <span class="fd-ai-loader-typing-dot"></span>
220
220
  </span>
221
221
  {/if}
222
222
  </div>
@@ -276,7 +276,7 @@
276
276
  {/if}
277
277
  </div>
278
278
  {:else}
279
- {#each messages as msg}
279
+ {#each messages as msg, i}
280
280
  <div class="fd-ai-msg" data-role={msg.role}>
281
281
  <div class="fd-ai-msg-label">
282
282
  {msg.role === "user" ? "You" : aiLabel}
@@ -286,16 +286,18 @@
286
286
  {:else}
287
287
  <div class="fd-ai-bubble-ai">
288
288
  {#if msg.content}
289
- {@html renderMarkdown(msg.content)}
289
+ <div class={isStreaming && i === messages.length - 1 ? 'fd-ai-streaming' : ''}>
290
+ {@html renderMarkdown(msg.content)}
291
+ </div>
290
292
  {:else}
291
- <span class="fd-ai-loading">
292
- <span class="fd-ai-loading-text">{aiLabel} is thinking</span>
293
- <span class="fd-ai-loading-dots">
294
- <span class="fd-ai-loading-dot"></span>
295
- <span class="fd-ai-loading-dot"></span>
296
- <span class="fd-ai-loading-dot"></span>
293
+ <div class="fd-ai-loader">
294
+ <span class="fd-ai-loader-shimmer-text">Thinking</span>
295
+ <span class="fd-ai-loader-typing-dots">
296
+ <span class="fd-ai-loader-typing-dot"></span>
297
+ <span class="fd-ai-loader-typing-dot"></span>
298
+ <span class="fd-ai-loader-typing-dot"></span>
297
299
  </span>
298
- </span>
300
+ </div>
299
301
  {/if}
300
302
  </div>
301
303
  {/if}
@@ -226,19 +226,24 @@
226
226
  <!-- Scrollable message list -->
227
227
  <div bind:this={fmListEl} class="fd-ai-fm-messages">
228
228
  <div class="fd-ai-fm-messages-inner">
229
- {#each messages as msg}
229
+ {#each messages as msg, i}
230
230
  <div class="fd-ai-fm-msg" data-role={msg.role}>
231
231
  <div class="fd-ai-fm-msg-label" data-role={msg.role}>
232
232
  {msg.role === "user" ? "you" : label}
233
233
  </div>
234
234
  <div class="fd-ai-fm-msg-content">
235
235
  {#if msg.content}
236
- {@html renderMarkdown(msg.content)}
236
+ <div class={isStreaming && i === messages.length - 1 && msg.role === 'assistant' ? 'fd-ai-streaming' : ''}>
237
+ {@html renderMarkdown(msg.content)}
238
+ </div>
237
239
  {:else}
238
- <div class="fd-ai-fm-thinking">
239
- <span class="fd-ai-fm-thinking-dot"></span>
240
- <span class="fd-ai-fm-thinking-dot"></span>
241
- <span class="fd-ai-fm-thinking-dot"></span>
240
+ <div class="fd-ai-loader">
241
+ <span class="fd-ai-loader-shimmer-text">Thinking</span>
242
+ <span class="fd-ai-loader-typing-dots">
243
+ <span class="fd-ai-loader-typing-dot"></span>
244
+ <span class="fd-ai-loader-typing-dot"></span>
245
+ <span class="fd-ai-loader-typing-dot"></span>
246
+ </span>
242
247
  </div>
243
248
  {/if}
244
249
  </div>
@@ -292,10 +297,10 @@
292
297
  ></textarea>
293
298
  {#if isStreaming}
294
299
  <button class="fd-ai-fm-send-btn" onclick={() => isStreaming = false} aria-label="Stop">
295
- <span class="fd-ai-loading-dots">
296
- <span class="fd-ai-loading-dot"></span>
297
- <span class="fd-ai-loading-dot"></span>
298
- <span class="fd-ai-loading-dot"></span>
300
+ <span class="fd-ai-loader-typing-dots" style="margin-left:0">
301
+ <span class="fd-ai-loader-typing-dot"></span>
302
+ <span class="fd-ai-loader-typing-dot"></span>
303
+ <span class="fd-ai-loader-typing-dot"></span>
299
304
  </span>
300
305
  </button>
301
306
  {:else}
@@ -407,7 +412,7 @@
407
412
  {/if}
408
413
  </div>
409
414
  {:else}
410
- {#each messages as msg}
415
+ {#each messages as msg, i}
411
416
  <div class="fd-ai-msg" data-role={msg.role}>
412
417
  <div class="fd-ai-msg-label">
413
418
  {msg.role === "user" ? "You" : label}
@@ -417,16 +422,18 @@
417
422
  {:else}
418
423
  <div class="fd-ai-bubble-ai">
419
424
  {#if msg.content}
420
- {@html renderMarkdown(msg.content)}
425
+ <div class={isStreaming && i === messages.length - 1 ? 'fd-ai-streaming' : ''}>
426
+ {@html renderMarkdown(msg.content)}
427
+ </div>
421
428
  {:else}
422
- <span class="fd-ai-loading">
423
- <span class="fd-ai-loading-text">{label} is thinking</span>
424
- <span class="fd-ai-loading-dots">
425
- <span class="fd-ai-loading-dot"></span>
426
- <span class="fd-ai-loading-dot"></span>
427
- <span class="fd-ai-loading-dot"></span>
429
+ <div class="fd-ai-loader">
430
+ <span class="fd-ai-loader-shimmer-text">Thinking</span>
431
+ <span class="fd-ai-loader-typing-dots">
432
+ <span class="fd-ai-loader-typing-dot"></span>
433
+ <span class="fd-ai-loader-typing-dot"></span>
434
+ <span class="fd-ai-loader-typing-dot"></span>
428
435
  </span>
429
- </span>
436
+ </div>
430
437
  {/if}
431
438
  </div>
432
439
  {/if}
package/styles/docs.css CHANGED
@@ -1329,19 +1329,6 @@ html.dark pre.shiki {
1329
1329
  * AI Chat & Search Dialog — base styles (fd-ai-*)
1330
1330
  * ═══════════════════════════════════════════════════════════════════════ */
1331
1331
 
1332
- @keyframes fd-ai-dot {
1333
- 0%,
1334
- 80%,
1335
- 100% {
1336
- transform: scale(0);
1337
- opacity: 0.5;
1338
- }
1339
- 40% {
1340
- transform: scale(1);
1341
- opacity: 1;
1342
- }
1343
- }
1344
-
1345
1332
  @keyframes fd-ai-fade-in {
1346
1333
  from {
1347
1334
  opacity: 0;
@@ -1693,6 +1680,12 @@ html.dark pre.shiki {
1693
1680
  line-height: 1.6;
1694
1681
  max-width: 95%;
1695
1682
  word-break: break-word;
1683
+ animation: fd-ai-msg-in 300ms ease-out;
1684
+ }
1685
+
1686
+ @keyframes fd-ai-msg-in {
1687
+ from { opacity: 0; transform: translateY(6px); }
1688
+ to { opacity: 1; transform: translateY(0); }
1696
1689
  }
1697
1690
 
1698
1691
  .fd-ai-chat-footer {
@@ -1745,36 +1738,70 @@ html.dark pre.shiki {
1745
1738
  color: var(--color-fd-primary-foreground);
1746
1739
  }
1747
1740
 
1748
- .fd-ai-loading {
1741
+ .fd-ai-loader {
1749
1742
  display: inline-flex;
1750
- gap: 6px;
1751
1743
  align-items: center;
1744
+ gap: 6px;
1745
+ animation: fd-ai-loader-in 300ms ease-out;
1752
1746
  }
1753
1747
 
1754
- .fd-ai-loading-text {
1755
- font-size: 12px;
1756
- color: var(--color-fd-muted-foreground);
1748
+ @keyframes fd-ai-loader-in {
1749
+ from { opacity: 0; transform: translateY(4px); }
1750
+ to { opacity: 1; transform: translateY(0); }
1757
1751
  }
1758
1752
 
1759
- .fd-ai-loading-dots {
1753
+ .fd-ai-loader-shimmer-text {
1754
+ font-size: 13px;
1755
+ font-weight: 500;
1756
+ background: linear-gradient(to right, var(--color-fd-muted-foreground, #888) 40%, var(--color-fd-foreground, #fff) 60%, var(--color-fd-muted-foreground, #888) 80%);
1757
+ background-size: 200% auto;
1758
+ background-clip: text;
1759
+ -webkit-background-clip: text;
1760
+ color: transparent;
1761
+ animation: fd-ai-shimmer-text 3s linear infinite;
1762
+ }
1763
+
1764
+ @keyframes fd-ai-shimmer-text {
1765
+ 0% { background-position: 150% center; }
1766
+ 100% { background-position: -150% center; }
1767
+ }
1768
+
1769
+ .fd-ai-loader-typing-dots {
1760
1770
  display: inline-flex;
1761
- gap: 3px;
1762
1771
  align-items: center;
1772
+ gap: 2px;
1763
1773
  }
1764
1774
 
1765
- .fd-ai-loading-dot {
1766
- width: 5px;
1767
- height: 5px;
1775
+ .fd-ai-loader-typing-dot {
1776
+ width: 4px;
1777
+ height: 4px;
1768
1778
  border-radius: 50%;
1769
- background: var(--color-fd-muted-foreground);
1770
- animation: fd-ai-dot 1.4s infinite ease-in-out both;
1779
+ background: var(--color-fd-primary, #6366f1);
1780
+ animation: fd-ai-typing 1s infinite;
1781
+ }
1782
+
1783
+ .fd-ai-loader-typing-dot:nth-child(2) { animation-delay: 250ms; }
1784
+ .fd-ai-loader-typing-dot:nth-child(3) { animation-delay: 500ms; }
1785
+
1786
+ @keyframes fd-ai-typing {
1787
+ 0%, 100% { transform: translateY(0); opacity: 0.5; }
1788
+ 50% { transform: translateY(-2px); opacity: 1; }
1771
1789
  }
1772
1790
 
1773
- .fd-ai-loading-dot:nth-child(2) {
1774
- animation-delay: 0.16s;
1791
+ .fd-ai-streaming::after {
1792
+ content: "";
1793
+ display: inline-block;
1794
+ width: 2px;
1795
+ height: 1em;
1796
+ background: var(--color-fd-primary, #6366f1);
1797
+ margin-left: 2px;
1798
+ vertical-align: text-bottom;
1799
+ animation: fd-ai-cursor-blink 0.8s step-end infinite;
1775
1800
  }
1776
- .fd-ai-loading-dot:nth-child(3) {
1777
- animation-delay: 0.32s;
1801
+
1802
+ @keyframes fd-ai-cursor-blink {
1803
+ 0%, 100% { opacity: 1; }
1804
+ 50% { opacity: 0; }
1778
1805
  }
1779
1806
 
1780
1807
  /* ─── Markdown in AI responses ───────────────────────────────── */
@@ -2161,41 +2188,7 @@ html.dark pre.shiki {
2161
2188
  font-size: 12px;
2162
2189
  }
2163
2190
 
2164
- /* ─── Thinking dots ──────────────────────────────────────────── */
2165
-
2166
- .fd-ai-fm-thinking {
2167
- display: flex;
2168
- gap: 4px;
2169
- align-items: center;
2170
- }
2171
-
2172
- .fd-ai-fm-thinking-dot {
2173
- width: 6px;
2174
- height: 6px;
2175
- border-radius: 9999px;
2176
- background: var(--color-fd-primary, #6366f1);
2177
- animation: fd-ai-fm-bounce 1s infinite ease-in-out;
2178
- }
2179
-
2180
- .fd-ai-fm-thinking-dot:nth-child(2) {
2181
- animation-delay: 150ms;
2182
- }
2183
- .fd-ai-fm-thinking-dot:nth-child(3) {
2184
- animation-delay: 300ms;
2185
- }
2186
-
2187
- @keyframes fd-ai-fm-bounce {
2188
- 0%,
2189
- 80%,
2190
- 100% {
2191
- transform: scale(0.6);
2192
- opacity: 0.4;
2193
- }
2194
- 40% {
2195
- transform: scale(1);
2196
- opacity: 1;
2197
- }
2198
- }
2191
+ /* Full-modal now uses the shared .fd-ai-loader indicator */
2199
2192
 
2200
2193
  /* ─── Bottom input bar ───────────────────────────────────────── */
2201
2194
 
@@ -477,13 +477,13 @@
477
477
  letter-spacing: 0.06em;
478
478
  }
479
479
 
480
- .fd-ai-loading-text {
480
+ .fd-ai-loader-shimmer-text {
481
481
  text-transform: uppercase;
482
482
  letter-spacing: 0.04em;
483
483
  font-size: 11px;
484
484
  }
485
485
 
486
- .fd-ai-loading-dot {
486
+ .fd-ai-loader-typing-dot {
487
487
  border-radius: 0;
488
488
  width: 4px;
489
489
  height: 4px;
@@ -561,11 +561,7 @@
561
561
  font-size: 11px;
562
562
  }
563
563
 
564
- .fd-ai-fm-thinking-dot {
565
- border-radius: 0;
566
- width: 5px;
567
- height: 5px;
568
- }
564
+ /* Full-modal now uses .fd-ai-loader-typing-dot (see above) */
569
565
 
570
566
  /* ─── Code blocks in AI chat (pixel-border) ──────────────────────── */
571
567