@farming-labs/svelte-theme 0.0.48 → 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/svelte-theme",
3
- "version": "0.0.48",
3
+ "version": "0.0.51",
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/svelte": "0.0.48",
86
- "@farming-labs/docs": "0.0.48"
85
+ "@farming-labs/docs": "0.0.51",
86
+ "@farming-labs/svelte": "0.0.51"
87
87
  },
88
88
  "peerDependencies": {
89
89
  "svelte": ">=5.0.0"
@@ -40,6 +40,25 @@
40
40
  return { ...page, url: withLang(page.url, activeLocale) };
41
41
  }
42
42
 
43
+ function setHoverLinkOpen(root, open) {
44
+ if (!(root instanceof HTMLElement)) return;
45
+ const trigger = root.querySelector(".fd-hover-link-trigger");
46
+ const popover = root.querySelector(".fd-hover-link-popover");
47
+ if (!(trigger instanceof HTMLElement) || !(popover instanceof HTMLElement)) return;
48
+
49
+ root.classList.toggle("fd-hover-link-open", open);
50
+ trigger.setAttribute("aria-expanded", String(open));
51
+ popover.setAttribute("aria-hidden", String(!open));
52
+ }
53
+
54
+ function closeOpenHoverLinks(event) {
55
+ document.querySelectorAll("[data-hover-link].fd-hover-link-open").forEach((root) => {
56
+ if (!(root instanceof HTMLElement)) return;
57
+ if (event.target instanceof Node && root.contains(event.target)) return;
58
+ setHoverLinkOpen(root, false);
59
+ });
60
+ }
61
+
43
62
  onMount(() => {
44
63
  scanHeadings();
45
64
  wireInteractive();
@@ -115,6 +134,75 @@
115
134
  const localized = withLang(href, locale);
116
135
  if (localized) link.setAttribute("href", localized);
117
136
  });
137
+
138
+ document.querySelectorAll("[data-hover-link]").forEach((root) => {
139
+ if (!(root instanceof HTMLElement)) return;
140
+ if (root.dataset.fdHoverLinkBound === "true") return;
141
+ root.dataset.fdHoverLinkBound = "true";
142
+
143
+ const trigger = root.querySelector(".fd-hover-link-trigger");
144
+ const popover = root.querySelector(".fd-hover-link-popover");
145
+ if (!(trigger instanceof HTMLElement) || !(popover instanceof HTMLElement)) return;
146
+
147
+ let closeTimer = 0;
148
+ const setOpen = (open) => {
149
+ if (closeTimer !== 0) {
150
+ window.clearTimeout(closeTimer);
151
+ closeTimer = 0;
152
+ }
153
+ setHoverLinkOpen(root, open);
154
+ };
155
+
156
+ const containsTarget = (target) => target instanceof Node && root.contains(target);
157
+ const closeSoon = () => {
158
+ if (closeTimer !== 0) window.clearTimeout(closeTimer);
159
+ closeTimer = window.setTimeout(() => setOpen(false), 90);
160
+ };
161
+
162
+ trigger.addEventListener("pointerenter", () => setOpen(true));
163
+ trigger.addEventListener("pointerleave", (event) => {
164
+ if (containsTarget(event.relatedTarget)) return;
165
+ closeSoon();
166
+ });
167
+ trigger.addEventListener("focus", (event) => {
168
+ if (!(event.currentTarget instanceof HTMLElement)) return;
169
+ if (typeof event.currentTarget.matches === "function" && !event.currentTarget.matches(":focus-visible")) {
170
+ return;
171
+ }
172
+ setOpen(true);
173
+ });
174
+ trigger.addEventListener("blur", (event) => {
175
+ if (containsTarget(event.relatedTarget)) return;
176
+ closeSoon();
177
+ });
178
+ trigger.addEventListener("click", (event) => {
179
+ event.preventDefault();
180
+ setOpen(true);
181
+ });
182
+
183
+ popover.addEventListener("pointerenter", () => setOpen(true));
184
+ popover.addEventListener("pointerleave", (event) => {
185
+ if (containsTarget(event.relatedTarget)) return;
186
+ closeSoon();
187
+ });
188
+ popover.addEventListener("focusin", () => setOpen(true));
189
+ popover.addEventListener("focusout", (event) => {
190
+ if (containsTarget(event.relatedTarget)) return;
191
+ closeSoon();
192
+ });
193
+
194
+ root.addEventListener("keydown", (event) => {
195
+ if (event.key !== "Escape") return;
196
+ setOpen(false);
197
+ });
198
+ });
199
+
200
+ if (document.documentElement.dataset.fdHoverLinkGlobalBound !== "true") {
201
+ document.documentElement.dataset.fdHoverLinkGlobalBound = "true";
202
+
203
+ document.addEventListener("pointerdown", closeOpenHoverLinks);
204
+ document.addEventListener("focusin", closeOpenHoverLinks);
205
+ }
118
206
  });
