@farming-labs/nuxt-theme 0.0.50 → 0.0.51

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.50",
3
+ "version": "0.0.51",
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.50"
63
+ "@farming-labs/docs": "0.0.51"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "nuxt": ">=3.0.0",
@@ -70,6 +70,24 @@ function scanHeadings() {
70
70
  });
71
71
  }
72
72
 
73
+ function setHoverLinkOpen(root: HTMLElement, open: boolean) {
74
+ const trigger = root.querySelector(".fd-hover-link-trigger");
75
+ const popover = root.querySelector(".fd-hover-link-popover");
76
+ if (!(trigger instanceof HTMLElement) || !(popover instanceof HTMLElement)) return;
77
+
78
+ root.classList.toggle("fd-hover-link-open", open);
79
+ trigger.setAttribute("aria-expanded", String(open));
80
+ popover.setAttribute("aria-hidden", String(!open));
81
+ }
82
+
83
+ function closeOpenHoverLinks(event: Event) {
84
+ document.querySelectorAll("[data-hover-link].fd-hover-link-open").forEach((root) => {
85
+ if (!(root instanceof HTMLElement)) return;
86
+ if (event.target instanceof Node && root.contains(event.target)) return;
87
+ setHoverLinkOpen(root, false);
88
+ });
89
+ }
90
+
73
91
  function wireInteractive() {
74
92
  requestAnimationFrame(() => {
75
93
  document.querySelectorAll(".fd-copy-btn").forEach((btn) => {
@@ -122,6 +140,82 @@ function wireInteractive() {
122
140
  const localized = withLang(href);
123
141
  if (localized) link.setAttribute("href", localized);
124
142
  });
143
+
144
+ document.querySelectorAll("[data-hover-link]").forEach((root) => {
145
+ if (!(root instanceof HTMLElement)) return;
146
+ if (root.dataset.fdHoverLinkBound === "true") return;
147
+ root.dataset.fdHoverLinkBound = "true";
148
+
149
+ const trigger = root.querySelector(".fd-hover-link-trigger");
150
+ const popover = root.querySelector(".fd-hover-link-popover");
151
+ if (!(trigger instanceof HTMLElement) || !(popover instanceof HTMLElement)) return;
152
+
153
+ let closeTimer = 0;
154
+ const containsTarget = (target: EventTarget | null) => target instanceof Node && root.contains(target);
155
+ const clearCloseTimer = () => {
156
+ if (closeTimer !== 0) {
157
+ window.clearTimeout(closeTimer);
158
+ closeTimer = 0;
159
+ }
160
+ };
161
+
162
+ const openPopover = () => {
163
+ clearCloseTimer();
164
+ setHoverLinkOpen(root, true);
165
+ };
166
+ const closePopover = () => {
167
+ clearCloseTimer();
168
+ setHoverLinkOpen(root, false);
169
+ };
170
+ const closePopoverSoon = () => {
171
+ clearCloseTimer();
172
+ closeTimer = window.setTimeout(closePopover, 90);
173
+ };
174
+
175
+ trigger.addEventListener("pointerenter", openPopover);
176
+ trigger.addEventListener("pointerleave", (event) => {
177
+ if (containsTarget(event.relatedTarget)) return;
178
+ closePopoverSoon();
179
+ });
180
+ trigger.addEventListener("focus", (event) => {
181
+ if (!(event.currentTarget instanceof HTMLElement)) return;
182
+ if (typeof event.currentTarget.matches === "function" && !event.currentTarget.matches(":focus-visible")) {
183
+ return;
184
+ }
185
+ openPopover();
186
+ });
187
+ trigger.addEventListener("blur", (event) => {
188
+ if (containsTarget(event.relatedTarget)) return;
189
+ closePopoverSoon();
190
+ });
191
+ trigger.addEventListener("click", (event) => {
192
+ event.preventDefault();
193
+ openPopover();
194
+ });
195
+
196
+ popover.addEventListener("pointerenter", openPopover);
197
+ popover.addEventListener("pointerleave", (event) => {
198
+ if (containsTarget(event.relatedTarget)) return;
199
+ closePopoverSoon();
200
+ });
201
+ popover.addEventListener("focusin", openPopover);
202
+ popover.addEventListener("focusout", (event) => {
203
+ if (containsTarget(event.relatedTarget)) return;
204
+ closePopoverSoon();
205
+ });
206
+
207
+ root.addEventListener("keydown", (event) => {
208
+ if (event.key !== "Escape") return;
209
+ closePopover();
210
+ });
211
+ });
212
+
213
+ if (document.documentElement.dataset.fdHoverLinkGlobalBound !== "true") {
214
+ document.documentElement.dataset.fdHoverLinkGlobalBound = "true";
215
+
216
+ document.addEventListener("pointerdown", closeOpenHoverLinks);
217
+ document.addEventListener("focusin", closeOpenHoverLinks);
218
+ }
125
219
  });
126
220
  }
127
221
 
@@ -30,6 +30,7 @@ const ColorfulUIDefaults = {
30
30
  components: {
31
31
  Callout: { variant: "soft", icon: true },
32
32
  CodeBlock: { showCopyButton: true },
33
+ HoverLink: { linkLabel: "Open page", showIndicator: false },
33
34
  Tabs: { style: "default" },
34
35
  },
35
36
  };
@@ -30,6 +30,7 @@ const DarksharpUIDefaults = {
30
30
  components: {
31
31
  Callout: { variant: "soft", icon: true },
32
32
  CodeBlock: { showCopyButton: true },
33
+ HoverLink: { linkLabel: "Open page", showIndicator: false },
33
34
  Tabs: { style: "default" },
34
35
  },
35
36
  };
@@ -30,6 +30,7 @@ const DefaultUIDefaults = {
30
30
  components: {
31
31
  Callout: { variant: "soft", icon: true },
32
32
  CodeBlock: { showCopyButton: true },
33
+ HoverLink: { linkLabel: "Open page", showIndicator: false },
33
34
  Tabs: { style: "default" },
34
35
  },
35
36
  };
@@ -30,6 +30,7 @@ const GreenTreeUIDefaults = {
30
30
  components: {
31
31
  Callout: { variant: "soft", icon: true },
32
32
  CodeBlock: { showCopyButton: true },
33
+ HoverLink: { linkLabel: "Open page", showIndicator: false },
33
34
  Tabs: { style: "default" },
34
35
  },
35
36
  };
@@ -27,7 +27,9 @@ const PixelBorderUIDefaults = {
27
27
  toc: { enabled: true, depth: 3 },
28
28
  header: { height: 56, sticky: true },
29
29
  },
30
- components: {},
30
+ components: {
31
+ HoverLink: { linkLabel: "Open page", showIndicator: false },
32
+ },
31
33
  };
