@netlify/spark-ui 1.26.0-alpha.4 → 1.26.0-alpha.5

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.
Files changed (20) hide show
  1. package/dist/components/preact/SearchModal/components/SearchModal/SearchModal.d.ts +2 -0
  2. package/dist/components/preact/SearchModal/components/SearchModal/SearchModal.js +53 -50
  3. package/dist/components/preact/SearchModal/components/SearchWindow.d.ts +1 -1
  4. package/dist/components/preact/SearchModal/components/SearchWindow.js +34 -29
  5. package/dist/components/preact/SearchModal/hooks/useSearchHotkeys.d.ts +1 -1
  6. package/dist/components/preact/SearchModal/hooks/useSearchHotkeys.js +9 -8
  7. package/dist/components/preact/SearchModal/hooks/useSearchParams.d.ts +1 -1
  8. package/dist/components/preact/SearchModal/hooks/useSearchParams.js +12 -12
  9. package/dist/components/preact/SearchModal/hooks/useSearchToggles.d.ts +1 -1
  10. package/dist/components/preact/SearchModal/hooks/useSearchToggles.js +13 -11
  11. package/dist/components/preact/SearchModal/types/search.types.d.ts +2 -0
  12. package/package.json +1 -1
  13. package/packages/components/ActionArrow.astro +1 -1
  14. package/packages/components/Card.astro +41 -5
  15. package/packages/components/preact/SearchModal/components/SearchModal/SearchModal.tsx +9 -4
  16. package/packages/components/preact/SearchModal/components/SearchWindow.tsx +13 -4
  17. package/packages/components/preact/SearchModal/hooks/useSearchHotkeys.ts +9 -2
  18. package/packages/components/preact/SearchModal/hooks/useSearchParams.ts +4 -3
  19. package/packages/components/preact/SearchModal/hooks/useSearchToggles.ts +6 -3
  20. package/packages/components/preact/SearchModal/types/search.types.tsx +2 -0
@@ -6,6 +6,8 @@ interface Props {
6
6
  debug?: boolean;
7
7
  kapaIntegrationId?: string;
8
8
  filters?: PagefindFilters;
9
+ scopedSearch?: boolean;
10
+ searchToggleTarget?: string;
9
11
  }
10
12
  declare function SearchModal(props?: Props): import("preact").JSX.Element;
11
13
  export default SearchModal;
@@ -1,96 +1,99 @@
1
1
  import { u as e } from "../../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import { A as g, y as f, d } from "../../../../../chunks/hooks.module.DRcxknIz.js";