119
207
  }
120
208
  </script>
@@ -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
@@ -914,6 +914,206 @@ samp {
914
914
  opacity: 0.8;
915
915
  }
916
916
 
917
+ .fd-hover-link {
918
+ position: relative;
919
+ display: inline-block;
920
+ vertical-align: baseline;
921
+ max-width: 100%;
922
+ }
923
+
924
+ .fd-hover-link-trigger {
925
+ display: inline !important;
926
+ border: none;
927
+ background: transparent;
928
+ padding: 0;
929
+ margin: 0;
930
+ color: var(--color-fd-foreground);
931
+ cursor: pointer;
932
+ text-decoration: underline;
933
+ text-decoration-style: dashed;
934
+ text-decoration-thickness: 0.08em;
935
+ text-underline-offset: 0.22em;
936
+ text-decoration-color: color-mix(in srgb, var(--color-fd-foreground) 46%, transparent);
937
+ font: inherit;
938
+ line-height: inherit;
939
+ vertical-align: baseline;
940
+ appearance: none;
941
+ transition: text-decoration-color 180ms ease, opacity 180ms ease;
942
+ }
943
+
944
+ .fd-hover-link-trigger:hover,
945
+ .fd-hover-link-trigger:focus-visible,
946
+ .fd-hover-link-open > .fd-hover-link-trigger {
947
+ text-decoration-color: color-mix(in srgb, var(--color-fd-foreground) 68%, transparent);
948
+ }
949
+
950
+ .fd-hover-link-trigger:focus-visible {
951
+ outline: none;
952
+ }
953
+
954
+ .fd-hover-link-popover {
955
+ --fd-hover-link-rest-x: -50%;
956
+ --fd-hover-link-rest-y: 8px;
957
+ --fd-hover-link-open-x: -50%;
958
+ --fd-hover-link-open-y: 0;
959
+ position: absolute;
960
+ top: calc(100% + var(--fd-hover-link-side-offset, 12px));
961
+ left: 50%;
962
+ z-index: 40;
963
+ width: min(22rem, calc(100vw - 2rem));
964
+ max-width: min(22rem, calc(100vw - 2rem));
965
+ opacity: 0;
966
+ visibility: hidden;
967
+ pointer-events: none;
968
+ transform: translate3d(var(--fd-hover-link-rest-x), var(--fd-hover-link-rest-y), 0);
969
+ transition: opacity 180ms ease, transform 180ms ease, visibility 180ms linear;
970
+ }
971
+
972
+ .fd-hover-link[data-align="start"] > .fd-hover-link-popover {
973
+ left: 0;
974
+ --fd-hover-link-rest-x: 0;
975
+ --fd-hover-link-open-x: 0;
976
+ }
977
+
978
+ .fd-hover-link[data-align="end"] > .fd-hover-link-popover {
979
+ left: auto;
980
+ right: 0;
981
+ --fd-hover-link-rest-x: 0;
982
+ --fd-hover-link-open-x: 0;
983
+ }
984
+
985
+ .fd-hover-link[data-side="top"] > .fd-hover-link-popover {
986
+ top: auto;
987
+ bottom: calc(100% + var(--fd-hover-link-side-offset, 12px));
988
+ --fd-hover-link-rest-y: -8px;
989
+ --fd-hover-link-open-y: 0;
990
+ }
991
+
992
+ .fd-hover-link[data-side="right"] > .fd-hover-link-popover {
993
+ top: 50%;
994
+ left: calc(100% + var(--fd-hover-link-side-offset, 12px));
995
+ right: auto;
996
+ --fd-hover-link-rest-x: 8px;
997
+ --fd-hover-link-rest-y: -50%;
998
+ --fd-hover-link-open-x: 0;
999
+ --fd-hover-link-open-y: -50%;
1000
+ }
1001
+
1002
+ .fd-hover-link[data-side="right"][data-align="start"] > .fd-hover-link-popover {
1003
+ top: 0;
1004
+ --fd-hover-link-rest-y: 0;
1005
+ --fd-hover-link-open-y: 0;
1006
+ }
1007
+
1008
+ .fd-hover-link[data-side="right"][data-align="end"] > .fd-hover-link-popover {
1009
+ top: auto;
1010
+ bottom: 0;
1011
+ --fd-hover-link-rest-y: 0;
1012
+ --fd-hover-link-open-y: 0;
1013
+ }
1014
+
1015
+ .fd-hover-link[data-side="left"] > .fd-hover-link-popover {
1016
+ top: 50%;
1017
+ left: auto;
1018
+ right: calc(100% + var(--fd-hover-link-side-offset, 12px));
1019
+ --fd-hover-link-rest-x: -8px;
1020
+ --fd-hover-link-rest-y: -50%;
1021
+ --fd-hover-link-open-x: 0;
1022
+ --fd-hover-link-open-y: -50%;
1023
+ }
1024
+
1025
+ .fd-hover-link[data-side="left"][data-align="start"] > .fd-hover-link-popover {
1026
+ top: 0;
1027
+ --fd-hover-link-rest-y: 0;
1028
+ --fd-hover-link-open-y: 0;
1029
+ }
1030
+
1031
+ .fd-hover-link[data-side="left"][data-align="end"] > .fd-hover-link-popover {
1032
+ top: auto;
1033
+ bottom: 0;
1034
+ --fd-hover-link-rest-y: 0;
1035
+ --fd-hover-link-open-y: 0;
1036
+ }
1037
+
1038
+ .fd-hover-link-open > .fd-hover-link-popover {
1039
+ opacity: 1;
1040
+ visibility: visible;
1041
+ pointer-events: auto;
1042
+ transform: translate3d(var(--fd-hover-link-open-x), var(--fd-hover-link-open-y), 0);
1043
+ }
1044
+
1045
+ .fd-hover-link-card {
1046
+ display: flex;
1047
+ flex-direction: column;
1048
+ gap: 0.75rem;
1049
+ width: 100%;
1050
+ border-radius: calc(var(--radius, 0.75rem) + 2px);
1051
+ border: 1px solid color-mix(in srgb, var(--color-fd-border) 88%, transparent);
1052
+ background: var(--color-fd-popover, var(--color-fd-background));
1053
+ color: var(--color-fd-popover-foreground, var(--color-fd-foreground));
1054
+ padding: 0.95rem 1rem;
1055
+ box-shadow: 0 20px 45px color-mix(in srgb, var(--color-fd-background) 78%, transparent);
1056
+ backdrop-filter: blur(14px);
1057
+ }
1058
+
1059
+ .fd-hover-link-body {
1060
+ display: flex;
1061
+ flex-direction: column;
1062
+ gap: 0.35rem;
1063
+ }
1064
+
1065
+ .fd-hover-link-preview-label {
1066
+ font-size: 0.68rem;
1067
+ text-transform: uppercase;
1068
+ letter-spacing: 0.1em;
1069
+ font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace));
1070
+ color: color-mix(in srgb, var(--color-fd-popover-foreground, var(--color-fd-foreground)) 55%, transparent);
1071
+ }
1072
+
1073
+ .fd-hover-link-title,
1074
+ .fd-hover-link-cta {
1075
+ text-decoration: none !important;
1076
+ }
1077
+
1078
+ .fd-hover-link-title {
1079
+ color: var(--color-fd-popover-foreground, var(--color-fd-foreground));
1080
+ font-size: 1rem;
1081
+ font-weight: 600 !important;
1082
+ line-height: 1.3;
1083
+ }
1084
+
1085
+ .fd-hover-link-title:hover,
1086
+ .fd-hover-link-cta:hover {
1087
+ opacity: 1;
1088
+ }
1089
+
1090
+ .fd-hover-link-description {
1091
+ font-size: 0.92rem;
1092
+ line-height: 1.6;
1093
+ color: color-mix(in srgb, var(--color-fd-popover-foreground, var(--color-fd-foreground)) 74%, transparent);
1094
+ }
1095
+
1096
+ .fd-hover-link-footer {
1097
+ display: flex;
1098
+ align-items: center;
1099
+ justify-content: space-between;
1100
+ gap: 0.75rem;
1101
+ padding-top: 0.25rem;
1102
+ border-top: 1px solid color-mix(in srgb, var(--color-fd-border) 72%, transparent);
1103
+ }
1104
+
1105
+ .fd-hover-link-cta {
1106
+ display: inline-flex !important;
1107
+ align-items: center;
1108
+ gap: 0.4rem;
1109
+ color: var(--color-fd-primary);
1110
+ font-size: 0.8rem;
1111
+ font-weight: 600 !important;
1112
+ text-transform: uppercase;
1113
+ letter-spacing: 0.08em;
1114
+ font-family: var(--fd-font-mono, var(--font-geist-mono, ui-monospace, monospace));
1115
+ }
1116
+
917
1117
  .fd-page-body h1 {
918
1118
  font-size: var(--fd-h1-size, 2.25rem);
919
1119
  font-weight: var(--fd-h1-weight, 700);