@farming-labs/svelte-theme 0.0.6 → 0.0.7

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.6",
3
+ "version": "0.0.7",
4
4
  "description": "Svelte UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "docs",
@@ -82,8 +82,8 @@
82
82
  "dependencies": {
83
83
  "gray-matter": "^4.0.3",
84
84
  "sugar-high": "^0.9.5",
85
- "@farming-labs/docs": "0.0.6",
86
- "@farming-labs/svelte": "0.0.6"
85
+ "@farming-labs/docs": "0.0.7",
86
+ "@farming-labs/svelte": "0.0.7"
87
87
  },
88
88
  "peerDependencies": {
89
89
  "svelte": ">=5.0.0"
@@ -198,6 +198,10 @@
198
198
  const layout = config?.theme?.ui?.layout;
199
199
  return [buildColorsCSS(colorOverrides), buildTypographyCSS(typography), buildLayoutCSS(layout)].filter(Boolean).join("\n");
200
200
  });
201
+
202
+ // Build style tag from parts so Vite/Svelte preprocessor doesn't treat it as a real <style> block (PostCSS would then fail on "overrideCSS")
203
+ const styleTagOpen = "<sty" + "le>";
204
+ const styleTagClose = "</sty" + "le>";
201
205
  </script>
202
206
 
203
207
  <svelte:window onkeydown={handleKeydown} />
@@ -205,7 +209,7 @@
205
209
  <svelte:head>
206
210
  {@html `<script>${themeInitScript}</script>`}
