@farming-labs/svelte-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/svelte-theme",
3
- "version": "0.1.57",
3
+ "version": "0.1.59",
4
4
  "description": "Svelte UI components for @farming-labs/docs — layout, sidebar, TOC, search, and theme toggle",
5
5
  "keywords": [
6
6
  "docs",
@@ -112,8 +112,8 @@
112
112
  "dependencies": {
113
113
  "gray-matter": "^4.0.3",
114
114
  "sugar-high": "^0.9.5",
115
- "@farming-labs/docs": "0.1.57",
116
- "@farming-labs/svelte": "0.1.57"
115
+ "@farming-labs/docs": "0.1.59",
116
+ "@farming-labs/svelte": "0.1.59"
117
117
  },
118
118
  "peerDependencies": {
119
119
  "svelte": ">=5.0.0"
@@ -59,6 +59,49 @@
59
59
  });
60
60
  }
61
61
 
62
+ async function fallbackCopyPromptText(text) {
63
+ const textarea = document.createElement("textarea");
64
+ textarea.value = text;
65
+ textarea.setAttribute("readonly", "");
66
+ textarea.style.position = "fixed";
67
+ textarea.style.top = "0";
68
+ textarea.style.left = "0";
69
+ textarea.style.opacity = "0";
70
+ textarea.style.pointerEvents = "none";
71
+ document.body.appendChild(textarea);
72
+ textarea.focus();
73
+ textarea.select();
74
+
75
+ let copied = false;
76
+ try {
77
+ copied = document.execCommand("copy");
78
+ } catch {
79
+ copied = false;
80
+ } finally {
81
+ document.body.removeChild(textarea);
82
+ }
83
+
84
+ return copied;
85
+ }
86
+
87
+ function setPromptMenuOpen(root, open) {
88
+ if (!(root instanceof HTMLElement)) return;
89
+ const trigger = root.querySelector("[data-prompt-trigger]");
90
+ const menu = root.querySelector("[data-prompt-menu]");
91
+ if (!(trigger instanceof HTMLElement) || !(menu instanceof HTMLElement)) return;
92
+
93
+ trigger.setAttribute("aria-expanded", String(open));
94
+ menu.hidden = !open;
95
+ }
96
+
97
+ function closeOpenPromptMenus(event) {
98
+ document.querySelectorAll("[data-prompt-dropdown]").forEach((root) => {
99
+ if (!(root instanceof HTMLElement)) return;
100
+ if (event.target instanceof Node && root.contains(event.target)) return;
101
+ setPromptMenuOpen(root, false);
102
+ });
103
+ }
104
+
62
105
  onMount(() => {
63
106
  scanHeadings();
64
107
  wireInteractive();
@@ -203,6 +246,91 @@
203
246
  document.addEventListener("pointerdown", closeOpenHoverLinks);
204
247
  document.addEventListener("focusin", closeOpenHoverLinks);
205
248
  }
249
+
250
+ document.querySelectorAll("[data-prompt-card]").forEach((root) => {
251
+ if (!(root instanceof HTMLElement)) return;
252
+ if (root.dataset.fdPromptBound === "true") return;
253
+ root.dataset.fdPromptBound = "true";
254
+
255
+ const promptTextNode = root.querySelector("[data-prompt-text]");
256
+ const promptText = promptTextNode?.textContent?.trim() ?? "";
257
+
258
+ const copyButton = root.querySelector("[data-prompt-copy]");
259
+ if (copyButton instanceof HTMLButtonElement && promptText) {
260
+ copyButton.addEventListener("click", async () => {
261
+ const defaultIcon = copyButton.querySelector(".fd-prompt-action-icon");
262
+ const copiedIcon = copyButton.querySelector(".fd-prompt-action-icon-copied");
263
+ const label = copyButton.querySelector("[data-prompt-copy-label]");
264
+ const copiedLabel = label?.getAttribute("data-prompt-copy-label") ?? "Copied";
265
+ const defaultLabel =
266
+ label?.getAttribute("data-prompt-default-label") ??
267
+ label?.textContent ??
268
+ "Copy prompt";
269
+
270
+ let copied = false;
271
+ try {
272
+ if (navigator.clipboard?.writeText) {
273
+ await navigator.clipboard.writeText(promptText);
274
+ copied = true;
275
+ } else {
276
+ copied = await fallbackCopyPromptText(promptText);
277
+ }
278
+ } catch {
279
+ copied = await fallbackCopyPromptText(promptText);
280
+ }
281
+
282
+ if (!copied || !(label instanceof HTMLElement)) return;
283
+
284
+ copyButton.dataset.copied = "true";
285
+ label.textContent = copiedLabel;
286
+ if (defaultIcon instanceof HTMLElement) defaultIcon.hidden = true;
287
+ if (copiedIcon instanceof HTMLElement) copiedIcon.hidden = false;
288
+
289
+ window.setTimeout(() => {
290
+ copyButton.dataset.copied = "false";
291
+ label.textContent = defaultLabel;
292
+ if (defaultIcon instanceof HTMLElement) defaultIcon.hidden = false;
293
+ if (copiedIcon instanceof HTMLElement) copiedIcon.hidden = true;
294
+ }, 2000);
295
+ });
296
+ }
297
+
298
+ const directOpen = root.querySelector("[data-prompt-open-direct]");
299
+ if (directOpen instanceof HTMLButtonElement && promptText) {
300
+ directOpen.addEventListener("click", () => {
301
+ const template = directOpen.getAttribute("data-url-template");
302
+ if (!template) return;
303
+ const url = template.replace(/\{prompt\}/g, encodeURIComponent(promptText));
304
+ window.open(url, "_blank", "noopener,noreferrer");
305
+ });
306
+ }
307
+
308
+ const dropdown = root.querySelector("[data-prompt-dropdown]");
309
+ const trigger = root.querySelector("[data-prompt-trigger]");
310
+ if (dropdown instanceof HTMLElement && trigger instanceof HTMLButtonElement) {
311
+ trigger.addEventListener("click", () => {
312
+ const isOpen = trigger.getAttribute("aria-expanded") === "true";
313
+ setPromptMenuOpen(dropdown, !isOpen);
314
+ });
315
+ }
316
+
317
+ root.querySelectorAll("[data-prompt-open-provider]").forEach((providerButton) => {
318
+ if (!(providerButton instanceof HTMLButtonElement) || !promptText) return;
319
+ providerButton.addEventListener("click", () => {
320
+ const template = providerButton.getAttribute("data-url-template");
321
+ if (!template) return;
322
+ const url = template.replace(/\{prompt\}/g, encodeURIComponent(promptText));
323
+ window.open(url, "_blank", "noopener,noreferrer");
324
+ if (dropdown instanceof HTMLElement) setPromptMenuOpen(dropdown, false);
325
+ });
326
+ });
327
+ });
328
+
329
+ if (document.documentElement.dataset.fdPromptGlobalBound !== "true") {
330
+ document.documentElement.dataset.fdPromptGlobalBound = "true";
331
+ document.addEventListener("pointerdown", closeOpenPromptMenus);
332
+ document.addEventListener("focusin", closeOpenPromptMenus);
333
+ }
206
334
  });
