@netlify/spark-ui 1.26.0-alpha.3 → 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 (28) hide show
  1. package/dist/assets/DropZone.css +1 -1
  2. package/dist/components/index.d.ts +1 -1
  3. package/dist/components/preact/DropZone/DropZone.js +58 -96
  4. package/dist/components/preact/DropZone/drop-core/readFiles.js +4 -1
  5. package/dist/components/preact/SearchModal/components/SearchModal/SearchModal.d.ts +2 -0
  6. package/dist/components/preact/SearchModal/components/SearchModal/SearchModal.js +53 -50
  7. package/dist/components/preact/SearchModal/components/SearchWindow.d.ts +1 -1
  8. package/dist/components/preact/SearchModal/components/SearchWindow.js +34 -29
  9. package/dist/components/preact/SearchModal/hooks/useSearchHotkeys.d.ts +1 -1
  10. package/dist/components/preact/SearchModal/hooks/useSearchHotkeys.js +9 -8
  11. package/dist/components/preact/SearchModal/hooks/useSearchParams.d.ts +1 -1
  12. package/dist/components/preact/SearchModal/hooks/useSearchParams.js +12 -12
  13. package/dist/components/preact/SearchModal/hooks/useSearchToggles.d.ts +1 -1
  14. package/dist/components/preact/SearchModal/hooks/useSearchToggles.js +13 -11
  15. package/dist/components/preact/SearchModal/types/search.types.d.ts +2 -0
  16. package/package.json +1 -1
  17. package/packages/components/ActionArrow.astro +1 -1
  18. package/packages/components/Card.astro +41 -5
  19. package/packages/components/index.ts +1 -1
  20. package/packages/components/preact/DropZone/DropZone.css +1 -80
  21. package/packages/components/preact/DropZone/DropZone.tsx +16 -53
  22. package/packages/components/preact/DropZone/drop-core/readFiles.ts +6 -1
  23. package/packages/components/preact/SearchModal/components/SearchModal/SearchModal.tsx +9 -4
  24. package/packages/components/preact/SearchModal/components/SearchWindow.tsx +13 -4
  25. package/packages/components/preact/SearchModal/hooks/useSearchHotkeys.ts +9 -2
  26. package/packages/components/preact/SearchModal/hooks/useSearchParams.ts +4 -3
  27. package/packages/components/preact/SearchModal/hooks/useSearchToggles.ts +6 -3
  28. package/packages/components/preact/SearchModal/types/search.types.tsx +2 -0