207
211
  {#if overrideCSS}
208
- {@html `<style>${overrideCSS}</style>`}
212
+ {@html `${styleTagOpen}${overrideCSS}${styleTagClose}`}
209
213
  {/if}
210
214
  </svelte:head>
211
215
 
@@ -207,14 +207,41 @@
207
207
 
208
208
  {#if mounted}
209
209
  {#if isFullModal}
210
- <!-- ═══ Full-Modal Mode (better-auth inspired) ═══ -->
210
+ <!-- ═══ Full-Modal Mode (better-auth inspired) ═══
211
+ Trigger is always in a fixed-position wrapper when closed (no morphing).
212
+ When open: overlay + separate fixed input bar for smooth open/close. -->
211
213
 
214
+ <!-- When closed: fixed trigger only — stays in place, no layout jump -->
215
+ {#if !isOpen}
216
+ <div class="fd-ai-fm-trigger-fixed" style={btnStyle}>
217
+ {#if triggerComponent}
218
+ {@const Trigger = triggerComponent}
219
+ <!-- svelte-ignore a11y_click_events_have_key_events -->
220
+ <!-- svelte-ignore a11y_no_static_element_interactions -->
221
+ <div onclick={() => isOpen = true} class="fd-ai-floating-trigger fd-ai-floating-trigger--static">
222
+ <Trigger aiLabel={label} />
223
+ </div>
224
+ {:else}
225
+ <button
226
+ onclick={() => isOpen = true}
227
+ class="fd-ai-fm-trigger-btn"
228
+ aria-label="Ask {label}"
229
+ >
230
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
231
+ <path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/>
232
+ <path d="M20 3v4"/><path d="M22 5h-4"/>
233
+ </svg>
234
+ <span>Ask {label}</span>
235
+ </button>
236
+ {/if}
237
+ </div>
238
+ {/if}
239
+
240
+ <!-- When open: overlay + input bar (separate elements, no morphing from trigger) -->
212
241
  {#if isOpen}
213
- <!-- Full-screen overlay -->
214
242
  <!-- svelte-ignore a11y_click_events_have_key_events -->
215
243
  <!-- svelte-ignore a11y_no_static_element_interactions -->
216
- <div class="fd-ai-fm-overlay" onclick={(e) => { if (e.target === e.currentTarget) isOpen = false; }}>
217
- <!-- Close button -->
244
+ <div class="fd-ai-fm-overlay fd-ai-fm-overlay--animate" onclick={(e) => { if (e.target === e.currentTarget) isOpen = false; }}>
218
245
  <div class="fd-ai-fm-topbar">
219
246
  <button onclick={() => isOpen = false} class="fd-ai-fm-close-btn" aria-label="Close">
220
247
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -223,7 +250,6 @@
223
250
  </button>
224
251
  </div>
225
252
 
226
- <!-- Scrollable message list -->
227
253
  <div bind:this={fmListEl} class="fd-ai-fm-messages">
228
254
  <div class="fd-ai-fm-messages-inner">
229
255
  {#each messages as msg, i}
@@ -252,38 +278,9 @@
252
278
  </div>
253
279
  </div>
254
280
  </div>
255
- {/if}
256
281
 
257
- <!-- Bottom input bar always visible when open, pinned to bottom -->
258
- <div
259
- class="fd-ai-fm-input-bar {isOpen ? 'fd-ai-fm-input-bar--open' : 'fd-ai-fm-input-bar--closed'}"
260
- style={isOpen ? undefined : btnStyle}
261
- >
262
- {#if !isOpen}
263
- {#if triggerComponent}
264
- <!-- svelte-ignore a11y_click_events_have_key_events -->
265
- <!-- svelte-ignore a11y_no_static_element_interactions -->
266
- <div
267
- onclick={() => isOpen = true}
268
- class="fd-ai-floating-trigger"
269
- style={btnStyle}
270
- >
271
- <svelte:component this={triggerComponent} aiLabel={label} />
272
- </div>
273
- {:else}
274
- <button
275
- onclick={() => isOpen = true}
276
- class="fd-ai-fm-trigger-btn"
277
- aria-label="Ask {label}"
278
- >
279
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
280
- <path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z"/>
281
- <path d="M20 3v4"/><path d="M22 5h-4"/>
282
- </svg>
283
- <span>Ask {label}</span>
284
- </button>
285
- {/if}
286
- {:else}
282
+ <!-- Input bar when open: fixed at bottom center, never morphs from trigger -->
283
+ <div class="fd-ai-fm-input-bar fd-ai-fm-input-bar--open">
287
284
  <div class="fd-ai-fm-input-container">
288
285
  <div class="fd-ai-fm-input-wrap">
289
286
  <textarea
@@ -350,9 +347,8 @@
350
347
  {/if}
351
348
  </div>
352
349
  </div>
353
- {/if}
354
- </div>
355
-
350
+ </div>
351
+ {/if}
356
352
  {:else}
357
353
  <!-- ═══ Panel / Modal / Popover Mode ═══ -->
358
354
 
@@ -479,6 +475,7 @@
479
475
 
480
476
  {#if !isOpen}
481
477
  {#if triggerComponent}
478
+ {@const Trigger = triggerComponent}
482
479
  <!-- svelte-ignore a11y_click_events_have_key_events -->
483
480
  <!-- svelte-ignore a11y_no_static_element_interactions -->
484
481
  <div
@@ -486,7 +483,7 @@
486
483
  class="fd-ai-floating-trigger"
487
484
  style={btnStyle}
488
485
  >
489
- <svelte:component this={triggerComponent} aiLabel={label} />
486
+ <Trigger aiLabel={label} />
490
487
  </div>
491
488
  {:else}
492
489
  <button
package/styles/docs.css CHANGED
@@ -2262,6 +2262,20 @@ html.dark pre.shiki {
2262
2262
  transform: scale(0.97);
2263
2263
  }
2264
2264
 
2265
+ /* Dark mode: floating button and trigger use dark-friendly colors */
2266
+ .dark .fd-ai-floating-btn,
2267
+ .dark .fd-ai-fm-trigger-btn {
2268
+ background: color-mix(in srgb, var(--color-fd-secondary, rgba(255, 255, 255, 0.08)) 90%, transparent);
2269
+ color: var(--color-fd-foreground, #e4e4e7);
2270
+ border-color: var(--color-fd-border, rgba(255, 255, 255, 0.12));
2271
+ }
2272
+
2273
+ .dark .fd-ai-floating-btn:hover,
2274
+ .dark .fd-ai-fm-trigger-btn:hover {
2275
+ background: var(--color-fd-accent);
2276
+ color: var(--color-fd-accent-foreground);
2277
+ }
2278
+
2265
2279
  .fd-ai-floating-trigger {
2266
2280
  position: fixed;
2267
2281
  z-index: 9997;
@@ -2290,12 +2304,23 @@ html.dark pre.shiki {
2290
2304
  transition: transform 150ms, background 150ms, color 150ms;
2291
2305
  }
2292
2306
 
2307
+ .dark .fd-ai-floating-trigger .ask-ai-trigger {
2308
+ background: color-mix(in srgb, var(--color-fd-secondary, rgba(255, 255, 255, 0.08)) 90%, transparent);
2309
+ color: var(--color-fd-foreground, #e4e4e7);
2310
+ border-color: var(--color-fd-border, rgba(255, 255, 255, 0.12));
2311
+ }
2312
+
2293
2313
  .fd-ai-floating-trigger .ask-ai-trigger:hover {
2294
2314
  background: var(--color-fd-accent);
2295
2315
  color: var(--color-fd-accent-foreground);
2296
2316
  transform: scale(1.03);
2297
2317
  }
2298
2318
 
2319
+ .dark .fd-ai-floating-trigger .ask-ai-trigger:hover {
2320
+ background: var(--color-fd-accent);
2321
+ color: var(--color-fd-accent-foreground);
2322
+ }
2323
+
2299
2324
  .fd-ai-floating-trigger .ask-ai-trigger:active {
2300
2325
  transform: scale(0.97);
2301
2326
  }
@@ -2304,6 +2329,17 @@ html.dark pre.shiki {
2304
2329
  Full-Modal (better-auth inspired) — fd-ai-fm-*
2305
2330
  ═══════════════════════════════════════════════════════════════ */
2306
2331
 
2332
+ /* Fixed wrapper for trigger when closed — never morphs, so no "stuck" feel */
2333
+ .fd-ai-fm-trigger-fixed {
2334
+ position: fixed;
2335
+ z-index: 9997;
2336
+ animation: fd-ai-fade-in 200ms ease-out;
2337
+ }
2338
+
2339
+ .fd-ai-floating-trigger--static {
2340
+ position: static;
2341
+ }
2342
+
2307
2343
  .fd-ai-fm-overlay {
2308
2344
  position: fixed;
2309
2345
  inset: 0;
@@ -2313,10 +2349,13 @@ html.dark pre.shiki {
2313
2349
  background: color-mix(in srgb, var(--color-fd-background, #000) 80%, transparent);
2314
2350
  backdrop-filter: blur(8px);
2315
2351
  z-index: 9998;
2316
- animation: fd-ai-fade-in 200ms ease-out;
2317
2352
  padding: 0 8px;
2318
2353
  }
2319
2354
 
2355
+ .fd-ai-fm-overlay--animate {
2356
+ animation: fd-ai-fade-in 200ms ease-out;
2357
+ }
2358
+
2320
2359
  /* ─── Top bar (close button) ─────────────────────────────────── */
2321
2360
 
2322
2361
  .fd-ai-fm-topbar {
@@ -2498,14 +2537,6 @@ html.dark pre.shiki {
2498
2537
  .fd-ai-fm-input-bar {
2499
2538
  position: fixed;
2500
2539
  z-index: 9999;
2501
- transition:
2502
- width 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
2503
- height 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
2504
- transform 200ms ease-out;
2505
- }
2506
-
2507
- .fd-ai-fm-input-bar--closed {
2508
- /* inherits position from inline btnPosition styles */
2509
2540
  }
2510
2541
 
2511
2542
  .fd-ai-fm-input-bar--open {
@@ -2513,6 +2544,7 @@ html.dark pre.shiki {
2513
2544
  left: 50%;
2514
2545
  transform: translateX(-50%);
2515
2546
  width: min(800px, calc(100vw - 32px));
2547
+ animation: fd-ai-fade-in 200ms ease-out;
2516
2548
  }
2517
2549
 
2518
2550
  .fd-ai-fm-input-container {