3
- import { A as L, K as P } from "../../../../../chunks/AskNetlify.bx0blyGV.js";
4
- import M from "../../../Modal/Modal.js";
5
- import h from "../../../KeyboardKey/KeyboardKey.js";
6
- import O from "../SearchWindow.js";
7
- import Q from "../SearchInput.js";
8
- import C from "../AskNetlifyLink.js";
9
- import { useSearch as E } from "../../hooks/useSearch.js";
10
- import { useSearchAnalytics as R } from "../../hooks/useSearchAnalytics.js";
11
- import { useKeyboardNav as q } from "../../hooks/useKeyboardNav.js";
12
- import { useSearchHotkeys as x } from "../../hooks/useSearchHotkeys.js";
13
- import { useSearchParams as D } from "../../hooks/useSearchParams.js";
14
- import { useSearchToggles as F } from "../../hooks/useSearchToggles.js";
15
- import { useAskAnalytics as G } from "../../../AskNetlify/hooks/useAskAnalytics.js";
16
- import { Fragment as N } from "preact";
17
- import '../../../../../assets/SearchModal.css';function H(a) {
18
- const s = g(null);
19
- return f(() => {
20
- function n(m) {
2
+ import { A as N, y as p, d as h } from "../../../../../chunks/hooks.module.DRcxknIz.js";
3
+ import { A as M, K as O } from "../../../../../chunks/AskNetlify.bx0blyGV.js";
4
+ import Q from "../../../Modal/Modal.js";
5
+ import f from "../../../KeyboardKey/KeyboardKey.js";
6
+ import C from "../SearchWindow.js";
7
+ import E from "../SearchInput.js";
8
+ import R from "../AskNetlifyLink.js";
9
+ import { useSearch as q } from "../../hooks/useSearch.js";
10
+ import { useSearchAnalytics as x } from "../../hooks/useSearchAnalytics.js";
11
+ import { useKeyboardNav as D } from "../../hooks/useKeyboardNav.js";
12
+ import { useSearchHotkeys as F } from "../../hooks/useSearchHotkeys.js";
13
+ import { useSearchParams as G } from "../../hooks/useSearchParams.js";
14
+ import { useSearchToggles as H } from "../../hooks/useSearchToggles.js";
15
+ import { useAskAnalytics as U } from "../../../AskNetlify/hooks/useAskAnalytics.js";
16
+ import { Fragment as k } from "preact";
17
+ import '../../../../../assets/SearchModal.css';function V(a) {
18
+ const s = N(null);
19
+ return p(() => {
20
+ function o(m) {
21
21
  s.current && !s.current.contains(m.target) && a();
22
22
  }
23
- return document.addEventListener("mousedown", n), () => {
24
- document.removeEventListener("mousedown", n);
23
+ return document.addEventListener("mousedown", o), () => {
24
+ document.removeEventListener("mousedown", o);
25
25
  };
26
26
  }, [a]), s;
27
27
  }
28
- function se(a = {
28
+ function ne(a = {
29
29
  className: "",
30
30
  children: void 0,
31
31
  debug: !1,
32
32
  kapaIntegrationId: void 0,
33
- filters: void 0
33
+ filters: void 0,
34
+ scopedSearch: !1,
35
+ searchToggleTarget: void 0
34
36
  }) {
35
- const { children: s, className: n, debug: m, filters: T, ...v } = a, [c, o] = d({ current: "search" }), [i, p] = d(!1), [A, I] = d(""), l = () => p(!0), u = () => p(!1), t = g(null), w = H(u), { state: r, actions: S } = E(T);
36
- F(l, o), D(l, S.setSearchTerm, I, o), x(i, l, u), q(t, i, u), R(r, m);
37
- const { handleNewQuery: b, handleAnswer: K } = G();
38
- return f(() => {
37
+ const { children: s, className: o, debug: m, filters: v, scopedSearch: A, searchToggleTarget: l, ...I } = a, [c, n] = h({ current: "search" }), [i, S] = h(!1), [w, b] = h(""), d = () => S(!0), u = () => S(!1), t = N(null), K = V(u), { state: r, actions: g } = q(v);
38
+ H(d, n, l), G(d, g.setSearchTerm, b, n, !l), F(i, d, u, !l), D(t, i, u), x(r, m);
39
+ const { handleNewQuery: L, handleAnswer: P } = U();
40
+ return p(() => {
39
41
  t.current && (i ? t.current.showModal() : t.current.close());
40
- }, [i]), f(() => {
41
- var k;
42
- const y = (k = t.current) == null ? void 0 : k.querySelector("input");
42
+ }, [i]), p(() => {
43
+ var T;
44
+ const y = (T = t.current) == null ? void 0 : T.querySelector("input");
43
45
  y && y.focus();
44
46
  }, [c.current]), /* @__PURE__ */ e(
45
- P,
47
+ O,
46
48
  {
47
49
  integrationId: a.kapaIntegrationId || "",
48
50
  callbacks: {
49
51
  askAI: {
50
- onQuerySubmit: b,
51
- onAnswerGenerationCompleted: K
52
+ onQuerySubmit: L,
53
+ onAnswerGenerationCompleted: P
52
54
  }
53
55
  },
54
56
  children: /* @__PURE__ */ e(
55
- M,
57
+ Q,
56
58
  {
57
59
  ref: t,
58
- className: `n-search-modal ${n || ""}`,
60
+ className: `n-search-modal ${o || ""}`,
59
61
  "data-state": c.current,
60
- ...v,
61
- children: /* @__PURE__ */ e("div", { ref: w, className: "n-search-container", children: [
62
+ ...I,
63
+ children: /* @__PURE__ */ e("div", { ref: K, className: "n-search-container", children: [
62
64
  c.current === "ask" && /* @__PURE__ */ e(
63
- L,
65
+ M,
64
66
  {
65
- setModalState: o,
67
+ setModalState: n,
66
68
  searchQuery: r.searchTerm,
67
- urlParamQuery: A
69
+ urlParamQuery: w
68
70
  }
69
71
  ),
70
- c.current === "search" && /* @__PURE__ */ e(N, { children: [
71
- /* @__PURE__ */ e(Q, { setSearchTerm: S.setSearchTerm, initialValue: r.searchTerm }),
72
+ c.current === "search" && /* @__PURE__ */ e(k, { children: [
73
+ /* @__PURE__ */ e(E, { setSearchTerm: g.setSearchTerm, initialValue: r.searchTerm }),
72
74
  /* @__PURE__ */ e(
73
- O,
75
+ C,
74
76
  {
75
- setModalState: o,
77
+ setModalState: n,
76
78
  searchLoading: r.isLoading,
77
79
  searchTerm: r.searchTerm,
78
80
  results: r.results,
79
- children: /* @__PURE__ */ e(N, { children: [
80
- a.kapaIntegrationId && /* @__PURE__ */ e(C, { searchTerm: r.searchTerm, setModalState: o }),
81
+ scopedSearch: A,
82
+ children: /* @__PURE__ */ e(k, { children: [
83
+ a.kapaIntegrationId && /* @__PURE__ */ e(R, { searchTerm: r.searchTerm, setModalState: n }),
81
84
  s
82
85
  ] })
83
86
  }
84
87
  ),
85
88
  /* @__PURE__ */ e("div", { className: "n-search-footer", children: [
86
89
  /* @__PURE__ */ e("p", { className: "n-search-footer-tip", children: [
87
- /* @__PURE__ */ e(h, { keyNames: ["Esc"] }),
90
+ /* @__PURE__ */ e(f, { keyNames: ["Esc"] }),
88
91
  "to close"
89
92
  ] }),
90
93
  /* @__PURE__ */ e("p", { className: "n-search-footer-tip", children: [
91
- /* @__PURE__ */ e(h, { keyNames: ["Tab"] }),
94
+ /* @__PURE__ */ e(f, { keyNames: ["Tab"] }),
92
95
  /* @__PURE__ */ e("span", { children: "or" }),
93
- /* @__PURE__ */ e(h, { keyNames: ["↑", "↓"] }),
96
+ /* @__PURE__ */ e(f, { keyNames: ["↑", "↓"] }),
94
97
  "to navigate"
95
98
  ] })
96
99
  ] })
@@ -102,5 +105,5 @@ function se(a = {
102
105
  );
103
106
  }
104
107
  export {
105
- se as default
108
+ ne as default
106
109
  };
@@ -1,2 +1,2 @@
1
1
  import { SearchWindowProps } from '../types/search.types';
2
- export default function SearchWindow({ setModalState, searchLoading, searchTerm, results, children: DefaultWindow, }: SearchWindowProps): import("preact").JSX.Element;
2
+ export default function SearchWindow({ setModalState, searchLoading, searchTerm, results, children: DefaultWindow, scopedSearch, }: SearchWindowProps): import("preact").JSX.Element;
@@ -1,49 +1,54 @@
1
1
  import { u as n } from "../../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import t from "./SearchHeading/SearchHeading.js";
2
+ import m from "./SearchHeading/SearchHeading.js";
3
3
  import h from "./SearchLink/SearchLink.js";
4
- import m from "./SearchLinkThemeToggle.js";
5
- import o from "./AskNetlifyLink.js";
6
- import { Fragment as a } from "preact";
7
- const f = ({ searchTerm: l }) => /* @__PURE__ */ n("div", { className: "n-search-feedback", children: /* @__PURE__ */ n("p", { className: "n-results-info", children: [
4
+ import f from "./SearchLinkThemeToggle.js";
5
+ import t from "./AskNetlifyLink.js";
6
+ import { Fragment as s } from "preact";
7
+ const N = ({ searchTerm: e }) => /* @__PURE__ */ n("div", { className: "n-search-feedback", children: /* @__PURE__ */ n("p", { className: "n-results-info", children: [
8
8
  "0 results for ",
9
- /* @__PURE__ */ n("span", { className: "n-search-term", children: l })
9
+ /* @__PURE__ */ n("span", { className: "n-search-term", children: e })
10
10
  ] }) }), p = ({
11
- setModalState: l,
12
- searchLoading: c,
11
+ setModalState: e,
12
+ searchLoading: r,
13
13
  searchTerm: i,
14
- results: e
14
+ results: l,
15
+ scopedSearch: a
15
16
  }) => {
16
- const s = !c && (!e || e.length === 0);
17
- return /* @__PURE__ */ n(a, { children: [
18
- /* @__PURE__ */ n(o, { searchTerm: i, setModalState: l }),
19
- s ? /* @__PURE__ */ n(f, { searchTerm: i }) : /* @__PURE__ */ n("ul", { className: "n-results-list", role: "list", children: e == null ? void 0 : e.map((r, d) => /* @__PURE__ */ n("li", { className: "n-results-list-item", children: /* @__PURE__ */ n(h, { ...r }) }, d)) })
17
+ const c = !r && (!l || l.length === 0);
18
+ return /* @__PURE__ */ n(s, { children: [
19
+ !a && /* @__PURE__ */ n(t, { searchTerm: i, setModalState: e }),
20
+ c ? /* @__PURE__ */ n(N, { searchTerm: i }) : /* @__PURE__ */ n("ul", { className: "n-results-list", role: "list", children: l == null ? void 0 : l.map((o, d) => /* @__PURE__ */ n("li", { className: "n-results-list-item", children: /* @__PURE__ */ n(h, { ...o }) }, d)) })
20
21
  ] });
21
22
  };
22
- function w({
23
- setModalState: l,
24
- searchLoading: c,
23
+ function b({
24
+ setModalState: e,
25
+ searchLoading: r,
25
26
  searchTerm: i,
26
- results: e,
27
- children: s
27
+ results: l,
28
+ children: a,
29
+ scopedSearch: c
28
30
  }) {
29
- const r = (i == null ? void 0 : i.length) > 1;
30
- return /* @__PURE__ */ n("div", { className: "n-search-window", children: /* @__PURE__ */ n("div", { className: "n-search-links", children: r ? c ? /* @__PURE__ */ n(a, { children: [
31
- /* @__PURE__ */ n(o, { searchTerm: i, setModalState: l }),
31
+ const o = (i == null ? void 0 : i.length) > 1;
32
+ return /* @__PURE__ */ n("div", { className: "n-search-window", children: /* @__PURE__ */ n("div", { className: "n-search-links", children: o ? r ? /* @__PURE__ */ n(s, { children: [
33
+ !c && /* @__PURE__ */ n(t, { searchTerm: i, setModalState: e }),
32
34
  /* @__PURE__ */ n("div", { className: "n-search-feedback", children: /* @__PURE__ */ n("div", { className: "n-loader-dots-spinner" }) })
33
35
  ] }) : /* @__PURE__ */ n(
34
36
  p,
35
37
  {
36
- setModalState: l,
37
- searchLoading: c,
38
+ setModalState: e,
39
+ searchLoading: r,
38
40
  searchTerm: i,
39
- results: e
41
+ results: l,
42
+ scopedSearch: c
40
43
  }
41
- ) : /* @__PURE__ */ n(a, { children: [
42
- s,
43
- /* @__PURE__ */ n(t, { children: "Actions" }),
44
- /* @__PURE__ */ n(m, {})
44
+ ) : /* @__PURE__ */ n(s, { children: [
45
+ a,
46
+ !c && /* @__PURE__ */ n(s, { children: [
47
+ /* @__PURE__ */ n(m, { children: "Actions" }),
48
+ /* @__PURE__ */ n(f, {})
49
+ ] })
45
50
  ] }) }) });
46
51
  }
47
52
  export {
48
- w as default
53
+ b as default
49
54
  };
@@ -10,4 +10,4 @@
10
10
  * @param onOpen - Callback to open the search interface.
11
11
  * @param onClose - Callback to close the search interface.
12
12
  */
13
- export declare function useSearchHotkeys(isOpen: boolean, onOpen: () => void, onClose: () => void): void;
13
+ export declare function useSearchHotkeys(isOpen: boolean, onOpen: () => void, onClose: () => void, enabled?: boolean): void;
@@ -1,12 +1,13 @@
1
- import { y as d } from "../../../../chunks/hooks.module.DRcxknIz.js";
2
- function m(t, n, o) {
3
- d(() => {
4
- const r = (e) => {
5
- e.metaKey && e.key === "k" && (e.preventDefault(), e.stopImmediatePropagation(), t ? o() : n());
1
+ import { y as m } from "../../../../chunks/hooks.module.DRcxknIz.js";
2
+ function a(t, r, n, o = !0) {
3
+ m(() => {
4
+ if (!o) return;
5
+ const d = (e) => {
6
+ e.metaKey && e.key === "k" && (e.preventDefault(), e.stopImmediatePropagation(), t ? n() : r());
6
7
  };
7
- return document.addEventListener("keydown", r), () => document.removeEventListener("keydown", r);
8
- }, [t, n, o]);
8
+ return document.addEventListener("keydown", d), () => document.removeEventListener("keydown", d);
9
+ }, [t, r, n, o]);
9
10
  }
10
11
  export {
11
- m as useSearchHotkeys
12
+ a as useSearchHotkeys
12
13
  };
@@ -17,4 +17,4 @@
17
17
  */
18
18
  export declare function useSearchParams(onOpen: () => void, setSearchTerm: (term: string) => void, setUrlParamTerm: (term: string) => void, setModalState?: (e: {
19
19
  current: string;
20
- }) => void): void;
20
+ }) => void, enabled?: boolean): void;
@@ -1,24 +1,24 @@
1
- import { d as u, y as g } from "../../../../chunks/hooks.module.DRcxknIz.js";
2
- function m(a, c, i, r) {
3
- const [o, h] = u(!1);
4
- g(() => {
1
+ import { d as m, y as h } from "../../../../chunks/hooks.module.DRcxknIz.js";
2
+ function w(a, c, i, r, o = !0) {
3
+ const [t, u] = m(!1);
4
+ h(() => {
5
5
  let e;
6
6
  const s = () => {
7
- window.pagefind && (h(!0), e && clearInterval(e));
7
+ window.pagefind && (u(!0), e && clearInterval(e));
8
8
  };
9
9
  return s(), e = setInterval(s, 100), () => clearInterval(e);
10
- }, []), g(() => {
11
- if (typeof location > "u" || o) return;
12
- const e = new URLSearchParams(location.search), s = e.has("ask"), n = e.get("msg") || e.get("message"), f = e.get("search"), t = new URL(location.href);
10
+ }, []), h(() => {
11
+ if (!o || typeof location > "u" || t) return;
12
+ const e = new URLSearchParams(location.search), s = e.has("ask"), n = e.get("msg") || e.get("message"), f = e.get("search"), g = new URL(location.href);
13
13
  if (["ask", "msg", "message", "search"].forEach((d) => {
14
- t.searchParams.delete(d);
15
- }), window.history.replaceState({}, "", t), s || n) {
14
+ g.searchParams.delete(d);
15
+ }), window.history.replaceState({}, "", g), s || n) {
16
16
  n && i(n), r == null || r({ current: "ask" }), a();
17
17
  return;
18
18
  }
19
19
  f && (c(f), a());
20
- }, [o, a, r, c, i]);
20
+ }, [t, a, r, c, i, o]);
21
21
  }
22
22
  export {
23
- m as useSearchParams
23
+ w as useSearchParams
24
24
  };
@@ -11,4 +11,4 @@
11
11
  */
12
12
  export declare function useSearchToggles(onOpen: () => void, setState: (state: {
13
13
  current: string;
14
- }) => void): void;
14
+ }) => void, scopeId?: string): void;
@@ -1,18 +1,20 @@
1
- import { y as l } from "../../../../chunks/hooks.module.DRcxknIz.js";
2
- function n(t, c) {
3
- l(() => {
4
- const r = document.querySelectorAll("[data-ntl-search-toggle]");
5
- if (r.length)
6
- return r.forEach((e) => {
7
- const a = e.dataset.ntlSearchToggle ? e.dataset.ntlSearchToggle : "search";
1
+ import { y as n } from "../../../../chunks/hooks.module.DRcxknIz.js";
2
+ function g(t, l, r) {
3
+ n(() => {
4
+ const a = Array.from(document.querySelectorAll("[data-ntl-search-toggle]")).filter(
5
+ (e) => r ? e.dataset.ntlSearchTarget === r : !e.dataset.ntlSearchTarget
6
+ );
7
+ if (a.length)
8
+ return a.forEach((e) => {
9
+ const c = e.dataset.ntlSearchToggle ? e.dataset.ntlSearchToggle : "search";
8
10
  e.removeAttribute("disabled"), e.addEventListener("click", () => {
9
- t(), c({ current: a });
11
+ t(), l({ current: c });
10
12
  });
11
13
  }), () => {
12
- r.forEach((e) => e.removeEventListener("click", t));
14
+ a.forEach((e) => e.removeEventListener("click", t));
13
15
  };
14
- }, [t]);
16
+ }, [t, r]);
15
17
  }
16
18
  export {
17
- n as useSearchToggles
19
+ g as useSearchToggles
18
20
  };
@@ -18,6 +18,7 @@ export interface SearchWindowProps {
18
18
  searchTerm: string;
19
19
  results?: SearchLinkProps[];
20
20
  children: ComponentChildren;
21
+ scopedSearch?: boolean;
21
22
  }
22
23
  export interface SearchResultsProps {
23
24
  setModalState: (e: {
@@ -26,6 +27,7 @@ export interface SearchResultsProps {
26
27
  searchLoading: boolean;
27
28
  searchTerm: string;
28
29
  results?: SearchLinkProps[];
30
+ scopedSearch?: boolean;
29
31
  }
30
32
  export interface SearchState {
31
33
  searchTerm: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@netlify/spark-ui",
3
3
  "description": "Assets, design tokens, components, and utilities",
4
- "version": "1.26.0-alpha.4",
4
+ "version": "1.26.0-alpha.5",
5
5
  "type": "module",
6
6
  "main": "dist/components/preact/index.js",
7
7
  "types": "dist/components/preact/index.d.ts",
@@ -3,7 +3,7 @@ const { class: className, ...rest } = Astro.props;
3
3
  ---
4
4
 
5
5
  <div class:list={['n-action-arrow', className]} {...rest}>
6
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14">
6
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="none" viewBox="0 0 14 14" role="presentation">
7
7
  <g stroke="currentColor" stroke-linecap="square" stroke-width="1.564">
8
8
  <path stroke-linejoin="round" d="M3.417 10.556 9.4 4.572"></path>
9
9
  <path d="M9.88 9.381V4.093H4.59"></path>
@@ -6,8 +6,11 @@ import Eyebrow from './Eyebrow.astro';
6
6
  interface Props {
7
7
  as?: HTMLElement;
8
8
  eyebrow?: string;
9
+ eyebrowTransitionName?: string;
9
10
  paragraph?: string | HTMLElement;
11
+ paragraphTransitionName?: string;
10
12
  headline?: string | HTMLElement;
13
+ headlineTransitionName?: string;
11
14
  link?: {
12
15
  id?: string;
13
16
  href: string;
@@ -19,8 +22,11 @@ interface Props {
19
22
  const {
20
23
  as: Element = 'div',
21
24
  eyebrow,
25
+ eyebrowTransitionName,
22
26
  paragraph,
27
+ paragraphTransitionName,
23
28
  headline,
29
+ headlineTransitionName,
24
30
  link,
25
31
  isCardClickable,
26
32
  class: className,
@@ -55,17 +61,32 @@ const isExternal =
55
61
  </div>
56
62
  )
57
63
  }
58
- {eyebrow && <Eyebrow class="n-card-eyebrow">{eyebrow}</Eyebrow>}
64
+ {
65
+ eyebrow && (
66
+ <Eyebrow class="n-card-eyebrow" transition:name={eyebrowTransitionName}>
67
+ {eyebrow}
68
+ </Eyebrow>
69
+ )
70
+ }
59
71
  {
60
72
  isAnchorHeadline ? (
61
73
  <a class="n-card-link n-card-link-headline" href={link?.href} id={link.id}>
62
- <div class="n-card-headline" set:html={headline} />
74
+ <div class="n-card-headline" set:html={headline} transition:name={headlineTransitionName} />
63
75
  </a>
64
76
  ) : (
65
- <div class="n-card-headline" set:html={headline} />
77
+ <div class="n-card-headline" set:html={headline} transition:name={headlineTransitionName} />
78
+ )
79
+ }
80
+ {
81
+ Astro.slots.has('meta') && (
82
+ <div class="n-card-meta">
83
+ <slot name="meta" />
84
+ </div>
66
85
  )
67
86
  }
68
- {paragraph && <div class="n-card-paragraph" set:html={paragraph} />}
87
+ {paragraph && (
88
+ <div class="n-card-paragraph" set:html={paragraph} transition:name={paragraphTransitionName} />
89
+ )}
69
90
  <slot />
70
91
  {
71
92
  link && link.text && (
@@ -95,10 +116,24 @@ const isExternal =
95
116
  --ntl-flow-space: var(--ntl-space-l);
96
117
  }
97
118
 
98
- .n-card-eyebrow + .n-card-headline {
119
+ .n-card-eyebrow + .n-card-headline,
120
+ .n-card-eyebrow + .n-card-link-headline {
99
121
  --ntl-flow-space: var(--ntl-space-s);
100
122
  }
101
123
 
124
+ .n-card-headline + .n-card-meta,
125
+ .n-card-link-headline + .n-card-meta {
126
+ --ntl-flow-space: var(--ntl-space-2xs);
127
+ }
128
+
129
+ .n-card-meta {
130
+ color: var(--ntl-color-text-weak);
131
+ }
132
+
133
+ .n-card-meta + .n-card-paragraph {
134
+ --ntl-flow-space: var(--ntl-space-xs);
135
+ }
136
+
102
137
  .n-card-link:has(> .n-card-headline) {
103
138
  text-decoration: none;
104
139
  }
@@ -171,6 +206,7 @@ const isExternal =
171
206
  .n-card-clickable .n-action-arrow {
172
207
  margin-block-start: auto;
173
208
  margin-inline-start: auto;
209
+ padding-block-start: var(--ntl-space-s);
174
210
  }
175
211
 
176
212
  /* Focus for Anchor Headline */
@@ -30,6 +30,8 @@ interface Props {
30
30
  debug?: boolean;
31
31
  kapaIntegrationId?: string;
32
32
  filters?: PagefindFilters;
33
+ scopedSearch?: boolean;
34
+ searchToggleTarget?: string;
33
35
  }
34
36
 
35
37
  function SearchModal(
@@ -39,9 +41,11 @@ function SearchModal(
39
41
  debug: false,
40
42
  kapaIntegrationId: undefined,
41
43
  filters: undefined,
44
+ scopedSearch: false,
45
+ searchToggleTarget: undefined,
42
46
  }
43
47
  ) {
44
- const { children, className, debug, filters, ...rest } = props;
48
+ const { children, className, debug, filters, scopedSearch, searchToggleTarget, ...rest } = props;
45
49
 
46
50
  const [modalState, setModalState] = useState({ current: 'search' });
47
51
  const [searchOpen, setSearchOpen] = useState(false);
@@ -53,9 +57,9 @@ function SearchModal(
53
57
  const containerRef = useClickOutside<HTMLDivElement>(closeSearch);
54
58
 
55
59
  const { state, actions } = useSearch(filters);
56
- useSearchToggles(openSearch, setModalState);
57
- useSearchParams(openSearch, actions.setSearchTerm, setUrlParamTerm, setModalState);
58
- useSearchHotkeys(searchOpen, openSearch, closeSearch);
60
+ useSearchToggles(openSearch, setModalState, searchToggleTarget);
61
+ useSearchParams(openSearch, actions.setSearchTerm, setUrlParamTerm, setModalState, !searchToggleTarget);
62
+ useSearchHotkeys(searchOpen, openSearch, closeSearch, !searchToggleTarget);
59
63
  useKeyboardNav(modalRef, searchOpen, closeSearch);
60
64
  useSearchAnalytics(state, debug);
61
65
  const { handleNewQuery, handleAnswer } = useAskAnalytics();
@@ -103,6 +107,7 @@ function SearchModal(
103
107
  searchLoading={state.isLoading}
104
108
  searchTerm={state.searchTerm}
105
109
  results={state.results}
110
+ scopedSearch={scopedSearch}
106
111
  >
107
112
  <>
108
113
  {props.kapaIntegrationId && (
@@ -18,12 +18,13 @@ const SearchResults: FunctionComponent<SearchResultsProps> = ({
18
18
  searchLoading,
19
19
  searchTerm,
20
20
  results,
21
+ scopedSearch,
21
22
  }) => {
22
23
  const noResults = !searchLoading && (!results || results.length === 0);
23
24
 
24
25
  return (
25
26
  <>
26
- <AskNetlifyLink searchTerm={searchTerm} setModalState={setModalState} />
27
+ {!scopedSearch && <AskNetlifyLink searchTerm={searchTerm} setModalState={setModalState} />}
27
28
  {noResults ? (
28
29
  <NoResults searchTerm={searchTerm} />
29
30
  ) : (
@@ -45,6 +46,7 @@ export default function SearchWindow({
45
46
  searchTerm,
46
47
  results,
47
48
  children: DefaultWindow,
49
+ scopedSearch,
48
50
  }: SearchWindowProps) {
49
51
  const hasQuery = searchTerm?.length > 1;
50
52
 
@@ -54,7 +56,9 @@ export default function SearchWindow({
54
56
  {hasQuery ? (
55
57
  searchLoading ? (
56
58
  <>
57
- <AskNetlifyLink searchTerm={searchTerm} setModalState={setModalState} />
59
+ {!scopedSearch && (
60
+ <AskNetlifyLink searchTerm={searchTerm} setModalState={setModalState} />
61
+ )}
58
62
  <div className="n-search-feedback">
59
63
  <div className="n-loader-dots-spinner" />
60
64
  </div>
@@ -65,13 +69,18 @@ export default function SearchWindow({
65
69
  searchLoading={searchLoading}
66
70
  searchTerm={searchTerm}
67
71
  results={results}
72
+ scopedSearch={scopedSearch}
68
73
  />
69
74
  )
70
75
  ) : (
71
76
  <>
72
77
  {DefaultWindow}
73
- <SearchHeading>Actions</SearchHeading>
74
- <SearchLinkThemeToggle />
78
+ {!scopedSearch && (
79
+ <>
80
+ <SearchHeading>Actions</SearchHeading>
81
+ <SearchLinkThemeToggle />
82
+ </>
83
+ )}
75
84
  </>
76
85
  )}
77
86
  </div>
@@ -13,8 +13,15 @@ import { useEffect } from 'preact/hooks';
13
13
  * @param onClose - Callback to close the search interface.
14
14
  */
15
15
 
16
- export function useSearchHotkeys(isOpen: boolean, onOpen: () => void, onClose: () => void) {
16
+ export function useSearchHotkeys(
17
+ isOpen: boolean,
18
+ onOpen: () => void,
19
+ onClose: () => void,
20
+ enabled: boolean = true
21
+ ) {
17
22
  useEffect(() => {
23
+ if (!enabled) return;
24
+
18
25
  const handleKeydown = (e: KeyboardEvent) => {
19
26
  if (e.metaKey && e.key === 'k') {
20
27
  e.preventDefault();
@@ -25,5 +32,5 @@ export function useSearchHotkeys(isOpen: boolean, onOpen: () => void, onClose: (
25
32
 
26
33
  document.addEventListener('keydown', handleKeydown);
27
34
  return () => document.removeEventListener('keydown', handleKeydown);
28
- }, [isOpen, onOpen, onClose]);
35
+ }, [isOpen, onOpen, onClose, enabled]);
29
36
  }
@@ -22,7 +22,8 @@ export function useSearchParams(
22
22
  onOpen: () => void,
23
23
  setSearchTerm: (term: string) => void,
24
24
  setUrlParamTerm: (term: string) => void,
25
- setModalState?: (e: { current: string }) => void
25
+ setModalState?: (e: { current: string }) => void,
26
+ enabled: boolean = true
26
27
  ) {
27
28
  const [isPagefindLoaded, setIsPagefindLoaded] = useState(false);
28
29
 
@@ -46,7 +47,7 @@ export function useSearchParams(
46
47
  }, []);
47
48
 
48
49
  useEffect(() => {
49
- if (typeof location === 'undefined' || isPagefindLoaded) return;
50
+ if (!enabled || typeof location === 'undefined' || isPagefindLoaded) return;
50
51
 
51
52
  const params = new URLSearchParams(location.search);
52
53
 
@@ -72,5 +73,5 @@ export function useSearchParams(
72
73
  setSearchTerm(search);
73
74
  onOpen();
74
75
  }
75
- }, [isPagefindLoaded, onOpen, setModalState, setSearchTerm, setUrlParamTerm]);
76
+ }, [isPagefindLoaded, onOpen, setModalState, setSearchTerm, setUrlParamTerm, enabled]);
76
77
  }
@@ -14,10 +14,13 @@ import { useEffect } from 'preact/hooks';
14
14
 
15
15
  export function useSearchToggles(
16
16
  onOpen: () => void,
17
- setState: (state: { current: string }) => void
17
+ setState: (state: { current: string }) => void,
18
+ scopeId?: string
18
19
  ) {
19
20
  useEffect(() => {
20
- const toggles = document.querySelectorAll('[data-ntl-search-toggle]');
21
+ const toggles = Array.from(document.querySelectorAll<HTMLElement>('[data-ntl-search-toggle]')).filter(
22
+ t => (scopeId ? t.dataset.ntlSearchTarget === scopeId : !t.dataset.ntlSearchTarget)
23
+ );
21
24
 
22
25
  if (!toggles.length) return;
23
26
 
@@ -33,5 +36,5 @@ export function useSearchToggles(
33
36
  return () => {
34
37
  toggles.forEach(t => t.removeEventListener('click', onOpen));
35
38
  };
36
- }, [onOpen]);
39
+ }, [onOpen, scopeId]);
37
40
  }
@@ -18,6 +18,7 @@ export interface SearchWindowProps {
18
18
  searchTerm: string;
19
19
  results?: SearchLinkProps[];
20
20
  children: ComponentChildren;
21
+ scopedSearch?: boolean;
21
22
  }
22
23
 
23
24
  export interface SearchResultsProps {
@@ -25,6 +26,7 @@ export interface SearchResultsProps {
25
26
  searchLoading: boolean;
26
27
  searchTerm: string;
27
28
  results?: SearchLinkProps[];
29
+ scopedSearch?: boolean;
28
30
  }
29
31
 
30
32
  export interface SearchState {