207
335
  }
208
336
  </script>
package/styles/docs.css CHANGED
@@ -997,6 +997,189 @@ samp {
997
997
  color: var(--color-fd-foreground);
998
998
  }
999
999
 
1000
+ /* ─── Prompt Cards ─────────────────────────────────────────────────── */
1001
+
1002
+ .fd-prompt {
1003
+ display: flex;
1004
+ flex-direction: column;
1005
+ gap: 0.875rem;
1006
+ margin: 1.25rem 0;
1007
+ padding: 1rem;
1008
+ border: 1px solid var(--color-fd-border);
1009
+ border-radius: 0.75rem;
1010
+ background: color-mix(in srgb, var(--color-fd-card) 78%, transparent);
1011
+ }
1012
+
1013
+ .fd-prompt-header {
1014
+ display: flex;
1015
+ align-items: flex-start;
1016
+ gap: 0.75rem;
1017
+ }
1018
+
1019
+ .fd-prompt-icon,
1020
+ .fd-prompt-action-icon,
1021
+ .fd-prompt-menu-icon {
1022
+ display: inline-flex;
1023
+ align-items: center;
1024
+ justify-content: center;
1025
+ flex-shrink: 0;
1026
+ }
1027
+
1028
+ .fd-prompt-icon {
1029
+ width: 1.75rem;
1030
+ height: 1.75rem;
1031
+ border-radius: 0.5rem;
1032
+ border: 1px solid color-mix(in srgb, var(--color-fd-border) 80%, transparent);
1033
+ background: color-mix(in srgb, var(--color-fd-background) 55%, transparent);
1034
+ color: var(--color-fd-foreground);
1035
+ }
1036
+
1037
+ .fd-prompt-icon svg,
1038
+ .fd-prompt-action-icon svg,
1039
+ .fd-prompt-menu-icon svg {
1040
+ width: 1rem;
1041
+ height: 1rem;
1042
+ }
1043
+
1044
+ .fd-prompt-copy {
1045
+ min-width: 0;
1046
+ }
1047
+
1048
+ .fd-prompt-title {
1049
+ margin: 0;
1050
+ color: var(--color-fd-foreground);
1051
+ font-size: 0.9375rem;
1052
+ font-weight: 600;
1053
+ line-height: 1.35;
1054
+ }
1055
+
1056
+ .fd-prompt-description {
1057
+ margin: 0.25rem 0 0;
1058
+ color: var(--color-fd-muted-foreground);
1059
+ font-size: 0.875rem;
1060
+ line-height: 1.55;
1061
+ }
1062
+
1063
+ .fd-prompt-body {
1064
+ margin: 0;
1065
+ padding: 0.875rem 1rem;
1066
+ border-radius: 0.625rem;
1067
+ border: 1px solid color-mix(in srgb, var(--color-fd-border) 82%, transparent);
1068
+ background: color-mix(in srgb, var(--color-fd-background) 45%, transparent);
1069
+ overflow-x: auto;
1070
+ }
1071
+
1072
+ .fd-prompt-body > pre.fd-prompt-code {
1073
+ margin: 0;
1074
+ padding: 0 !important;
1075
+ border: 0 !important;
1076
+ border-radius: 0 !important;
1077
+ background: transparent !important;
1078
+ box-shadow: none !important;
1079
+ color: var(--color-fd-foreground);
1080
+ font-size: 0.875rem;
1081
+ line-height: 1.65;
1082
+ white-space: pre-wrap;
1083
+ word-break: break-word;
1084
+ font-family: var(
1085
+ --fd-font-mono,
1086
+ ui-monospace,
1087
+ "SF Mono",
1088
+ SFMono-Regular,
1089
+ Menlo,
1090
+ Consolas,
1091
+ monospace
1092
+ );
1093
+ }
1094
+
1095
+ .fd-prompt-actions {
1096
+ display: flex;
1097
+ flex-wrap: wrap;
1098
+ gap: 0.5rem;
1099
+ align-items: center;
1100
+ justify-content: flex-end;
1101
+ }
1102
+
1103
+ .fd-prompt-action-btn {
1104
+ display: inline-flex;
1105
+ align-items: center;
1106
+ gap: 0.4375rem;
1107
+ min-height: 2rem;
1108
+ padding: 0.375rem 0.75rem;
1109
+ border: 1px solid var(--color-fd-border);
1110
+ border-radius: 0.375rem;
1111
+ background: var(--color-fd-secondary);
1112
+ color: var(--color-fd-muted-foreground);
1113
+ font-size: 0.8125rem;
1114
+ font-weight: 500;
1115
+ line-height: 1;
1116
+ cursor: pointer;
1117
+ transition: color 0.15s, background 0.15s, border-color 0.15s;
1118
+ }
1119
+
1120
+ .fd-prompt-action-btn:hover {
1121
+ color: var(--color-fd-accent-foreground);
1122
+ background: var(--color-fd-accent);
1123
+ }
1124
+
1125
+ .fd-prompt-action-btn[data-copied="true"] {
1126
+ color: var(--color-fd-foreground);
1127
+ }
1128
+
1129
+ .fd-prompt-action-icon-copied[hidden] {
1130
+ display: none !important;
1131
+ }
1132
+
1133
+ .fd-prompt-dropdown {
1134
+ position: relative;
1135
+ }
1136
+
1137
+ .fd-prompt-menu {
1138
+ position: absolute;
1139
+ top: calc(100% + 0.375rem);
1140
+ right: 0;
1141
+ z-index: 50;
1142
+ min-width: 220px;
1143
+ padding: 0.375rem;
1144
+ background: var(--color-fd-popover, var(--color-fd-background));
1145
+ border: 1px solid var(--color-fd-border);
1146
+ border-radius: 0.5rem;
1147
+ box-shadow: 0 4px 24px hsl(0 0% 0% / 0.15);
1148
+ display: flex;
1149
+ flex-direction: column;
1150
+ gap: 0.125rem;
1151
+ }
1152
+
1153
+ .fd-prompt-menu[hidden] {
1154
+ display: none !important;
1155
+ }
1156
+
1157
+ .fd-prompt-menu-item {
1158
+ display: flex;
1159
+ align-items: center;
1160
+ gap: 0.5rem;
1161
+ width: 100%;
1162
+ padding: 0.35rem 0.625rem;
1163
+ font-size: 0.8125rem;
1164
+ font-weight: 400;
1165
+ color: var(--color-fd-foreground);
1166
+ background: transparent;
1167
+ border: none;
1168
+ border-radius: 0.25rem;
1169
+ cursor: pointer;
1170
+ text-align: left;
1171
+ transition: background 0.1s, color 0.1s;
1172
+ }
1173
+
1174
+ .fd-prompt-menu-item:hover {
1175
+ background: var(--color-fd-accent);
1176
+ color: var(--color-fd-accent-foreground);
1177
+ }
1178
+
1179
+ .fd-prompt-menu-label {
1180
+ flex: 1;
1181
+ }
1182
+
1000
1183
  /* ─── Theme Toggle ───────────────────────────────────────────────────── */