32
34
 
33
35
  export const pixelBorder = createTheme({
package/styles/docs.css CHANGED
@@ -919,6 +919,206 @@ samp {
919
919
  opacity: 0.8;
920
920
  }
921
921
 
922
+ .fd-hover-link {
923
+ position: relative;
924
+ display: inline-block;
925
+ vertical-align: baseline;
926
+ max-width: 100%;
927
+ }
928
+
929
+ .fd-hover-link-trigger {
930
+ display: inline !important;
931
+ border: none;
932
+ background: transparent;
933
+ padding: 0;
934
+ margin: 0;
935
+ color: var(--color-fd-foreground);
936
+ cursor: pointer;
937
+ text-decoration: underline;
938
+ text-decoration-style: dashed;
939
+ text-decoration-thickness: 0.08em;
940
+ text-underline-offset: 0.22em;
941
+ text-decoration-color: color-mix(in srgb, var(--color-fd-foreground) 46%, transparent);
942
+ font: inherit;
943
+ line-height: inherit;
944
+ vertical-align: baseline;
945
+ appearance: none;
946
+ transition: text-decoration-color 180ms ease, opacity 180ms ease;
947
+ }
948
+
949
+ .fd-hover-link-trigger:hover,
950
+ .fd-hover-link-trigger:focus-visible,
951
+ .fd-hover-link-open > .fd-hover-link-trigger {
952
+ text-decoration-color: color-mix(in srgb, var(--color-fd-foreground) 68%, transparent);
953
+ }
954
+
955
+ .fd-hover-link-trigger:focus-visible {
956
+ outline: none;
957
+ }
958
+
959
+ .fd-hover-link-popover {
960
+ --fd-hover-link-rest-x: -50%;
961
+ --fd-hover-link-rest-y: 8px;
962
+ --fd-hover-link-open-x: -50%;
963
+ --fd-hover-link-open-y: 0;
964
+ position: absolute;
965
+ top: calc(100% + var(--fd-hover-link-side-offset, 12px));
966
+ left: 50%;
967
+ z-index: 40;
968
+ width: min(22rem, calc(100vw - 2rem));
969
+ max-width: min(22rem, calc(100vw - 2rem));
970
+ opacity: 0;
971
+ visibility: hidden;
972
+ pointer-events: none;
973
+ transform: translate3d(var(--fd-hover-link-rest-x), var(--fd-hover-link-rest-y), 0);
974
+ transition: opacity 180ms ease, transform 180ms ease, visibility 180ms linear;
975
+ }
976
+
977
+ .fd-hover-link[data-align="start"] > .fd-hover-link-popover {
978
+ left: 0;
979
+ --fd-hover-link-rest-x: 0;
980
+ --fd-hover-link-open-x: 0;
981
+ }
982
+
983
+ .fd-hover-link[data-align="end"] > .fd-hover-link-popover {
984
+ left: auto;
985
+ right: 0;
986
+ --fd-hover-link-rest-x: 0;
987
+ --fd-hover-link-open-x: 0;
988
+ }
989
+
990
+ .fd-hover-link[data-side="top"] > .fd-hover-link-popover {
991
+ top: auto;
992
+ bottom: calc(100% + var(--fd-hover-link-side-offset, 12px));
993
+ --fd-hover-link-rest-y: -8px;
994
+ --fd-hover-link-open-y: 0;
995
+ }
996
+
997
+ .fd-hover-link[data-side="right"] > .fd-hover-link-popover {
998
+ top: 50%;
999
+ left: calc(100% + var(--fd-hover-link-side-offset, 12px));
1000
+ right: auto;
1001
+ --fd-hover-link-rest-x: 8px;
1002
+ --fd-hover-link-rest-y: -50%;
1003
+ --fd-hover-link-open-x: 0;
1004
+ --fd-hover-link-open-y: -50%;
1005
+ }
1006
+
1007
+ .fd-hover-link[data-side="right"][data-align="start"] > .fd-hover-link-popover {
1008
+ top: 0;
1009
+ --fd-hover-link-rest-y: 0;
1010
+ --fd-hover-link-open-y: 0;
1011
+ }
1012
+
1013
+ .fd-hover-link[data-side="right"][data-align="end"] > .fd-hover-link-popover {
1014
+ top: auto;
1015
+ bottom: 0;
1016
+ --fd-hover-link-rest-y: 0;
1017
+ --fd-hover-link-open-y: 0;
1018
+ }
1019
+
1020
+ .fd-hover-link[data-side="left"] > .fd-hover-link-popover {
1021
+ top: 50%;
1022
+ left: auto;
1023
+ right: calc(100% + var(--fd-hover-link-side-offset, 12px));
1024
+ --fd-hover-link-rest-x: -8px;
1025
+ --fd-hover-link-rest-y: -50%;
1026
+ --fd-hover-link-open-x: 0;
1027
+ --fd-hover-link-open-y: -50%;
1028
+ }
1029
+
1030
+ .fd-hover-link[data-side="left"][data-align="start"] > .fd-hover-link-popover {
1031
+ top: 0;
1032
+ --fd-hover-link-rest-y: 0;
1033
+ --fd-hover-link-open-y: 0;
1034
+ }
1035
+
1036
+ .fd-hover-link[data-side="left"][data-align="end"] > .fd-hover-link-popover {
1037
+ top: auto;
1038
+ bottom: 0;
1039
+ --fd-hover-link-rest-y: 0;
1040
+ --fd-hover-link-open-y: 0;
1041
+ }
1042
+
1043
+ .fd-hover-link-open > .fd-hover-link-popover {
1044
+ opacity: 1;
1045
+ visibility: visible;
1046
+ pointer-events: auto;
1047
+ transform: translate3d(var(--fd-hover-link-open-x), var(--fd-hover-link-open-y), 0);
1048
+ }
1049
+
1050
+ .fd-hover-link-card {
1051
+ display: flex;
1052
+ flex-direction: column;
1053
+ gap: 0.75rem;
1054
+ width: 100%;
1055
+ border-radius: calc(var(--radius, 0.75rem) + 2px);
1056
+ border: 1px solid color-mix(in srgb, var(--color-fd-border) 88%, transparent);
1057
+ background: var(--color-fd-popover, var(--color-fd-background));
1058
+ color: var(--color-fd-popover-foreground, var(--color-fd-foreground));
1059
+ padding: 0.95rem 1rem;
1060
+ box-shadow: 0 20px 45px color-mix(in srgb, var(--color-fd-background) 78%, transparent);
1061
+ backdrop-filter: blur(14px);
1062
+ }
1063
+
1064
+ .fd-hover-link-body {
1065
+ display: flex;
1066
+ flex-direction: column;
1067
+ gap: 0.35rem;
1068
+ }
1069
+
1070
+ .fd-hover-link-preview-label {
1071
+ font-size: 0.68rem;
1072
+ text-transform: uppercase;
1073
+ letter-spacing: 0.1em;
1074
+ font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace));
1075
+ color: color-mix(in srgb, var(--color-fd-popover-foreground, var(--color-fd-foreground)) 55%, transparent);
1076
+ }
1077
+
1078
+ .fd-hover-link-title,
1079
+ .fd-hover-link-cta {
1080
+ text-decoration: none !important;
1081
+ }
1082
+
1083
+ .fd-hover-link-title {
1084
+ color: var(--color-fd-popover-foreground, var(--color-fd-foreground));
1085
+ font-size: 1rem;
1086
+ font-weight: 600 !important;
1087
+ line-height: 1.3;
1088
+ }
1089
+
1090
+ .fd-hover-link-title:hover,
1091
+ .fd-hover-link-cta:hover {
1092
+ opacity: 1;
1093
+ }
1094
+
1095
+ .fd-hover-link-description {
1096
+ font-size: 0.92rem;
1097
+ line-height: 1.6;
1098
+ color: color-mix(in srgb, var(--color-fd-popover-foreground, var(--color-fd-foreground)) 74%, transparent);
1099
+ }
1100
+
1101
+ .fd-hover-link-footer {
1102
+ display: flex;
1103
+ align-items: center;
1104
+ justify-content: space-between;
1105
+ gap: 0.75rem;
1106
+ padding-top: 0.25rem;
1107
+ border-top: 1px solid color-mix(in srgb, var(--color-fd-border) 72%, transparent);
1108
+ }
1109
+
1110
+ .fd-hover-link-cta {
1111
+ display: inline-flex !important;
1112
+ align-items: center;
1113
+ gap: 0.4rem;
1114
+ color: var(--color-fd-primary);
1115
+ font-size: 0.8rem;
1116
+ font-weight: 600 !important;
1117
+ text-transform: uppercase;
1118
+ letter-spacing: 0.08em;
1119
+ font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace));
1120
+ }
1121
+
922
1122
  .fd-page-body h1 {
923
1123
  font-size: var(--fd-h1-size, 2.25rem);
924
1124
  font-weight: var(--fd-h1-weight, 700);