@farming-labs/nuxt-theme 0.0.3-beta.3 → 0.0.3-beta.4

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/nuxt-theme",
3
- "version": "0.0.3-beta.3",
3
+ "version": "0.0.3-beta.4",
4
4
  "description": "Nuxt/Vue UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "docs",
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "dependencies": {
62
62
  "sugar-high": "^0.9.5",
63
- "@farming-labs/docs": "0.0.3-beta.3"
63
+ "@farming-labs/docs": "0.0.3-beta.4"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "nuxt": ">=3.0.0",
@@ -23,26 +23,60 @@ const thumbHeight = ref(0);
23
23
  const svgPath = ref("");
24
24
 
25
25
  const ACTIVE_ZONE_TOP = 120; // px from top of viewport — heading "active" when near this line
26
+ const HYSTERESIS_PX = 65; // only switch section when new is this much closer — keeps TOC highlight smooth (no flicker)
26
27
 
27
28
  let observer: IntersectionObserver | null = null;
28
29
  let scrollRafId = 0;
30
+ let lastStableId: string | null = null;
31
+
32
+ function getDistanceToZone(id: string): number {
33
+ const el = document.getElementById(id);
34
+ if (!el) return Infinity;
35
+ const rect = el.getBoundingClientRect();
36
+ const mid = rect.top + rect.height / 2;
37
+ return Math.abs(mid - ACTIVE_ZONE_TOP);
38
+ }
29
39
 
30
- function getActiveIdFromScroll(): Set<string> {
40
+ function getClosestId(): string | null {
31
41
  const ids = items.value.map((item) => item.url.slice(1));
32
42
  let bestId: string | null = null;
33
43
  let bestDistance = Infinity;
34
44
  for (const id of ids) {
35
- const el = document.getElementById(id);
36
- if (!el) continue;
37
- const rect = el.getBoundingClientRect();
38
- const mid = rect.top + rect.height / 2;
39
- const distance = Math.abs(mid - ACTIVE_ZONE_TOP);
40
- if (distance < bestDistance) {
41
- bestDistance = distance;
45
+ const d = getDistanceToZone(id);
46
+ if (d < bestDistance) {
47
+ bestDistance = d;
42
48
  bestId = id;
43
49
  }
44
50
  }
45
- return bestId ? new Set([bestId]) : new Set();
51
+ return bestId;
52
+ }
53
+
54
+ function isInView(id: string): boolean {
55
+ const el = document.getElementById(id);
56
+ if (!el) return false;
57
+ const rect = el.getBoundingClientRect();
58
+ return rect.top < window.innerHeight && rect.bottom > 0;
59
+ }
60
+
61
+ function getActiveIdFromScroll(): Set<string> {
62
+ const newId = getClosestId();
63
+ if (!newId) return new Set();
64
+
65
+ if (lastStableId === null) {
66
+ lastStableId = newId;
67
+ return new Set([newId]);
68
+ }
69
+
70
+ if (newId === lastStableId) return new Set([newId]);
71
+
72
+ const newDist = getDistanceToZone(newId);
73
+ const currentDist = getDistanceToZone(lastStableId);
74
+
75
+ const switchToNew =
76
+ newDist <= currentDist - HYSTERESIS_PX || !isInView(lastStableId);
77
+
78
+ if (switchToNew) lastStableId = newId;
79
+ return new Set([lastStableId]);
46
80
  }
47
81
 
48
82
  function updateActiveFromScroll() {
@@ -221,6 +255,7 @@ onMounted(() => {
221
255
  watch(
222
256
  items,
223
257
  () => {
258
+ lastStableId = null; // reset so new page gets smooth TOC from scroll position
224
259
  observeHeadings();
225
260
  nextTick(() => {
226
261
  activeIds.value = getActiveIdFromScroll();
@@ -86,40 +86,38 @@ aside#nd-sidebar,
86
86
  #nd-docs-layout aside,
87
87
  .fd-sidebar {
88
88
  border: none;
89
- border-right: none;
89
+ border-right: 1px solid var(--color-fd-border);
90
90
  border-left: none;
91
- border-color: transparent;
92
91
  box-shadow: none;
93
92
  background: var(--color-fd-background);
94
93
  }
95
94
 
96
95
  .dark .fd-sidebar {
97
- background: var(--fd-sidebar-bg, #1a1a1a);
96
+ background: var(--color-fd-background);
98
97
  }
99
98
 
100
99
  .dark .fd-sidebar .fd-sidebar-title {
101
100
  font-size: 1.125rem;
102
101
  font-weight: 600;
103
- color: #e0e0e0;
102
+ color: var(--color-fd-foreground);
104
103
  }
105
104
 
106
- /* Search bar — rounded, darker grey background, ⌘ K badges */
107
105
  .dark .fd-sidebar .fd-sidebar-search-btn {
108
- background: var(--fd-sidebar-card-bg, #252525) !important;
109
- border: 1px solid var(--fd-sidebar-indent-line, #3c3c3c);
106
+ background: var(--color-fd-secondary) !important;
107
+ border: 1px solid var(--color-fd-border);
110
108
  border-radius: 8px;
111
- color: #a0a0a0;
109
+ color: var(--color-fd-muted-foreground);
112
110
  font-size: 0.875rem;
113
111
  }
114
112
 
115
113
  .dark .fd-sidebar .fd-sidebar-search-btn:hover {
116
- background: #2d2d2d !important;
114
+ background: var(--color-fd-accent) !important;
117
115
  }
118
116
 
119
117
  .dark .fd-sidebar .fd-sidebar-search-btn kbd {
120
- background: #404040 !important;
121
- border-color: #3c3c3c;
122
- color: #a0a0a0;
118
+ background: var(--color-fd-muted) !important;
119
+ border-color: var(--color-fd-border);
120
+ color: var(--color-fd-muted-foreground);
123
121
  border-radius: 4px;
124
122
  padding: 2px 6px;
125
123
  font-size: 11px;
@@ -135,7 +133,7 @@ aside a[data-active],
135
133
  .fd-sidebar .fd-sidebar-link {
136
134
  font-size: 0.875rem;
137
135
  line-height: 1.5;
138
- font-weight: 400;
136
+ font-weight: 500;
139
137
  padding: 6px 10px;
140
138
  border-radius: 8px;
141
139
  color: var(--color-fd-muted-foreground);
@@ -143,7 +141,7 @@ aside a[data-active],
143
141
  }
144
142
 
145
143
  .dark .fd-sidebar .fd-sidebar-link {
146
- color: #e0e0e0;
144
+ color: var(--color-fd-muted-foreground);
147
145
  }
148
146
 
149
147
  aside a[data-active]:hover,
@@ -153,69 +151,52 @@ aside a[data-active]:hover,
153
151
  }
154
152
 
155
153
  .dark .fd-sidebar .fd-sidebar-link:hover {
156
- color: #e0e0e0;
157
- background: #2d2d2d;
154
+ color: var(--color-fd-foreground);
155
+ background: var(--color-fd-accent);
158
156
  }
159
157
 
158
+ /* Active sidebar item — green tinted background + left highlight line */
160
159
  aside a[data-active="true"],
161
160
  .fd-sidebar .fd-sidebar-link-active,
162
161
  .fd-sidebar .fd-sidebar-link[data-active="true"] {
162
+ position: relative !important;
163
163
  color: var(--color-fd-primary) !important;
164
164
  font-weight: 600 !important;
165
- background: transparent !important;
166
- background-color: transparent !important;
165
+ background: rgba(13, 147, 115, 0.08) !important;
166
+ background-color: rgba(13, 147, 115, 0.08) !important;
167
167
  }
168
168
 
169
169
  .dark .fd-sidebar .fd-sidebar-link-active,
170
170
  .dark .fd-sidebar .fd-sidebar-link[data-active="true"] {
171
- color: var(--fd-sidebar-active-text, #50c878) !important;
172
- background: transparent !important;
173
- background-color: transparent !important;
171
+ color: var(--color-fd-primary) !important;
172
+ background: rgba(38, 189, 108, 0.1) !important;
173
+ background-color: rgba(38, 189, 108, 0.1) !important;
174
174
  }
175
175
 
176
+ /* Left highlight line — only for links that are children inside a folder (not for top-level links with no children) */
176
177
  .fd-sidebar-folder-content .fd-sidebar-link-active::before,
177
178
  .fd-sidebar-folder-content .fd-sidebar-link[data-active="true"]::before {
178
- content: "";
179
- position: absolute;
180
- left: 0;
181
- top: 0;
182
- bottom: 0;
183
- width: 2px;
184
- background: var(--fd-sidebar-active-line, #50c878);
185
- border-radius: 0;
186
- }
187
-
188
- .dark .fd-sidebar-folder-content .fd-sidebar-link-active::before,
189
- .dark .fd-sidebar-folder-content .fd-sidebar-link[data-active="true"]::before {
190
- background: var(--fd-sidebar-active-line, #50c878);
179
+ content: "" !important;
180
+ display: block !important;
181
+ position: absolute !important;
182
+ left: -9px !important;
183
+ top: 20% !important;
184
+ bottom: 20% !important;
185
+ width: 3px !important;
186
+ border-radius: 0 2px 2px 0 !important;
187
+ background: var(--color-fd-primary) !important;
191
188
  }
192
189
 
193
190
  .fd-sidebar .fd-sidebar-top-link.fd-sidebar-link-active,
194
191
  .fd-sidebar .fd-sidebar-top-link[data-active="true"] {
195
- background: transparent !important;
196
- background-color: transparent !important;
192
+ background: rgba(13, 147, 115, 0.08) !important;
193
+ background-color: rgba(13, 147, 115, 0.08) !important;
197
194
  }
198
195
 
199
- .fd-sidebar .fd-sidebar-top-link.fd-sidebar-link-active::before,
200
- .fd-sidebar .fd-sidebar-top-link[data-active="true"]::before {
201
- content: "";
202
- position: absolute;
203
- left: 0;
204
- top: 25%;
205
- bottom: 25%;
206
- width: 2px;
207
- background: var(--color-fd-primary);
208
- border-radius: 1px;
209
- }
210
-
211
- .dark .fd-sidebar .fd-sidebar-top-link.fd-sidebar-link-active::before,
212
- .dark .fd-sidebar .fd-sidebar-top-link[data-active="true"]::before {
213
- background: var(--fd-sidebar-active-line, #50c878);
214
- }
215
-
216
- aside a[data-active="true"]::before {
217
- background-color: transparent;
218
- width: 0;
196
+ .dark .fd-sidebar .fd-sidebar-top-link.fd-sidebar-link-active,
197
+ .dark .fd-sidebar .fd-sidebar-top-link[data-active="true"] {
198
+ background: rgba(38, 189, 108, 0.1) !important;
199
+ background-color: rgba(38, 189, 108, 0.1) !important;
219
200
  }
220
201
 
221
202
  .dark .fd-sidebar .fd-sidebar-folder {
@@ -236,14 +217,14 @@ aside a[data-active].w-full,
236
217
  font-weight: 600;
237
218
  font-size: 0.875rem;
238
219
  color: var(--color-fd-foreground);
239
- padding: 7px 10px 8px 10px;
220
+ padding: 4px 10px 4px 10px;
240
221
  margin-top: 0;
241
222
  border: none;
242
223
  background: transparent !important;
243
224
  }
244
225
 
245
226
  .dark .fd-sidebar .fd-sidebar-folder-trigger {
246
- color: #e0e0e0;
227
+ color: var(--color-fd-muted-foreground);
247
228
  }
248
229
 
249
230
  .fd-sidebar .fd-sidebar-folder-trigger:hover {
@@ -251,7 +232,7 @@ aside a[data-active].w-full,
251
232
  }
252
233
 
253
234
  .dark .fd-sidebar .fd-sidebar-folder-trigger:hover {
254
- background: #2d2d2d !important;
235
+ background: var(--color-fd-accent) !important;
255
236
  }
256
237
 
257
238
  aside a[data-active].w-full:first-child,
@@ -277,7 +258,7 @@ aside a[data-active="true"].w-full,
277
258
 
278
259
  .dark .fd-sidebar .fd-sidebar-top-link.fd-sidebar-link-active,
279
260
  .dark .fd-sidebar .fd-sidebar-top-link[data-active="true"] {
280
- color: var(--fd-sidebar-active-text, #50c878) !important;
261
+ color: var(--color-fd-primary) !important;
281
262
  }
282
263
 
283
264
  aside div.w-full:not([role]) {
@@ -322,7 +303,7 @@ aside .border-t,
322
303
  aside [class*="border-t"],
323
304
  .fd-sidebar .fd-sidebar-footer,
324
305
  .fd-sidebar .fd-sidebar-footer-custom {
325
- border-top-color: transparent;
306
+ border-top: 1px solid var(--color-fd-border);
326
307
  }
327
308
 
328
309
  /* ═══════════════════════════════════════════════════════════════════
@@ -539,21 +520,31 @@ details > :not(summary) {
539
520
  padding: 0.75rem 1rem;
540
521
  }
541
522
 
542
- #nd-toc a[data-active="true"] {
523
+ /* TOC — use .fd-toc (matches layout); transition reduces flash when scroll spy toggles active */
524
+ .fd-toc .fd-toc-link,
525
+ .fd-toc .fd-toc-clerk-link {
526
+ transition: color 0.2s ease;
527
+ }
528
+
529
+ .fd-toc .fd-toc-link-active,
530
+ .fd-toc .fd-toc-link[data-active="true"],
531
+ .fd-toc .fd-toc-clerk-link[data-active="true"] {
543
532
  color: var(--color-fd-primary);
544
533
  font-weight: 500;
545
534
  }
546
535
 
547
- #nd-toc a[data-active="false"] {
536
+ .fd-toc .fd-toc-link:not(.fd-toc-link-active):not([data-active="true"]),
537
+ .fd-toc .fd-toc-clerk-link:not([data-active="true"]) {
548
538
  color: var(--color-fd-muted-foreground);
549
539
  }
550
540
 
551
- #nd-toc a {
541
+ .fd-toc .fd-toc-link,
542
+ .fd-toc .fd-toc-clerk-link {
552
543
  font-size: 0.875rem;
553
544
  line-height: 1.3;
554
545
  }
555
546
 
556
- #nd-toc h3 {
547
+ .fd-toc .fd-toc-title {
557
548
  font-size: 0.875rem;
558
549
  font-weight: 500;
559
550
  }
@@ -591,6 +582,7 @@ details > :not(summary) {
591
582
  }
592
583
 
593
584
  .fd-page-description {
585
+ margin-bottom: 1rem;
594
586
  font-size: 1rem;
595
587
  line-height: 1.7;
596
588
  color: var(--color-fd-muted-foreground);
@@ -692,11 +684,42 @@ details > :not(summary) {
692
684
  filter: brightness(1.1);
693
685
  }
694
686
 
695
- .fd-ai-suggestion,
687
+ .fd-ai-suggestion {
688
+ border-radius: 10px;
689
+ }
690
+
696
691
  .fd-ai-result {
697
692
  border-radius: 10px;
698
693
  }
699
694
 
695
+ .fd-ai-fm-input-container {
696
+ border-radius: 12px;
697
+ }
698
+
699
+ .fd-ai-fm-send-btn {
700
+ border-radius: 9999px;
701
+ }
702
+
703
+ .fd-ai-fm-suggestion {
704
+ border-radius: 9999px;
705
+ }
706
+
707
+ .fd-ai-fm-trigger-btn {
708
+ border-radius: 16px;
709
+ }
710
+
711
+ .fd-ai-fm-close-btn {
712
+ border-radius: 9999px;
713
+ }
714
+
715
+ .fd-ai-code-block {
716
+ border-radius: 10px;
717
+ }
718
+
719
+ .fd-ai-code-copy {
720
+ border-radius: 6px;
721
+ }
722
+
700
723
  .fd-sidebar-search-ai-row {
701
724
  display: flex;
702
725
  gap: 8px;
@@ -773,54 +796,7 @@ details > :not(summary) {
773
796
  height: 16px;
774
797
  }
775
798
 
776
- .fd-page-actions {
777
- display: flex;
778
- gap: 0;
779
- align-items: stretch;
780
- }
781
-
782
- .fd-page-action-btn {
783
- display: inline-flex;
784
- align-items: center;
785
- gap: 6px;
786
- padding: 6px 12px;
787
- font-size: 0.8125rem;
788
- font-weight: 500;
789
- color: var(--color-fd-muted-foreground);
790
- background: transparent;
791
- border: 1px solid var(--color-fd-border);
792
- cursor: pointer;
793
- transition:
794
- background-color 150ms,
795
- color 150ms;
796
- white-space: nowrap;
797
- }
798
-
799
- .fd-page-action-btn:hover {
800
- background: var(--color-fd-accent);
801
- color: var(--color-fd-foreground);
802
- }
803
-
804
- .fd-page-actions .fd-page-action-btn:first-child {
805
- border-radius: 8px 0 0 8px;
806
- border-right: none;
807
- }
808
-
809
- .fd-page-actions .fd-page-action-dropdown:last-child .fd-page-action-btn,
810
- .fd-page-actions > .fd-page-action-btn:last-child {
811
- border-radius: 0 8px 8px 0;
812
- border-left: 1px solid var(--color-fd-border);
813
- padding: 6px 8px;
814
- }
815
-
816
- .fd-page-actions .fd-page-action-btn:only-child {
817
- border-radius: 8px;
818
- border: 1px solid var(--color-fd-border);
819
- }
820
-
821
- .fd-page-action-dropdown {
822
- position: relative;
823
- }
799
+ /* Page actions — greentree style overrides on top of Nuxt base layout */
824
800
 
825
801
  .fd-sidebar::-webkit-scrollbar {
826
802
  width: 4px;
@@ -705,3 +705,41 @@ code:not(pre code) {
705
705
  .fd-ai-code-block code {
706
706
  font-family: var(--fd-font-mono, ui-monospace, monospace);
707
707
  }
708
+
709
+ /* Light mode: AI code blocks — light bg + dark text + visible pixel border */
710
+ :root:not(.dark) .fd-ai-code-block {
711
+ background: #f4f4f5 !important;
712
+ box-shadow: 3px 3px 0 0 hsl(0 0% 75%);
713
+ --sh-class: #b45309;
714
+ --sh-identifier: #1f2937;
715
+ --sh-keyword: #7c3aed;
716
+ --sh-string: #0d9488;
717
+ --sh-property: #dc2626;
718
+ --sh-entity: #059669;
719
+ --sh-sign: #374151;
720
+ --sh-comment: #6b7280;
721
+ --sh-jsxliterals: #7c3aed;
722
+ }
723
+
724
+ :root:not(.dark) .fd-ai-code-header {
725
+ border-bottom-color: hsl(0 0% 80%);
726
+ background: color-mix(in srgb, #e4e4e7 90%, transparent);
727
+ }
728
+
729
+ :root:not(.dark) .fd-ai-code-lang {
730
+ color: #52525b;
731
+ }
732
+
733
+ :root:not(.dark) .fd-ai-code-copy {
734
+ color: #52525b;
735
+ border-color: hsl(0 0% 75%);
736
+ }
737
+
738
+ :root:not(.dark) .fd-ai-code-copy:hover {
739
+ color: #18181b;
740
+ background: color-mix(in srgb, #d4d4d8 70%, transparent);
741
+ }
742
+
743
+ :root:not(.dark) .fd-ai-code-block code {
744
+ color: #1f2937;
745
+ }