@@ -1 +1 @@
1
- .n-fadeIn{opacity:0;animation:fadeIn var(--animation-duration, .3s) ease-out forwards}.n-fadeInUp{opacity:0;transform:translateY(var(--animation-transformY, 5px));animation:fadeInUp var(--animation-duration, .3s) ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInUp{to{opacity:1;transform:translateY(0)}}.n-dropzone{--n-dropzone-accent: var(--color-brand-primary, #0e7fe1);--n-dropzone-radius: var(--radius-2xl, 1rem);box-sizing:border-box;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-s);width:100%;height:100%;min-height:18rem;padding:var(--space-2xl, 2.5rem) var(--space-l, 1.5rem);text-align:center;color:var(--color-text-default, #14161a);background:var(--color-bg, #fff);border:2px dashed var(--color-border-default, rgba(0, 0, 0, .15));border-radius:var(--n-dropzone-radius);transition:border-color .2s ease-out,background-color .2s ease-out,box-shadow .2s ease-out}.n-dropzone.is-active{border-color:var(--n-dropzone-accent);background:var(--color-bg-2, #f6f8fa);box-shadow:0 0 0 4px color-mix(in srgb,var(--n-dropzone-accent) 18%,transparent)}.n-dropzone.is-busy{border-style:solid;border-color:var(--color-border-subtle, rgba(0, 0, 0, .08))}.n-dropzone:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:radial-gradient(120% 120% at 50% 0%,color-mix(in srgb,var(--n-dropzone-accent) 8%,transparent),transparent 60%);opacity:0;transition:opacity .2s ease-out;pointer-events:none}.n-dropzone.is-active:before{opacity:1}.n-dropzone-panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-xs, .75rem);width:100%;animation:dropPanelIn .32s cubic-bezier(.22,1,.36,1) both}@keyframes dropPanelIn{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}.n-dropzone-title{margin:0;font-size:1.125rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-snug, 1.3)}.n-dropzone-title--error{color:var(--color-invalid-text, #d00)}.n-dropzone-subtitle{margin:0;max-width:30rem;font-size:.9375rem;color:var(--color-text-weak, #5c6570);line-height:var(--line-height-text, 1.5)}.n-dropzone-glyph{display:grid;place-items:center;width:3.5rem;height:3.5rem;color:var(--n-dropzone-accent)}.n-dropzone-glyph svg{width:100%;height:100%}.n-dropzone-glyph-arrow{animation:dropArrowBob 2.4s ease-in-out infinite}.n-dropzone.is-active .n-dropzone-glyph-arrow{animation-duration:.9s}@keyframes dropArrowBob{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.n-dropzone-glyph--success{color:var(--color-success-text, #108b46)}.n-dropzone-check-ring{stroke-dasharray:126;stroke-dashoffset:126;animation:dropDraw .5s ease-out 80ms forwards}.n-dropzone-check-mark{stroke-dasharray:32;stroke-dashoffset:32;animation:dropDraw .32s ease-out .46s forwards}@keyframes dropDraw{to{stroke-dashoffset:0}}.n-dropzone-loading{display:flex;flex-direction:column;align-items:center;gap:var(--space-s, 1rem)}.n-dropzone-spinner{width:2.25rem;height:2.25rem;border-radius:var(--radius-pill, 999px);border:3px solid color-mix(in srgb,var(--n-dropzone-accent) 22%,transparent);border-top-color:var(--n-dropzone-accent);animation:dropSpin .72s linear infinite}@keyframes dropSpin{to{transform:rotate(360deg)}}.n-dropzone-nudge{display:block;font-size:.8125rem;color:var(--color-text-weaker, #8a929c)}.n-dropzone-progress{width:min(22rem,100%);height:.5rem;border-radius:var(--radius-pill, 999px);background:var(--color-bg-3, rgba(0, 0, 0, .08));overflow:hidden}.n-dropzone-progress-bar{height:100%;border-radius:inherit;background:var(--n-dropzone-accent);transition:width .3s cubic-bezier(.22,1,.36,1)}.n-dropzone-link{display:inline-flex;align-items:center;gap:var(--space-3xs, .35rem);font-size:1rem;font-weight:var(--font-weight-semibold, 600);color:var(--color-link, #0e7fe1);text-decoration:none}.n-dropzone-link:hover{text-decoration:underline}.n-dropzone-link-icon{width:.9em;height:.9em}.n-dropzone-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--space-s, 1rem);margin-block-start:var(--space-2xs, .5rem)}.n-dropzone-browse{display:inline-flex;align-items:center;justify-content:center;padding:var(--space-2xs, .5rem) var(--space-m, 1.25rem);border:none;border-radius:var(--radius-pill, 999px);background:var(--n-dropzone-accent);color:var(--neutral-000, #fff);font-size:.9375rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-none, 1);text-decoration:none;cursor:pointer;transition:background-color .15s ease-out,transform .12s ease-out}.n-dropzone-browse:hover{background:var(--color-brand-primary-hover, #0b6bc0);transform:translateY(-1px)}.n-dropzone-browse:active{transform:translateY(0)}.n-dropzone-reset{padding:var(--space-2xs, .5rem) var(--space-m, 1.25rem);border:1px solid var(--color-border-default, rgba(0, 0, 0, .15));border-radius:var(--radius-pill, 999px);background:transparent;color:var(--color-text-default, #14161a);font-size:.9375rem;font-weight:var(--font-weight-semibold, 600);cursor:pointer;transition:background-color .15s ease-out}.n-dropzone-reset:hover{background:var(--color-bg-2, #f6f8fa)}.n-dropzone-warning{display:flex;align-items:center;gap:var(--space-2xs, .5rem);margin:0;margin-block-start:var(--space-xs, .75rem);padding:var(--space-2xs, .5rem) var(--space-s, 1rem);max-width:32rem;border-radius:var(--radius-m, .5rem);background:var(--color-warning-bg, #fdf3d7);color:var(--color-warning-text, #7a5b00);font-size:.8125rem;text-align:left}.n-dropzone-warning-icon{flex:none;width:1rem;height:1rem}@media (prefers-reduced-motion: reduce){.n-dropzone,.n-dropzone-panel,.n-dropzone-glyph-arrow,.n-dropzone-spinner,.n-dropzone-progress-bar,.n-dropzone-check-ring,.n-dropzone-check-mark{animation:none!important;transition:none!important}.n-dropzone-check-ring,.n-dropzone-check-mark{stroke-dashoffset:0}.n-dropzone-spinner{border-top-color:var(--n-dropzone-accent)}}
1
+ .n-fadeIn{opacity:0;animation:fadeIn var(--animation-duration, .3s) ease-out forwards}.n-fadeInUp{opacity:0;transform:translateY(var(--animation-transformY, 5px));animation:fadeInUp var(--animation-duration, .3s) ease-out forwards}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeInUp{to{opacity:1;transform:translateY(0)}}.n-dropzone{--n-dropzone-accent: var(--color-brand-primary, #0e7fe1);--n-dropzone-radius: var(--radius-2xl, 1rem);box-sizing:border-box;position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:var(--space-s);width:100%;height:100%;min-height:18rem;padding:var(--space-2xl, 2.5rem) var(--space-l, 1.5rem);text-align:center;color:var(--color-text-default, #14161a);background:var(--color-bg, #fff);border:2px dashed var(--color-border-default, rgba(0, 0, 0, .15));border-radius:var(--n-dropzone-radius);transition:border-color .2s ease-out,background-color .2s ease-out,box-shadow .2s ease-out}.n-dropzone.is-active{border-color:var(--n-dropzone-accent);background:var(--color-bg-2, #f6f8fa);box-shadow:0 0 0 4px color-mix(in srgb,var(--n-dropzone-accent) 18%,transparent)}.n-dropzone.is-busy{border-style:solid;border-color:var(--color-border-subtle, rgba(0, 0, 0, .08))}.n-dropzone:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:inherit;background:radial-gradient(120% 120% at 50% 0%,color-mix(in srgb,var(--n-dropzone-accent) 8%,transparent),transparent 60%);opacity:0;transition:opacity .2s ease-out;pointer-events:none}.n-dropzone.is-active:before{opacity:1}.n-dropzone-panel{display:flex;flex-direction:column;align-items:center;gap:var(--space-xs, .75rem);width:100%;animation:dropPanelIn .32s cubic-bezier(.22,1,.36,1) both}@keyframes dropPanelIn{0%{opacity:0;transform:translateY(8px) scale(.98)}to{opacity:1;transform:none}}.n-dropzone-title{margin:0;font-size:1.125rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-snug, 1.3)}.n-dropzone-title--error{color:var(--color-invalid-text, #d00)}.n-dropzone-subtitle{margin:0;max-width:30rem;font-size:.9375rem;color:var(--color-text-weak, #5c6570);line-height:var(--line-height-text, 1.5)}.n-dropzone-glyph{display:grid;place-items:center;width:3.5rem;height:3.5rem;color:var(--n-dropzone-accent)}.n-dropzone-glyph svg{width:100%;height:100%}.n-dropzone-glyph-arrow{animation:dropArrowBob 2.4s ease-in-out infinite}.n-dropzone.is-active .n-dropzone-glyph-arrow{animation-duration:.9s}@keyframes dropArrowBob{0%,to{transform:translateY(0)}50%{transform:translateY(-3px)}}.n-dropzone-loading{display:flex;flex-direction:column;align-items:center;gap:var(--space-s, 1rem)}.n-dropzone-spinner{width:2.25rem;height:2.25rem;border-radius:var(--radius-pill, 999px);border:3px solid color-mix(in srgb,var(--n-dropzone-accent) 22%,transparent);border-top-color:var(--n-dropzone-accent);animation:dropSpin .72s linear infinite}@keyframes dropSpin{to{transform:rotate(360deg)}}.n-dropzone-nudge{display:block;font-size:.8125rem;color:var(--color-text-weaker, #8a929c)}.n-dropzone-progress{width:min(22rem,100%);height:.5rem;border-radius:var(--radius-pill, 999px);background:var(--color-bg-3, rgba(0, 0, 0, .08));overflow:hidden}.n-dropzone-progress-bar{height:100%;border-radius:inherit;background:var(--n-dropzone-accent);transition:width .3s cubic-bezier(.22,1,.36,1)}.n-dropzone-browse{display:inline-flex;align-items:center;justify-content:center;padding:var(--space-2xs, .5rem) var(--space-m, 1.25rem);border:none;border-radius:var(--radius-pill, 999px);background:var(--n-dropzone-accent);color:var(--neutral-000, #fff);font-size:.9375rem;font-weight:var(--font-weight-semibold, 600);line-height:var(--line-height-none, 1);text-decoration:none;cursor:pointer;transition:background-color .15s ease-out,transform .12s ease-out}.n-dropzone-browse:hover{background:var(--color-brand-primary-hover, #0b6bc0);transform:translateY(-1px)}.n-dropzone-browse:active{transform:translateY(0)}.n-dropzone-warning{display:flex;align-items:center;gap:var(--space-2xs, .5rem);margin:0;margin-block-start:var(--space-xs, .75rem);padding:var(--space-2xs, .5rem) var(--space-s, 1rem);max-width:32rem;border-radius:var(--radius-m, .5rem);background:var(--color-warning-bg, #fdf3d7);color:var(--color-warning-text, #7a5b00);font-size:.8125rem;text-align:left}.n-dropzone-warning-icon{flex:none;width:1rem;height:1rem}@media (prefers-reduced-motion: reduce){.n-dropzone,.n-dropzone-panel,.n-dropzone-glyph-arrow,.n-dropzone-spinner,.n-dropzone-progress-bar{animation:none!important;transition:none!important}.n-dropzone-spinner{border-top-color:var(--n-dropzone-accent)}}
@@ -7,5 +7,5 @@ export { default as SearchToggle } from './preact/SearchModal/components/SearchT
7
7
  export { default as SearchModal } from './preact/SearchModal/components/SearchModal/SearchModal';
8
8
  export { default as DropZone } from './preact/DropZone/DropZone';
9
9
  export { AnonymousDropClient, deployFiles, readDataTransfer, readFileList, } from './preact/DropZone/drop-core';
10
- export type { DropClient, Deploy, Digest, DeployResult, DeployProgress, DeployPhase, ProcessedFile, } from './preact/DropZone/drop-core';
10
+ export type { DropClient, DropResponse, Digest, DeployResult, DeployProgress, DeployPhase, ProcessedFile, } from './preact/DropZone/drop-core';
11
11
  export { type IconName } from './preact/Icon';
@@ -1,11 +1,11 @@
1
1
  import { u as e } from "../../../chunks/jsxRuntime.module.Bzuv3cXw.js";
2
- import { d as k, A as I } from "../../../chunks/hooks.module.DRcxknIz.js";
3
- import b from "../Icon/index.js";
4
- import { getSingleNonIndexHtmlFileName as $, hasMultipleHtmlFilesWithoutIndex as D, readDataTransfer as F, readFileList as T } from "./drop-core/readFiles.js";
2
+ import { d as m, A as C } from "../../../chunks/hooks.module.DRcxknIz.js";
3
+ import I from "../Icon/index.js";
4
+ import { getSingleNonIndexHtmlFileName as N, hasMultipleHtmlFilesWithoutIndex as D, readDataTransfer as F, readFileList as T } from "./drop-core/readFiles.js";
5
5
  import { AnonymousDropClient as M } from "./drop-core/client.js";
6
6
  import { deployFiles as P } from "./drop-core/deploy.js";
7
- import { Fragment as p } from "preact";
8
- import '../../../assets/DropZone.css';const U = (n) => `https://app.netlify.com/drop/${n}/claim`;
7
+ import { Fragment as k } from "preact";
8
+ import '../../../assets/DropZone.css';const U = (n) => `https://app.netlify.com/drop/${n}`;
9
9
  function A(n) {
10
10
  switch (n.phase) {
11
11
  case "creating":
@@ -17,75 +17,74 @@ function A(n) {
17
17
  return { kind: "processing" };
18
18
  }
19
19
  }
20
- function Y({
20
+ function O({
21
21
  apiBase: n,
22
- client: h,
23
- claimUrl: d = U,
24
- onDeploy: s,
25
- className: l
22
+ client: p,
23
+ claimUrl: u = U,
24
+ onDeploy: i,
25
+ className: s
26
26
  }) {
27
- const [o, t] = k({ kind: "idle" }), [w, c] = k(null), [C, g] = k(!1), x = I(h ?? new M(n)).current, f = o.kind !== "idle" && o.kind !== "done" && o.kind !== "error";
28
- async function z(i) {
29
- c(null), t({ kind: "reading" });
27
+ const [o, a] = m({ kind: "idle" }), [w, d] = m(null), [v, g] = m(!1), z = C(p ?? new M(n)).current, h = o.kind !== "idle" && o.kind !== "error";
28
+ async function y(t) {
29
+ d(null), a({ kind: "reading" });
30
30
  try {
31
- const r = await i();
31
+ const r = await t();
32
32
  if (!r.length) {
33
- t({ kind: "error", message: "No files found to deploy." });
33
+ a({ kind: "error", message: "No files found to deploy." });
34
34
  return;
35
35
  }
36
- const y = $(r);
37
- y ? c(`No index.html found — "${y}" won’t be served at the site root.`) : D(r) && c("No index.html found — your site may not have a landing page.");
38
- const { url: v, token: m, deploy: a } = await P(x, r, {
39
- onProgress: (S) => t(A(S))
36
+ const b = N(r);
37
+ b ? d(`No index.html found — "${b}" won’t be served at the site root.`) : D(r) && d("No index.html found — your site may not have a landing page.");
38
+ const { url: $, token: f, deploy: c } = await P(z, r, {
39
+ onProgress: (x) => a(A(x))
40
40
  });
41
41
  try {
42
- localStorage.setItem("drop-token", m), localStorage.setItem("dropSiteName", a.subdomain);
42
+ localStorage.setItem("drop-token", f), localStorage.setItem("dropSiteName", c.subdomain);
43
43
  } catch {
44
44
  }
45
- t({ kind: "done", url: v, token: m, siteName: a.subdomain, siteId: a.id }), s == null || s({ url: v, token: m, siteName: a.subdomain, siteId: a.id });
45
+ a({ kind: "redirecting" }), i == null || i({ url: $, token: f, siteName: c.subdomain, siteId: c.id }), window.location.assign(`${u(c.subdomain)}#drop_token=${f}`);
46
46
  } catch (r) {
47
- t({ kind: "error", message: r instanceof Error ? r.message : String(r) });
47
+ a({ kind: "error", message: r instanceof Error ? r.message : String(r) });
48
48
  }
49
49
  }
50
- function N() {
51
- c(null), t({ kind: "idle" });
50
+ function S() {
51
+ d(null), a({ kind: "idle" });
52
52
  }
53
53
  return /* @__PURE__ */ e(
54
54
  "div",
55
55
  {
56
- class: `n-dropzone${C ? " is-active" : ""}${f ? " is-busy" : ""}${l ? ` ${l}` : ""}`,
56
+ class: `n-dropzone${v ? " is-active" : ""}${h ? " is-busy" : ""}${s ? ` ${s}` : ""}`,
57
57
  "data-state": o.kind,
58
- onDragOver: (i) => {
59
- f || (i.preventDefault(), g(!0));
58
+ onDragOver: (t) => {
59
+ h || (t.preventDefault(), g(!0));
60
60
  },
61
- onDragLeave: (i) => {
62
- i.currentTarget === i.target && g(!1);
61
+ onDragLeave: (t) => {
62
+ t.currentTarget === t.target && g(!1);
63
63
  },
64
- onDrop: (i) => {
65
- if (i.preventDefault(), g(!1), f) return;
66
- const r = i.dataTransfer;
67
- r && z(() => F(r));
64
+ onDrop: (t) => {
65
+ if (t.preventDefault(), g(!1), h) return;
66
+ const r = t.dataTransfer;
67
+ r && y(() => F(r));
68
68
  },
69
69
  children: [
70
- /* @__PURE__ */ e("div", { class: "n-dropzone-panel", children: /* @__PURE__ */ e(B, { status: o, claimUrl: d, onReset: N, onFiles: z }) }, o.kind),
70
+ /* @__PURE__ */ e("div", { class: "n-dropzone-panel", children: /* @__PURE__ */ e(L, { status: o, onReset: S, onFiles: y }) }, o.kind),
71
71
  w && o.kind !== "error" && /* @__PURE__ */ e("p", { class: "n-dropzone-warning n-fadeIn", role: "status", children: [
72
- /* @__PURE__ */ e(b, { name: "lightbulb", className: "n-dropzone-warning-icon" }),
72
+ /* @__PURE__ */ e(I, { name: "lightbulb", className: "n-dropzone-warning-icon" }),
73
73
  w
74
74
  ] })
75
75
  ]
76
76
  }
77
77
  );
78
78
  }
79
- function B({
79
+ function L({
80
80
  status: n,
81
- claimUrl: h,
82
- onReset: d,
83
- onFiles: s
81
+ onReset: p,
82
+ onFiles: u
84
83
  }) {
85
84
  switch (n.kind) {
86
85
  case "idle":
87
- return /* @__PURE__ */ e(p, { children: [
88
- /* @__PURE__ */ e(L, {}),
86
+ return /* @__PURE__ */ e(k, { children: [
87
+ /* @__PURE__ */ e(R, {}),
89
88
  /* @__PURE__ */ e("p", { class: "n-dropzone-title", children: "Drag & drop your site folder or zip" }),
90
89
  /* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", children: "Deploys instantly to a live URL — no account needed." }),
91
90
  /* @__PURE__ */ e("label", { class: "n-dropzone-browse", children: [
@@ -98,50 +97,39 @@ function B({
98
97
  multiple: !0,
99
98
  webkitdirectory: "",
100
99
  directory: "",
101
- onChange: (l) => {
102
- var t;
103
- const o = l.currentTarget;
104
- (t = o.files) != null && t.length && s(() => T(o.files));
100
+ onChange: (i) => {
101
+ var o;
102
+ const s = i.currentTarget;
103
+ (o = s.files) != null && o.length && u(() => T(s.files));
105
104
  }
106
105
  }
107
106
  )
108
107
  ] })
109
108
  ] });
110
109
  case "reading":
111
- return /* @__PURE__ */ e(u, { label: "Reading files…" });
110
+ return /* @__PURE__ */ e(l, { label: "Reading files…" });
112
111
  case "creating":
113
- return /* @__PURE__ */ e(u, { label: "Creating deploy…" });
112
+ return /* @__PURE__ */ e(l, { label: "Creating deploy…" });
114
113
  case "processing":
115
- return /* @__PURE__ */ e(u, { label: "Processing — almost live…" });
114
+ return /* @__PURE__ */ e(l, { label: "Processing — almost live…" });
115
+ case "redirecting":
116
+ return /* @__PURE__ */ e(l, { label: "Site’s live — taking you to claim it…" });
116
117
  case "uploading": {
117
- const l = n.total ? Math.round(n.uploaded / n.total * 100) : 0;
118
- return /* @__PURE__ */ e(p, { children: [
119
- /* @__PURE__ */ e(u, { label: `Uploading ${n.uploaded}/${n.total} files…` }),
120
- /* @__PURE__ */ e("div", { class: "n-dropzone-progress", role: "progressbar", "aria-valuenow": l, children: /* @__PURE__ */ e("div", { class: "n-dropzone-progress-bar", style: { width: `${l}%` } }) })
118
+ const i = n.total ? Math.round(n.uploaded / n.total * 100) : 0;
119
+ return /* @__PURE__ */ e(k, { children: [
120
+ /* @__PURE__ */ e(l, { label: `Uploading ${n.uploaded}/${n.total} files…` }),
121
+ /* @__PURE__ */ e("div", { class: "n-dropzone-progress", role: "progressbar", "aria-valuenow": i, children: /* @__PURE__ */ e("div", { class: "n-dropzone-progress-bar", style: { width: `${i}%` } }) })
121
122
  ] });
122
123
  }
123
- case "done":
124
- return /* @__PURE__ */ e(p, { children: [
125
- /* @__PURE__ */ e(j, {}),
126
- /* @__PURE__ */ e("p", { class: "n-dropzone-title", children: "Your site is live!" }),
127
- /* @__PURE__ */ e("a", { class: "n-dropzone-link", href: n.url, target: "_blank", rel: "noopener noreferrer", children: [
128
- n.url.replace(/^https?:\/\//, ""),
129
- /* @__PURE__ */ e(b, { name: "link", className: "n-dropzone-link-icon" })
130
- ] }),
131
- /* @__PURE__ */ e("div", { class: "n-dropzone-actions", children: [
132
- /* @__PURE__ */ e("a", { class: "n-dropzone-browse", href: h(n.siteName), children: "Claim this site" }),
133
- /* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-reset", onClick: d, children: "Deploy another" })
134
- ] })
135
- ] });
136
124
  case "error":
137
- return /* @__PURE__ */ e(p, { children: [
125
+ return /* @__PURE__ */ e(k, { children: [
138
126
  /* @__PURE__ */ e("p", { class: "n-dropzone-title n-dropzone-title--error", children: "Something went wrong" }),
139
127
  /* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", role: "alert", children: n.message }),
140
- /* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-browse", onClick: d, children: "Try again" })
128
+ /* @__PURE__ */ e("button", { type: "button", class: "n-dropzone-browse", onClick: p, children: "Try again" })
141
129
  ] });
142
130
  }
143
131
  }
144
- function u({ label: n }) {
132
+ function l({ label: n }) {
145
133
  return /* @__PURE__ */ e("div", { class: "n-dropzone-loading", children: [
146
134
  /* @__PURE__ */ e("span", { class: "n-dropzone-spinner", "aria-hidden": "true" }),
147
135
  /* @__PURE__ */ e("p", { class: "n-dropzone-subtitle", "aria-live": "polite", children: [
@@ -151,7 +139,7 @@ function u({ label: n }) {
151
139
  ] })
152
140
  ] });
153
141
  }
154
- function L() {
142
+ function R() {
155
143
  return /* @__PURE__ */ e("span", { class: "n-dropzone-glyph", "aria-hidden": "true", children: /* @__PURE__ */ e("svg", { viewBox: "0 0 48 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
156
144
  /* @__PURE__ */ e(
157
145
  "path",
@@ -176,32 +164,6 @@ function L() {
176
164
  )
177
165
  ] }) });
178
166
  }
179
- function j() {
180
- return /* @__PURE__ */ e("span", { class: "n-dropzone-glyph n-dropzone-glyph--success", "aria-hidden": "true", children: /* @__PURE__ */ e("svg", { viewBox: "0 0 48 48", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: [
181
- /* @__PURE__ */ e(
182
- "circle",
183
- {
184
- class: "n-dropzone-check-ring",
185
- cx: "24",
186
- cy: "24",
187
- r: "20",
188
- stroke: "currentColor",
189
- "stroke-width": "3"
190
- }
191
- ),
192
- /* @__PURE__ */ e(
193
- "path",
194
- {
195
- class: "n-dropzone-check-mark",
196
- d: "M15 24.5 21 30.5 33 18",
197
- stroke: "currentColor",
198
- "stroke-width": "3",
199
- "stroke-linecap": "round",
200
- "stroke-linejoin": "round"
201
- }
202
- )
203
- ] }) });
204
- }
205
167
  export {
206
- Y as default
168
+ O as default
207
169
  };
@@ -579,7 +579,10 @@ async function U(x) {
579
579
  ), p = [];
580
580
  for (const [v, s] of Object.entries(b)) {
581
581
  if (v.endsWith("/") || /(^|\/)(__MACOSX\/|\.)/.test(v)) continue;
582
- const g = s.buffer.slice(s.byteOffset, s.byteOffset + s.byteLength);
582
+ const g = s.buffer.slice(
583
+ s.byteOffset,
584
+ s.byteOffset + s.byteLength
585
+ );
583
586
  p.push(k(v, g, v.split("/").pop()));
584
587
  }
585
588
  return O(p);
@@ -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.3",
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 */
@@ -15,7 +15,7 @@ export {
15
15
  } from './preact/DropZone/drop-core';
16
16
  export type {
17
17
  DropClient,
18
- Deploy,
18
+ DropResponse,
19
19
  Digest,
20
20
  DeployResult,
21
21
  DeployProgress,
@@ -138,31 +138,6 @@
138
138
  }
139
139
  }
140
140
 
141
- /* ----------------------------- */
142
- /* Success glyph (draws in) */
143
- /* ----------------------------- */
144
- .n-dropzone-glyph--success {
145
- color: var(--color-success-text, #108b46);
146
- }
147
-
148
- .n-dropzone-check-ring {
149
- stroke-dasharray: 126;
150
- stroke-dashoffset: 126;
151
- animation: dropDraw 500ms ease-out 80ms forwards;
152
- }
153
-
154
- .n-dropzone-check-mark {
155
- stroke-dasharray: 32;
156
- stroke-dashoffset: 32;
157
- animation: dropDraw 320ms ease-out 460ms forwards;
158
- }
159
-
160
- @keyframes dropDraw {
161
- to {
162
- stroke-dashoffset: 0;
163
- }
164
- }
165
-
166
141
  /* ----------------------------- */
167
142
  /* Loading / spinner */
168
143
  /* ----------------------------- */
@@ -212,37 +187,6 @@
212
187
  transition: width 300ms cubic-bezier(0.22, 1, 0.36, 1);
213
188
  }
214
189
 
215
- /* ----------------------------- */
216
- /* Done state links & actions */
217
- /* ----------------------------- */
218
- .n-dropzone-link {
219
- display: inline-flex;
220
- align-items: center;
221
- gap: var(--space-3xs, 0.35rem);
222
- font-size: 1rem;
223
- font-weight: var(--font-weight-semibold, 600);
224
- color: var(--color-link, #0e7fe1);
225
- text-decoration: none;
226
- }
227
-
228
- .n-dropzone-link:hover {
229
- text-decoration: underline;
230
- }
231
-
232
- .n-dropzone-link-icon {
233
- width: 0.9em;
234
- height: 0.9em;
235
- }
236
-
237
- .n-dropzone-actions {
238
- display: flex;
239
- flex-wrap: wrap;
240
- align-items: center;
241
- justify-content: center;
242
- gap: var(--space-s, 1rem);
243
- margin-block-start: var(--space-2xs, 0.5rem);
244
- }
245
-
246
190
  /* ----------------------------- */
247
191
  /* Buttons */
248
192
  /* ----------------------------- */
@@ -274,22 +218,6 @@
274
218
  transform: translateY(0);
275
219
  }
276
220
 
277
- .n-dropzone-reset {
278
- padding: var(--space-2xs, 0.5rem) var(--space-m, 1.25rem);
279
- border: 1px solid var(--color-border-default, rgba(0, 0, 0, 0.15));
280
- border-radius: var(--radius-pill, 999px);
281
- background: transparent;
282
- color: var(--color-text-default, #14161a);
283
- font-size: 0.9375rem;
284
- font-weight: var(--font-weight-semibold, 600);
285
- cursor: pointer;
286
- transition: background-color 150ms ease-out;
287
- }
288
-
289
- .n-dropzone-reset:hover {
290
- background: var(--color-bg-2, #f6f8fa);
291
- }
292
-
293
221
  /* ----------------------------- */
294
222
  /* Warning banner */
295
223
  /* ----------------------------- */
@@ -322,18 +250,11 @@
322
250
  .n-dropzone-panel,
323
251
  .n-dropzone-glyph-arrow,
324
252
  .n-dropzone-spinner,
325
- .n-dropzone-progress-bar,
326
- .n-dropzone-check-ring,
327
- .n-dropzone-check-mark {
253
+ .n-dropzone-progress-bar {
328
254
  animation: none !important;
329
255
  transition: none !important;
330
256
  }
331
257
 
332
- .n-dropzone-check-ring,
333
- .n-dropzone-check-mark {
334
- stroke-dashoffset: 0;
335
- }
336
-
337
258
  .n-dropzone-spinner {
338
259
  border-top-color: var(--n-dropzone-accent);
339
260
  }
@@ -20,7 +20,7 @@ type Status =
20
20
  | { kind: 'creating' }
21
21
  | { kind: 'uploading'; uploaded: number; total: number }
22
22
  | { kind: 'processing' }
23
- | { kind: 'done'; url: string; token: string; siteName: string; siteId: string }
23
+ | { kind: 'redirecting' }
24
24
  | { kind: 'error'; message: string };
25
25
 
26
26
  interface Props {
@@ -35,7 +35,7 @@ interface Props {
35
35
  className?: string;
36
36
  }
37
37
 
38
- const defaultClaimUrl = (siteName: string) => `https://app.netlify.com/drop/${siteName}/claim`;
38
+ const defaultClaimUrl = (siteName: string) => `https://app.netlify.com/drop/${siteName}`;
39
39
 
40
40
  function progressPhaseToStatus(e: DeployProgress): Status {
41
41
  switch (e.phase) {
@@ -61,7 +61,7 @@ export default function DropZone({
61
61
  const [active, setActive] = useState(false);
62
62
  const dropClient = useRef(client ?? new AnonymousDropClient(apiBase)).current;
63
63
 
64
- const busy = status.kind !== 'idle' && status.kind !== 'done' && status.kind !== 'error';
64
+ const busy = status.kind !== 'idle' && status.kind !== 'error';
65
65
 
66
66
  async function run(read: () => Promise<ProcessedFile[]>) {
67
67
  setWarning(null);
@@ -85,7 +85,10 @@ export default function DropZone({
85
85
  onProgress: e => setStatus(progressPhaseToStatus(e)),
86
86
  });
87
87
 
88
- // Persist for the claim step after signup (mirrors the dashboard).
88
+ // Best-effort local persistence. Note this does NOT reach the dashboard:
89
+ // localStorage is per-origin, so a token written here (e.g. www.netlify.com)
90
+ // is invisible to app.netlify.com. The cross-origin handoff is the URL
91
+ // fragment below; this only helps if the drop and claim share an origin.
89
92
  try {
90
93
  localStorage.setItem('drop-token', token);
91
94
  localStorage.setItem('dropSiteName', deploy.subdomain);
@@ -93,8 +96,13 @@ export default function DropZone({
93
96
  /* private mode / storage disabled — non-fatal */
94
97
  }
95
98
 
96
- setStatus({ kind: 'done', url, token, siteName: deploy.subdomain, siteId: deploy.id });
99
+ setStatus({ kind: 'redirecting' });
97
100
  onDeploy?.({ url, token, siteName: deploy.subdomain, siteId: deploy.id });
101
+
102
+ // Hand the drop token to the dashboard via the URL fragment — localStorage
103
+ // does not cross origins. The dashboard's /drop/:name page reads
104
+ // `#drop_token=` and persists it for the claim + post-signup steps.
105
+ window.location.assign(`${claimUrl(deploy.subdomain)}#drop_token=${token}`);
98
106
  } catch (err) {
99
107
  setStatus({ kind: 'error', message: err instanceof Error ? err.message : String(err) });
100
108
  }
@@ -131,7 +139,7 @@ export default function DropZone({
131
139
  >
132
140
  {/* keyed so each state change remounts and replays its enter animation */}
133
141
  <div class="n-dropzone-panel" key={status.kind}>
134
- <StatusView status={status} claimUrl={claimUrl} onReset={reset} onFiles={run} />
142
+ <StatusView status={status} onReset={reset} onFiles={run} />
135
143
  </div>
136
144
 
137
145
  {warning && status.kind !== 'error' && (
@@ -146,12 +154,10 @@ export default function DropZone({
146
154
 
147
155
  function StatusView({
148
156
  status,
149
- claimUrl,
150
157
  onReset,
151
158
  onFiles,
152
159
  }: {
153
160
  status: Status;
154
- claimUrl: (siteName: string) => string;
155
161
  onReset: () => void;
156
162
  onFiles: (read: () => Promise<ProcessedFile[]>) => void;
157
163
  }) {
@@ -186,6 +192,8 @@ function StatusView({
186
192
  return <Spinner label="Creating deploy…" />;
187
193
  case 'processing':
188
194
  return <Spinner label="Processing — almost live…" />;
195
+ case 'redirecting':
196
+ return <Spinner label="Site’s live — taking you to claim it…" />;
189
197
 
190
198
  case 'uploading': {
191
199
  const pct = status.total ? Math.round((status.uploaded / status.total) * 100) : 0;
@@ -199,26 +207,6 @@ function StatusView({
199
207
  );
200
208
  }
201
209
 
202
- case 'done':
203
- return (
204
- <>
205
- <SuccessGlyph />
206
- <p class="n-dropzone-title">Your site is live!</p>
207
- <a class="n-dropzone-link" href={status.url} target="_blank" rel="noopener noreferrer">
208
- {status.url.replace(/^https?:\/\//, '')}
209
- <Icon name="link" className="n-dropzone-link-icon" />
210
- </a>
211
- <div class="n-dropzone-actions">
212
- <a class="n-dropzone-browse" href={claimUrl(status.siteName)}>
213
- Claim this site
214
- </a>
215
- <button type="button" class="n-dropzone-reset" onClick={onReset}>
216
- Deploy another
217
- </button>
218
- </div>
219
- </>
220
- );
221
-
222
210
  case 'error':
223
211
  return (
224
212
  <>
@@ -268,28 +256,3 @@ function UploadGlyph() {
268
256
  </span>
269
257
  );
270
258
  }
271
-
272
- function SuccessGlyph() {
273
- return (
274
- <span class="n-dropzone-glyph n-dropzone-glyph--success" aria-hidden="true">
275
- <svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
276
- <circle
277
- class="n-dropzone-check-ring"
278
- cx="24"
279
- cy="24"
280
- r="20"
281
- stroke="currentColor"
282
- stroke-width="3"
283
- />
284
- <path
285
- class="n-dropzone-check-mark"
286
- d="M15 24.5 21 30.5 33 18"
287
- stroke="currentColor"
288
- stroke-width="3"
289
- stroke-linecap="round"
290
- stroke-linejoin="round"
291
- />
292
- </svg>
293
- </span>
294
- );
295
- }
@@ -99,7 +99,12 @@ export async function readZip(zip: File): Promise<ProcessedFile[]> {
99
99
  // fflate uses a trailing slash to signal directory entries; also skip the
100
100
  // usual junk (macOS metadata, dotfiles at any depth).
101
101
  if (path.endsWith('/') || /(^|\/)(__MACOSX\/|\.)/.test(path)) continue;
102
- const content = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
102
+ // `bytes.buffer` is ArrayBufferLike; fflate always backs entries with a plain
103
+ // ArrayBuffer, so narrow it for toProcessedFile's ArrayBuffer parameter.
104
+ const content = bytes.buffer.slice(
105
+ bytes.byteOffset,
106
+ bytes.byteOffset + bytes.byteLength,
107
+ ) as ArrayBuffer;
103
108
  out.push(toProcessedFile(path, content, path.split('/').pop()!));
104
109
  }
105
110
  return normalizeFiles(out);
@@ -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 {