@farming-labs/nuxt-theme 0.1.57 → 0.1.59

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.1.57",
3
+ "version": "0.1.59",
4
4
  "description": "Nuxt/Vue UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "docs",
@@ -81,7 +81,7 @@
81
81
  },
82
82
  "dependencies": {
83
83
  "sugar-high": "^0.9.5",
84
- "@farming-labs/docs": "0.1.57"
84
+ "@farming-labs/docs": "0.1.59"
85
85
  },
86
86
  "peerDependencies": {
87
87
  "nuxt": ">=3.0.0",
@@ -88,6 +88,48 @@ function closeOpenHoverLinks(event: Event) {
88
88
  });
89
89
  }
90
90
 
91
+ async function fallbackCopyPromptText(text: string): Promise<boolean> {
92
+ const textarea = document.createElement("textarea");
93
+ textarea.value = text;
94
+ textarea.setAttribute("readonly", "");
95
+ textarea.style.position = "fixed";
96
+ textarea.style.top = "0";
97
+ textarea.style.left = "0";
98
+ textarea.style.opacity = "0";
99
+ textarea.style.pointerEvents = "none";
100
+ document.body.appendChild(textarea);
101
+ textarea.focus();
102
+ textarea.select();
103
+
104
+ let copied = false;
105
+ try {
106
+ copied = document.execCommand("copy");
107
+ } catch {
108
+ copied = false;
109
+ } finally {
110
+ document.body.removeChild(textarea);
111
+ }
112
+
113
+ return copied;
114
+ }
115
+
116
+ function setPromptMenuOpen(root: HTMLElement, open: boolean) {
117
+ const trigger = root.querySelector("[data-prompt-trigger]");
118
+ const menu = root.querySelector("[data-prompt-menu]");
119
+ if (!(trigger instanceof HTMLElement) || !(menu instanceof HTMLElement)) return;
120
+
121
+ trigger.setAttribute("aria-expanded", String(open));
122
+ menu.hidden = !open;
123
+ }
124
+
125
+ function closeOpenPromptMenus(event: Event) {
126
+ document.querySelectorAll("[data-prompt-dropdown]").forEach((root) => {
127
+ if (!(root instanceof HTMLElement)) return;
128
+ if (event.target instanceof Node && root.contains(event.target)) return;
129
+ setPromptMenuOpen(root, false);
130
+ });
131
+ }
132
+
91
133
  function wireInteractive() {
92
134
  requestAnimationFrame(() => {
93
135
  document.querySelectorAll(".fd-copy-btn").forEach((btn) => {
@@ -216,6 +258,91 @@ function wireInteractive() {
216
258
  document.addEventListener("pointerdown", closeOpenHoverLinks);
217
259
  document.addEventListener("focusin", closeOpenHoverLinks);
218
260
  }
261
+
262
+ document.querySelectorAll("[data-prompt-card]").forEach((root) => {
263
+ if (!(root instanceof HTMLElement)) return;
264
+ if (root.dataset.fdPromptBound === "true") return;
265
+ root.dataset.fdPromptBound = "true";
266
+
267
+ const promptTextNode = root.querySelector("[data-prompt-text]");
268
+ const promptText = promptTextNode?.textContent?.trim() ?? "";
269
+
270
+ const copyButton = root.querySelector("[data-prompt-copy]");
271
+ if (copyButton instanceof HTMLButtonElement && promptText) {
272
+ copyButton.addEventListener("click", async () => {
273
+ const defaultIcon = copyButton.querySelector(".fd-prompt-action-icon");
274
+ const copiedIcon = copyButton.querySelector(".fd-prompt-action-icon-copied");
275
+ const label = copyButton.querySelector("[data-prompt-copy-label]");
276
+ const copiedLabel = label?.getAttribute("data-prompt-copy-label") ?? "Copied";
277
+ const defaultLabel =
278
+ label?.getAttribute("data-prompt-default-label") ??
279
+ label?.textContent ??
280
+ "Copy prompt";
281
+
282
+ let copied = false;
283
+ try {
284
+ if (navigator.clipboard?.writeText) {
285
+ await navigator.clipboard.writeText(promptText);
286
+ copied = true;
287
+ } else {
288
+ copied = await fallbackCopyPromptText(promptText);
289
+ }
290
+ } catch {
291
+ copied = await fallbackCopyPromptText(promptText);
292
+ }
293
+
294
+ if (!copied || !(label instanceof HTMLElement)) return;
295
+
296
+ copyButton.dataset.copied = "true";
297
+ label.textContent = copiedLabel;
298
+ if (defaultIcon instanceof HTMLElement) defaultIcon.hidden = true;
299
+ if (copiedIcon instanceof HTMLElement) copiedIcon.hidden = false;
300
+
301
+ window.setTimeout(() => {
302
+ copyButton.dataset.copied = "false";
303
+ label.textContent = defaultLabel;
304
+ if (defaultIcon instanceof HTMLElement) defaultIcon.hidden = false;
305
+ if (copiedIcon instanceof HTMLElement) copiedIcon.hidden = true;
306
+ }, 2000);
307
+ });
308
+ }
309
+
310
+ const directOpen = root.querySelector("[data-prompt-open-direct]");
311
+ if (directOpen instanceof HTMLButtonElement && promptText) {
312
+ directOpen.addEventListener("click", () => {
313
+ const template = directOpen.getAttribute("data-url-template");
314
+ if (!template) return;
315
+ const url = template.replace(/\{prompt\}/g, encodeURIComponent(promptText));
316
+ window.open(url, "_blank", "noopener,noreferrer");
317
+ });
318
+ }
319
+
320
+ const dropdown = root.querySelector("[data-prompt-dropdown]");
321
+ const trigger = root.querySelector("[data-prompt-trigger]");
322
+ if (dropdown instanceof HTMLElement && trigger instanceof HTMLButtonElement) {
323
+ trigger.addEventListener("click", () => {
324
+ const isOpen = trigger.getAttribute("aria-expanded") === "true";
325
+ setPromptMenuOpen(dropdown, !isOpen);
326
+ });
327
+ }
328
+
329
+ root.querySelectorAll("[data-prompt-open-provider]").forEach((providerButton) => {
330
+ if (!(providerButton instanceof HTMLButtonElement) || !promptText) return;
331
+ providerButton.addEventListener("click", () => {
332
+ const template = providerButton.getAttribute("data-url-template");
333
+ if (!template) return;
334
+ const url = template.replace(/\{prompt\}/g, encodeURIComponent(promptText));
335
+ window.open(url, "_blank", "noopener,noreferrer");
336
+ if (dropdown instanceof HTMLElement) setPromptMenuOpen(dropdown, false);
337
+ });
338
+ });
339
+ });
340
+
341
+ if (document.documentElement.dataset.fdPromptGlobalBound !== "true") {
342
+ document.documentElement.dataset.fdPromptGlobalBound = "true";
343
+ document.addEventListener("pointerdown", closeOpenPromptMenus);
344
+ document.addEventListener("focusin", closeOpenPromptMenus);
345
+ }
219
346
  });
220
347
  }
221
348
 
package/styles/docs.css CHANGED
@@ -1002,6 +1002,189 @@ samp {
1002
1002
  color: var(--color-fd-foreground);
1003
1003
  }
1004
1004
 
1005
+ /* ─── Prompt Cards ─────────────────────────────────────────────────── */
1006
+
1007
+ .fd-prompt {
1008
+ display: flex;
1009
+ flex-direction: column;
1010
+ gap: 0.875rem;
1011
+ margin: 1.25rem 0;
1012
+ padding: 1rem;
1013
+ border: 1px solid var(--color-fd-border);
1014
+ border-radius: 0.75rem;
1015
+ background: color-mix(in srgb, var(--color-fd-card) 78%, transparent);
1016
+ }
1017
+
1018
+ .fd-prompt-header {
1019
+ display: flex;
1020
+ align-items: flex-start;
1021
+ gap: 0.75rem;
1022
+ }
1023
+
1024
+ .fd-prompt-icon,
1025
+ .fd-prompt-action-icon,
1026
+ .fd-prompt-menu-icon {
1027
+ display: inline-flex;
1028
+ align-items: center;
1029
+ justify-content: center;
1030
+ flex-shrink: 0;
1031
+ }
1032
+
1033
+ .fd-prompt-icon {
1034
+ width: 1.75rem;
1035
+ height: 1.75rem;
1036
+ border-radius: 0.5rem;
1037
+ border: 1px solid color-mix(in srgb, var(--color-fd-border) 80%, transparent);
1038
+ background: color-mix(in srgb, var(--color-fd-background) 55%, transparent);
1039
+ color: var(--color-fd-foreground);
1040
+ }
1041
+
1042
+ .fd-prompt-icon svg,
1043
+ .fd-prompt-action-icon svg,
1044
+ .fd-prompt-menu-icon svg {
1045
+ width: 1rem;
1046
+ height: 1rem;
1047
+ }
1048
+
1049
+ .fd-prompt-copy {
1050
+ min-width: 0;
1051
+ }
1052
+
1053
+ .fd-prompt-title {
1054
+ margin: 0;
1055
+ color: var(--color-fd-foreground);
1056
+ font-size: 0.9375rem;
1057
+ font-weight: 600;
1058
+ line-height: 1.35;
1059
+ }
1060
+
1061
+ .fd-prompt-description {
1062
+ margin: 0.25rem 0 0;
1063
+ color: var(--color-fd-muted-foreground);
1064
+ font-size: 0.875rem;
1065
+ line-height: 1.55;
1066
+ }
1067
+
1068
+ .fd-prompt-body {
1069
+ margin: 0;
1070
+ padding: 0.875rem 1rem;
1071
+ border-radius: 0.625rem;
1072
+ border: 1px solid color-mix(in srgb, var(--color-fd-border) 82%, transparent);
1073
+ background: color-mix(in srgb, var(--color-fd-background) 45%, transparent);
1074
+ overflow-x: auto;
1075
+ }
1076
+
1077
+ .fd-prompt-body > pre.fd-prompt-code {
1078
+ margin: 0;
1079
+ padding: 0 !important;
1080
+ border: 0 !important;
1081
+ border-radius: 0 !important;
1082
+ background: transparent !important;
1083
+ box-shadow: none !important;
1084
+ color: var(--color-fd-foreground);
1085
+ font-size: 0.875rem;
1086
+ line-height: 1.65;
1087
+ white-space: pre-wrap;
1088
+ word-break: break-word;
1089
+ font-family: var(
1090
+ --fd-font-mono,
1091
+ ui-monospace,
1092
+ "SF Mono",
1093
+ SFMono-Regular,
1094
+ Menlo,
1095
+ Consolas,
1096
+ monospace
1097
+ );
1098
+ }
1099
+
1100
+ .fd-prompt-actions {
1101
+ display: flex;
1102
+ flex-wrap: wrap;
1103
+ gap: 0.5rem;
1104
+ align-items: center;
1105
+ justify-content: flex-end;
1106
+ }
1107
+
1108
+ .fd-prompt-action-btn {
1109
+ display: inline-flex;
1110
+ align-items: center;
1111
+ gap: 0.4375rem;
1112
+ min-height: 2rem;
1113
+ padding: 0.375rem 0.75rem;
1114
+ border: 1px solid var(--color-fd-border);
1115
+ border-radius: 0.375rem;
1116
+ background: var(--color-fd-secondary);
1117
+ color: var(--color-fd-muted-foreground);
1118
+ font-size: 0.8125rem;
1119
+ font-weight: 500;
1120
+ line-height: 1;
1121
+ cursor: pointer;
1122
+ transition: color 0.15s, background 0.15s, border-color 0.15s;
1123
+ }
1124
+
1125
+ .fd-prompt-action-btn:hover {
1126
+ color: var(--color-fd-accent-foreground);
1127
+ background: var(--color-fd-accent);
1128
+ }
1129
+
1130
+ .fd-prompt-action-btn[data-copied="true"] {
1131
+ color: var(--color-fd-foreground);
1132
+ }
1133
+
1134
+ .fd-prompt-action-icon-copied[hidden] {
1135
+ display: none !important;
1136
+ }
1137
+
1138
+ .fd-prompt-dropdown {
1139
+ position: relative;
1140
+ }
1141
+
1142
+ .fd-prompt-menu {
1143
+ position: absolute;
1144
+ top: calc(100% + 0.375rem);
1145
+ right: 0;
1146
+ z-index: 50;
1147
+ min-width: 220px;
1148
+ padding: 0.375rem;
1149
+ background: var(--color-fd-popover, var(--color-fd-background));
1150
+ border: 1px solid var(--color-fd-border);
1151
+ border-radius: 0.5rem;
1152
+ box-shadow: 0 4px 24px hsl(0 0% 0% / 0.15);
1153
+ display: flex;
1154
+ flex-direction: column;
1155
+ gap: 0.125rem;
1156
+ }
1157
+
1158
+ .fd-prompt-menu[hidden] {
1159
+ display: none !important;
1160
+ }
1161
+
1162
+ .fd-prompt-menu-item {
1163
+ display: flex;
1164
+ align-items: center;
1165
+ gap: 0.5rem;
1166
+ width: 100%;
1167
+ padding: 0.35rem 0.625rem;
1168
+ font-size: 0.8125rem;
1169
+ font-weight: 400;
1170
+ color: var(--color-fd-foreground);
1171
+ background: transparent;
1172
+ border: none;
1173
+ border-radius: 0.25rem;
1174
+ cursor: pointer;
1175
+ text-align: left;
1176
+ transition: background 0.1s, color 0.1s;
1177
+ }
1178
+
1179
+ .fd-prompt-menu-item:hover {
1180
+ background: var(--color-fd-accent);
1181
+ color: var(--color-fd-accent-foreground);
1182
+ }
1183
+
1184
+ .fd-prompt-menu-label {
1185
+ flex: 1;
1186
+ }
1187
+
1005
1188
  /* ─── Theme Toggle ───────────────────────────────────────────────────── */
1006
1189
 
1007
1190
  .fd-theme-toggle {
@@ -781,6 +781,66 @@ code:not(pre code) {
781
781
  color: #1f2937;
782
782
  }
783
783
 
784
+ /* ─── Prompt (pixel-border theme) ──────────────────────────────── */
785
+
786
+ .fd-prompt {
787
+ border-radius: 0 !important;
788
+ border: 1px solid var(--color-fd-border, #262626) !important;
789
+ background: var(--color-fd-card, var(--color-fd-background)) !important;
790
+ box-shadow: 4px 4px 0 0 var(--color-fd-border, #262626) !important;
791
+ }
792
+
793
+ .fd-prompt-body {
794
+ border-radius: 0 !important;
795
+ border-top: 1px solid var(--color-fd-border, #262626) !important;
796
+ background: var(--color-fd-background, #0c0c0c) !important;
797
+ }
798
+
799
+ .fd-prompt-action-btn {
800
+ text-transform: uppercase !important;
801
+ box-shadow: 2px 2px 0 0 var(--color-fd-border, #262626) !important;
802
+ font-family: var(--fd-font-mono, ui-monospace, monospace) !important;
803
+ border-radius: 0 !important;
804
+ font-size: 0.75rem !important;
805
+ letter-spacing: 0.03em !important;
806
+ background: var(--color-fd-background) !important;
807
+ color: var(--color-fd-foreground) !important;
808
+ border: 1px solid var(--color-fd-border) !important;
809
+ }
810
+
811
+ .fd-prompt-action-btn:hover {
812
+ background: var(--color-fd-muted) !important;
813
+ color: var(--color-fd-foreground) !important;
814
+ }
815
+
816
+ .fd-prompt-menu {
817
+ border-radius: 0 !important;
818
+ box-shadow: 4px 4px 0 0 var(--color-fd-border, hsl(0 0% 15%)), 0 4px 24px hsl(0 0% 0% / 0.5) !important;
819
+ background: var(--color-fd-popover) !important;
820
+ border: 2px solid var(--color-fd-border) !important;
821
+ padding: 0.375rem !important;
822
+ }
823
+
824
+ .fd-prompt-menu-item {
825
+ border-radius: 0 !important;
826
+ font-size: 0.8rem !important;
827
+ font-family: var(--fd-font-mono, ui-monospace, monospace) !important;
828
+ text-transform: uppercase !important;
829
+ letter-spacing: 0.03em !important;
830
+ color: var(--color-fd-popover-foreground) !important;
831
+ background: transparent !important;
832
+ border-top: 1px solid var(--color-fd-border) !important;
833
+ }
834
+
835
+ .fd-prompt-menu-item:first-child {
836
+ border-top: none !important;
837
+ }
838
+
839
+ .fd-prompt-menu-item:hover {
840
+ background: var(--color-fd-muted) !important;
841
+ color: var(--color-fd-foreground) !important;
842
+ }
843
+
784
844
  /* ─── Feedback (pixel-border theme) ──────────────────────────────── */
785
845
 
786
846
  .fd-feedback-input,