@farming-labs/astro-theme 0.0.2-beta.23 → 0.0.2-beta.26

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/astro-theme",
3
- "version": "0.0.2-beta.23",
3
+ "version": "0.0.2-beta.26",
4
4
  "description": "Astro UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "astro",
@@ -69,8 +69,8 @@
69
69
  },
70
70
  "dependencies": {
71
71
  "sugar-high": "^0.9.5",
72
- "@farming-labs/docs": "0.0.2-beta.23",
73
- "@farming-labs/astro": "0.0.2-beta.23"
72
+ "@farming-labs/astro": "0.0.2-beta.26",
73
+ "@farming-labs/docs": "0.0.2-beta.26"
74
74
  },
75
75
  "peerDependencies": {
76
76
  "astro": ">=4.0.0"
@@ -182,6 +182,11 @@ const showFloatingAI = aiConfig?.mode === "floating" && aiConfig?.enabled;
182
182
  </button>
183
183
  </div>
184
184
 
185
+ {Astro.slots.has("sidebar") ? (
186
+ <nav class="fd-sidebar-nav">
187
+ <slot name="sidebar" />
188
+ </nav>
189
+ ) : (
185
190
  <nav class="fd-sidebar-nav">
186
191
  {tree?.children?.map((node, i) => {
187
192
  if (node.type === "page") {
@@ -273,6 +278,7 @@ const showFloatingAI = aiConfig?.mode === "floating" && aiConfig?.enabled;
273
278
  }
274
279
  })}
275
280
  </nav>
281
+ )}
276
282
 
277
283
  {showThemeToggle && (
278
284
  <div class="fd-sidebar-footer">
@@ -263,8 +263,9 @@ const containerStyle = getContainerStyle(floatingStyle, position);
263
263
  return result;
264
264
  }
265
265
 
266
- const THINKING_HTML_FM = `<div class="fd-ai-fm-thinking"><span class="fd-ai-fm-thinking-dot"></span><span class="fd-ai-fm-thinking-dot"></span><span class="fd-ai-fm-thinking-dot"></span></div>`;
267
- const THINKING_HTML = `<span class="fd-ai-loading"><span class="fd-ai-loading-text">Thinking</span><span class="fd-ai-loading-dots"><span class="fd-ai-loading-dot"></span><span class="fd-ai-loading-dot"></span><span class="fd-ai-loading-dot"></span></span></span>`;
266
+ function thinkingHtml(label: string) {
267
+ return `<div class="fd-ai-loader"><span class="fd-ai-loader-shimmer-text">Thinking</span><span class="fd-ai-loader-typing-dots"><span class="fd-ai-loader-typing-dot"></span><span class="fd-ai-loader-typing-dot"></span><span class="fd-ai-loader-typing-dot"></span></span></div>`;
268
+ }
268
269
 
269
270
  function initFloatingAI() {
270
271
  const cfgEl = document.getElementById('fd-float-config');
@@ -355,12 +356,13 @@ const containerStyle = getContainerStyle(floatingStyle, position);
355
356
  if (footerHint) footerHint.style.display = 'none';
356
357
  if (clearWrap) clearWrap.style.display = 'flex';
357
358
 
358
- const thinkingHtml = isFullModal ? THINKING_HTML_FM : THINKING_HTML;
359
- messagesEl.innerHTML = messages.map(m => {
359
+ const thinking = thinkingHtml(aiLabel);
360
+ messagesEl.innerHTML = messages.map((m, i) => {
360
361
  const label = m.role === 'user' ? 'You' : aiLabel;
362
+ const lastAssistant = isStreaming && i === messages.length - 1 && m.role === 'assistant' && m.content;
361
363
  const renderedContent = m.role === 'user'
362
364
  ? escapeHtml(m.content)
363
- : (m.content ? renderMarkdown(m.content) : thinkingHtml);
365
+ : (m.content ? `<div${lastAssistant ? ' class="fd-ai-streaming"' : ''}>${renderMarkdown(m.content)}</div>` : thinking);
364
366
  const bubbleClass = isFullModal
365
367
  ? 'fd-ai-fm-msg-content'
366
368
  : (m.role === 'user' ? 'fd-ai-bubble-user' : 'fd-ai-bubble-ai');
@@ -288,11 +288,13 @@ const suggestedQuestions = config?.ai?.suggestedQuestions ?? [];
288
288
  aiMessages.innerHTML = '<div class="fd-ai-empty"><div class="fd-ai-empty-title">Ask anything about the docs</div></div>';
289
289
  return;
290
290
  }
291
- const THINKING = `<span class="fd-ai-loading"><span class="fd-ai-loading-text">Thinking</span><span class="fd-ai-loading-dots"><span class="fd-ai-loading-dot"></span><span class="fd-ai-loading-dot"></span><span class="fd-ai-loading-dot"></span></span></span>`;
292
- aiMessages.innerHTML = messages.map(m => {
291
+ const THINKING = `<div class="fd-ai-loader"><span class="fd-ai-loader-shimmer-text">Thinking</span><span class="fd-ai-loader-typing-dots"><span class="fd-ai-loader-typing-dot"></span><span class="fd-ai-loader-typing-dot"></span><span class="fd-ai-loader-typing-dot"></span></span></div>`;
292
+ const isLast = (i: number) => i === messages.length - 1;
293
+ aiMessages.innerHTML = messages.map((m, i) => {
294
+ const streaming = isStreaming && isLast(i) && m.role === 'assistant' && m.content;
293
295
  const renderedContent = m.role === 'user'
294
296
  ? escapeHtml(m.content)
295
- : (m.content ? renderMarkdown(m.content) : THINKING);
297
+ : (m.content ? `<div${streaming ? ' class="fd-ai-streaming"' : ''}>${renderMarkdown(m.content)}</div>` : THINKING);
296
298
  return `<div class="fd-ai-msg" data-role="${m.role}"><div class="fd-ai-msg-label">${m.role === 'user' ? 'You' : aiLabel}</div><div class="${m.role === 'user' ? 'fd-ai-bubble-user' : 'fd-ai-bubble-ai'}">${renderedContent}</div></div>`;
297
299
  }).join('');
298
300
  aiMessages.scrollTop = aiMessages.scrollHeight;
package/styles/docs.css CHANGED
@@ -1211,8 +1211,9 @@ html.dark pre.shiki {
1211
1211
 
1212
1212
  .fd-edit-on-github {
1213
1213
  display: flex;
1214
+ flex-wrap: wrap;
1214
1215
  align-items: center;
1215
- gap: 16px;
1216
+ gap: 10px 16px;
1216
1217
  margin-top: 32px;
1217
1218
  padding-top: 16px;
1218
1219
  border-top: 1px solid var(--color-fd-border);
@@ -1237,6 +1238,12 @@ html.dark pre.shiki {
1237
1238
  font-size: 12px;
1238
1239
  }
1239
1240
 
1241
+ @media (max-width: 640px) {
1242
+ .fd-last-modified {
1243
+ width: 100%;
1244
+ }
1245
+ }
1246
+
1240
1247
  .fd-llms-txt-links {
1241
1248
  display: inline-flex;
1242
1249
  align-items: center;
@@ -1329,19 +1336,6 @@ html.dark pre.shiki {
1329
1336
  * AI Chat & Search Dialog — base styles (fd-ai-*)
1330
1337
  * ═══════════════════════════════════════════════════════════════════════ */
1331
1338
 
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
1339
  @keyframes fd-ai-fade-in {
1346
1340
  from {
1347
1341
  opacity: 0;
@@ -1693,6 +1687,12 @@ html.dark pre.shiki {
1693
1687
  line-height: 1.6;
1694
1688
  max-width: 95%;
1695
1689
  word-break: break-word;
1690
+ animation: fd-ai-msg-in 300ms ease-out;
1691
+ }
1692
+
1693
+ @keyframes fd-ai-msg-in {
1694
+ from { opacity: 0; transform: translateY(4px); }
1695
+ to { opacity: 1; transform: translateY(0); }
1696
1696
  }
1697
1697
 
1698
1698
  .fd-ai-chat-footer {
@@ -1745,36 +1745,70 @@ html.dark pre.shiki {
1745
1745
  color: var(--color-fd-primary-foreground);
1746
1746
  }
1747
1747
 
1748
- .fd-ai-loading {
1748
+ .fd-ai-loader {
1749
1749
  display: inline-flex;
1750
- gap: 6px;
1751
1750
  align-items: center;
1751
+ gap: 6px;
1752
+ animation: fd-ai-loader-in 300ms ease-out;
1752
1753
  }
1753
1754
 
1754
- .fd-ai-loading-text {
1755
- font-size: 12px;
1756
- color: var(--color-fd-muted-foreground);
1755
+ @keyframes fd-ai-loader-in {
1756
+ from { opacity: 0; transform: translateY(4px); }
1757
+ to { opacity: 1; transform: translateY(0); }
1757
1758
  }
1758
1759
 
1759
- .fd-ai-loading-dots {
1760
+ .fd-ai-loader-shimmer-text {
1761
+ font-size: 13px;
1762
+ font-weight: 500;
1763
+ 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%);
1764
+ background-size: 200% auto;
1765
+ background-clip: text;
1766
+ -webkit-background-clip: text;
1767
+ color: transparent;
1768
+ animation: fd-ai-shimmer-text 3s linear infinite;
1769
+ }
1770
+
1771
+ @keyframes fd-ai-shimmer-text {
1772
+ 0% { background-position: 150% center; }
1773
+ 100% { background-position: -150% center; }
1774
+ }
1775
+
1776
+ .fd-ai-loader-typing-dots {
1760
1777
  display: inline-flex;
1761
- gap: 3px;
1762
1778
  align-items: center;
1779
+ gap: 2px;
1763
1780
  }
1764
1781
 
1765
- .fd-ai-loading-dot {
1766
- width: 5px;
1767
- height: 5px;
1782
+ .fd-ai-loader-typing-dot {
1783
+ width: 4px;
1784
+ height: 4px;
1768
1785
  border-radius: 50%;
1769
- background: var(--color-fd-muted-foreground);
1770
- animation: fd-ai-dot 1.4s infinite ease-in-out both;
1786
+ background: var(--color-fd-primary, #6366f1);
1787
+ animation: fd-ai-typing 1s infinite;
1788
+ }
1789
+
1790
+ .fd-ai-loader-typing-dot:nth-child(2) { animation-delay: 250ms; }
1791
+ .fd-ai-loader-typing-dot:nth-child(3) { animation-delay: 500ms; }
1792
+
1793
+ @keyframes fd-ai-typing {
1794
+ 0%, 100% { transform: translateY(0); opacity: 0.5; }
1795
+ 50% { transform: translateY(-2px); opacity: 1; }
1771
1796
  }
1772
1797
 
1773
- .fd-ai-loading-dot:nth-child(2) {
1774
- animation-delay: 0.16s;
1798
+ .fd-ai-streaming::after {
1799
+ content: "";
1800
+ display: inline-block;
1801
+ width: 2px;
1802
+ height: 1em;
1803
+ background: var(--color-fd-primary, #6366f1);
1804
+ margin-left: 2px;
1805
+ vertical-align: text-bottom;
1806
+ animation: fd-ai-cursor-blink 0.8s step-end infinite;
1775
1807
  }
1776
- .fd-ai-loading-dot:nth-child(3) {
1777
- animation-delay: 0.32s;
1808
+
1809
+ @keyframes fd-ai-cursor-blink {
1810
+ 0%, 100% { opacity: 1; }
1811
+ 50% { opacity: 0; }
1778
1812
  }
1779
1813
 
1780
1814
  /* ─── Markdown in AI responses ───────────────────────────────── */
@@ -2166,41 +2200,7 @@ html.dark pre.shiki {
2166
2200
  font-size: 12px;
2167
2201
  }
2168
2202
 
2169
- /* ─── Thinking dots ──────────────────────────────────────────── */
2170
-
2171
- .fd-ai-fm-thinking {
2172
- display: flex;
2173
- gap: 4px;
2174
- align-items: center;
2175
- }
2176
-
2177
- .fd-ai-fm-thinking-dot {
2178
- width: 6px;
2179
- height: 6px;
2180
- border-radius: 9999px;
2181
- background: var(--color-fd-primary, #6366f1);
2182
- animation: fd-ai-fm-bounce 1s infinite ease-in-out;
2183
- }
2184
-
2185
- .fd-ai-fm-thinking-dot:nth-child(2) {
2186
- animation-delay: 150ms;
2187
- }
2188
- .fd-ai-fm-thinking-dot:nth-child(3) {
2189
- animation-delay: 300ms;
2190
- }
2191
-
2192
- @keyframes fd-ai-fm-bounce {
2193
- 0%,
2194
- 80%,
2195
- 100% {
2196
- transform: scale(0.6);
2197
- opacity: 0.4;
2198
- }
2199
- 40% {
2200
- transform: scale(1);
2201
- opacity: 1;
2202
- }
2203
- }
2203
+ /* Full-modal now uses the shared .fd-ai-loader indicator */
2204
2204
 
2205
2205
  /* ─── Bottom input bar ───────────────────────────────────────── */
2206
2206
 
@@ -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