1001
1184
 
1002
1185
  .fd-theme-toggle {
@@ -863,6 +863,66 @@ code:not(pre code) {
863
863
  border-top: none !important;
864
864
  }
865
865
 
866
+ /* ─── Prompt (pixel-border theme) ──────────────────────────────── */
867
+
868
+ .fd-prompt {
869
+ border-radius: 0 !important;
870
+ border: 1px solid var(--color-fd-border, #262626) !important;
871
+ background: var(--color-fd-card, var(--color-fd-background)) !important;
872
+ box-shadow: 4px 4px 0 0 var(--color-fd-border, #262626) !important;
873
+ }
874
+
875
+ .fd-prompt-body {
876
+ border-radius: 0 !important;
877
+ border-top: 1px solid var(--color-fd-border, #262626) !important;
878
+ background: var(--color-fd-background, #0c0c0c) !important;
879
+ }
880
+
881
+ .fd-prompt-action-btn {
882
+ text-transform: uppercase !important;
883
+ box-shadow: 2px 2px 0 0 var(--color-fd-border, #262626) !important;
884
+ font-family: var(--fd-font-mono, ui-monospace, monospace) !important;
885
+ border-radius: 0 !important;
886
+ font-size: 0.75rem !important;
887
+ letter-spacing: 0.03em !important;
888
+ background: var(--color-fd-background) !important;
889
+ color: var(--color-fd-foreground) !important;
890
+ border: 1px solid var(--color-fd-border) !important;
891
+ }
892
+
893
+ .fd-prompt-action-btn:hover {
894
+ background: var(--color-fd-muted) !important;
895
+ color: var(--color-fd-foreground) !important;
896
+ }
897
+
898
+ .fd-prompt-menu {
899
+ border-radius: 0 !important;
900
+ box-shadow: 4px 4px 0 0 var(--color-fd-border, hsl(0 0% 15%)), 0 4px 24px hsl(0 0% 0% / 0.5) !important;
901
+ background: var(--color-fd-popover) !important;
902
+ border: 2px solid var(--color-fd-border) !important;
903
+ padding: 0.375rem !important;
904
+ }
905
+
906
+ .fd-prompt-menu-item {
907
+ border-radius: 0 !important;
908
+ font-size: 0.8rem !important;
909
+ font-family: var(--fd-font-mono, ui-monospace, monospace) !important;
910
+ text-transform: uppercase !important;
911
+ letter-spacing: 0.03em !important;
912
+ color: var(--color-fd-popover-foreground) !important;
913
+ background: transparent !important;
914
+ border-top: 1px solid var(--color-fd-border) !important;
915
+ }
916
+
917
+ .fd-prompt-menu-item:first-child {
918
+ border-top: none !important;
919
+ }
920
+
921
+ .fd-prompt-menu-item:hover {
922
+ background: var(--color-fd-muted) !important;
923
+ color: var(--color-fd-foreground) !important;
924
+ }
925
+
866
926
  /* ─── Feedback (pixel-border theme) ──────────────────────────────── */
867
927
 
868
928
  .fd-feedback-input,