@cloudflare/ai-search-snippet 0.0.24 → 0.0.26

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.
@@ -1,7 +1,7 @@
1
1
  var R = Object.defineProperty;
2
2
  var H = (o, i, e) => i in o ? R(o, i, { enumerable: !0, configurable: !0, writable: !0, value: e }) : o[i] = e;
3
3
  var a = (o, i, e) => H(o, typeof i != "symbol" ? i + "" : i, e);
4
- const u = [
4
+ const p = [
5
5
  "Searching...",
6
6
  "Digging through results...",
7
7
  "Scanning the knowledge base...",
@@ -22,7 +22,7 @@ function A(o, i) {
22
22
  clearTimeout(e), e = setTimeout(r, i);
23
23
  };
24
24
  }
25
- function l(o) {
25
+ function h(o) {
26
26
  const i = document.createElement("div");
27
27
  return i.textContent = o, i.innerHTML;
28
28
  }
@@ -51,18 +51,18 @@ function N(o) {
51
51
  function E(o = "id") {
52
52
  return `${o}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
53
53
  }
54
- function g(o, i) {
54
+ function d(o, i) {
55
55
  return o !== null ? o : i;
56
56
  }
57
- function b(o, i) {
57
+ function m(o, i) {
58
58
  return o === null ? i : o === "true" || o === "";
59
59
  }
60
- function w(o, i) {
60
+ function f(o, i) {
61
61
  if (o === null) return i;
62
62
  const e = Number.parseInt(o, 10);
63
63
  return Number.isNaN(e) ? i : e;
64
64
  }
65
- function v(o, i) {
65
+ function g(o, i) {
66
66
  return new CustomEvent(o, {
67
67
  detail: i,
68
68
  bubbles: !0,
@@ -70,7 +70,7 @@ function v(o, i) {
70
70
  cancelable: !0
71
71
  });
72
72
  }
73
- function y(o) {
73
+ function w(o) {
74
74
  if (!o)
75
75
  throw new Error("API URL is required");
76
76
  return new P(o);
@@ -138,24 +138,18 @@ class P extends _ {
138
138
  if (!n.body)
139
139
  throw new Error("Response body is empty");
140
140
  const c = await n.json();
141
- if (c.success && c.result) {
142
- const h = /* @__PURE__ */ new Map();
143
- for (const d of c.result.chunks) {
144
- const m = d.item.key, p = d.scoring_details.vector_score;
145
- (!h.has(m) || (h.get(m)?.score ?? 0) < p) && h.set(m, { chunk: d, score: p });
146
- }
147
- return Array.from(h.values()).sort((d, m) => m.score - d.score).slice(0, 10).map(
148
- ({ chunk: d }) => ({
141
+ if (c.success && c.result)
142
+ return c.result.chunks.slice(0, 10).map(
143
+ (l) => ({
149
144
  type: "result",
150
- id: d.id,
151
- title: S(d.item.metadata.title),
152
- description: d.item.metadata.description ? S(d.item.metadata.description) : "",
153
- url: d.item.key,
154
- image: d.item.metadata.image || void 0,
155
- metadata: d.item.metadata
145
+ id: l.id,
146
+ title: S(l.item.metadata?.title),
147
+ description: l.item.metadata?.description ? S(l.item.metadata?.description) : "",
148
+ url: l.item.key,
149
+ image: l.item.metadata?.image || void 0,
150
+ metadata: l.item.metadata
156
151
  })
157
152
  );
158
- }
159
153
  throw c.success === !1 ? new Error(c.error) : new Error("Unknown error");
160
154
  } finally {
161
155
  this.unregisterRequest(t);
@@ -177,12 +171,12 @@ class P extends _ {
177
171
  if (!n.body)
178
172
  throw new Error("Response body is empty");
179
173
  let c = "";
180
- const h = n.body.getReader(), d = new TextDecoder();
174
+ const l = n.body.getReader(), b = new TextDecoder();
181
175
  for (; ; ) {
182
- const { done: p, value: C } = await h.read();
183
- if (p)
176
+ const { done: u, value: C } = await l.read();
177
+ if (u)
184
178
  break;
185
- const B = d.decode(C, { stream: !0 });
179
+ const B = b.decode(C, { stream: !0 });
186
180
  c += B;
187
181
  }
188
182
  yield {
@@ -191,7 +185,7 @@ class P extends _ {
191
185
  title: "",
192
186
  description: c.replaceAll("data: ", "").trim().split(`
193
187
 
194
- `).map((p) => JSON.parse(p)).map((p) => p.response).join(""),
188
+ `).map((u) => JSON.parse(u)).map((u) => u.response).join(""),
195
189
  url: "",
196
190
  metadata: {}
197
191
  };
@@ -254,7 +248,7 @@ class P extends _ {
254
248
  const V = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w3.org/2000/svg" aria-label="Cloudflare" role="img">
255
249
  <path fill="#f38020" d="m280.8395,183.31456c11,-26 -4,-38 -19,-38l-148,-2c-4,0 -4,-6 1,-7l150,-2c17,-1 37,-15 43,-33c0,0 10,-21 9,-24a97,97 0 0 0 -187,-11c-38,-25 -78,9 -69,46c-48,3 -65,46 -60,72c0,1 1,2 3,2l274,0c1,0 3,-1 3,-3z"/>
256
250
  <path fill="#faae40" d="m330.8395,81.31456c-4,0 -6,-1 -7,1l-5,21c-5,16 3,30 20,31l32,2c4,0 4,6 -1,7l-33,1c-36,4 -46,39 -46,39c0,2 0,3 2,3l113,0l3,-2a81,81 0 0 0 -78,-103"/>
257
- </svg>`, D = "https://search.ai.cloudflare.com", x = `Powered by <a href="${D}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${V}</a>`, $ = `
251
+ </svg>`, j = "https://search.ai.cloudflare.com", y = `Powered by <a href="${j}" target="_blank" rel="noopener noreferrer">Cloudflare AI Search ${V}</a>`, $ = `
258
252
  /* Chat container */
259
253
  .chat-container {
260
254
  display: flex;
@@ -571,7 +565,7 @@ const V = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
571
565
  .chat-message-bubble a:hover {
572
566
  text-decoration: none;
573
567
  }
574
- `, k = `
568
+ `, x = `
575
569
  :host {
576
570
  /* Colors - Light Mode */
577
571
  --search-snippet-primary-color: #2563eb;
@@ -1006,17 +1000,17 @@ const V = `<svg width="32" height="10" viewBox="0 0 412 186" xmlns="http://www.w
1006
1000
  text-align: center;
1007
1001
  }
1008
1002
  `;
1009
- function O(o) {
1003
+ function D(o) {
1010
1004
  let i = o;
1011
- i = j(i), i = i.replace(/```([\s\S]*?)```/g, (n, c) => `<pre><code>${c.trim()}</code></pre>`);
1005
+ i = O(i), i = i.replace(/```([\s\S]*?)```/g, (n, c) => `<pre><code>${c.trim()}</code></pre>`);
1012
1006
  const e = i.split(`
1013
1007
  `), t = [];
1014
1008
  let s = !1, r = "";
1015
1009
  for (let n = 0; n < e.length; n++) {
1016
- const c = e[n], h = c.match(/^(#{1,6})\s+(.+)$/);
1017
- if (h) {
1018
- const p = h[1].length, C = h[2];
1019
- t.push(`<h${p}>${f(C)}</h${p}>`);
1010
+ const c = e[n], l = c.match(/^(#{1,6})\s+(.+)$/);
1011
+ if (l) {
1012
+ const u = l[1].length, C = l[2];
1013
+ t.push(`<h${u}>${v(C)}</h${u}>`);
1020
1014
  continue;
1021
1015
  }
1022
1016
  if (c.match(/^---+$/)) {
@@ -1024,37 +1018,37 @@ function O(o) {
1024
1018
  continue;
1025
1019
  }
1026
1020
  if (c.match(/^>\s+/)) {
1027
- const p = c.replace(/^>\s+/, "");
1028
- t.push(`<blockquote>${f(p)}</blockquote>`);
1021
+ const u = c.replace(/^>\s+/, "");
1022
+ t.push(`<blockquote>${v(u)}</blockquote>`);
1029
1023
  continue;
1030
1024
  }
1031
- const d = c.match(/^[-*]\s+(.+)$/);
1032
- if (d) {
1033
- (!s || r !== "ul") && (s && t.push(`</${r}>`), t.push("<ul>"), s = !0, r = "ul"), t.push(`<li>${f(d[1])}</li>`);
1025
+ const b = c.match(/^[-*]\s+(.+)$/);
1026
+ if (b) {
1027
+ (!s || r !== "ul") && (s && t.push(`</${r}>`), t.push("<ul>"), s = !0, r = "ul"), t.push(`<li>${v(b[1])}</li>`);
1034
1028
  continue;
1035
1029
  }
1036
- const m = c.match(/^\d+\.\s+(.+)$/);
1037
- if (m) {
1038
- (!s || r !== "ol") && (s && t.push(`</${r}>`), t.push("<ol>"), s = !0, r = "ol"), t.push(`<li>${f(m[1])}</li>`);
1030
+ const k = c.match(/^\d+\.\s+(.+)$/);
1031
+ if (k) {
1032
+ (!s || r !== "ol") && (s && t.push(`</${r}>`), t.push("<ol>"), s = !0, r = "ol"), t.push(`<li>${v(k[1])}</li>`);
1039
1033
  continue;
1040
1034
  }
1041
1035
  if (s && (t.push(`</${r}>`), s = !1, r = ""), c.trim() === "") {
1042
1036
  t.push("<br />");
1043
1037
  continue;
1044
1038
  }
1045
- t.push(`<p>${f(c)}</p>`);
1039
+ t.push(`<p>${v(c)}</p>`);
1046
1040
  }
1047
1041
  return s && t.push(`</${r}>`), t.join(`
1048
1042
  `);
1049
1043
  }
1050
- function f(o) {
1044
+ function v(o) {
1051
1045
  let i = o;
1052
1046
  return i = i.replace(/`([^`]+)`/g, "<code>$1</code>"), i = i.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>"), i = i.replace(/___(.+?)___/g, "<strong><em>$1</em></strong>"), i = i.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>"), i = i.replace(/__(.+?)__/g, "<strong>$1</strong>"), i = i.replace(/\*(.+?)\*/g, "<em>$1</em>"), i = i.replace(/_(.+?)_/g, "<em>$1</em>"), i = i.replace(
1053
1047
  /\[([^\]]+)\]\(([^)]+)\)/g,
1054
1048
  '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
1055
1049
  ), i;
1056
1050
  }
1057
- function j(o) {
1051
+ function O(o) {
1058
1052
  const i = {
1059
1053
  "&": "&amp;",
1060
1054
  "<": "&lt;",
@@ -1104,7 +1098,7 @@ class q {
1104
1098
  <div class="chat-input-wrapper">
1105
1099
  <textarea
1106
1100
  class="chat-input"
1107
- placeholder="${l(this.props.placeholder || "Type a message...")}"
1101
+ placeholder="${h(this.props.placeholder || "Type a message...")}"
1108
1102
  aria-label="Chat message input"
1109
1103
  style="height: 40px;"
1110
1104
  rows="1"
@@ -1159,18 +1153,18 @@ class q {
1159
1153
  try {
1160
1154
  const r = this.client.chat(i);
1161
1155
  let n = "";
1162
- for await (const h of r)
1163
- if (h.type === "text" && h.message)
1164
- n += h.message, this.updateStreamingMessage(t, n);
1165
- else if (h.type === "error") {
1166
- this.showErrorInMessage(t, h.message || "Unknown error");
1156
+ for await (const l of r)
1157
+ if (l.type === "text" && l.message)
1158
+ n += l.message, this.updateStreamingMessage(t, n);
1159
+ else if (l.type === "error") {
1160
+ this.showErrorInMessage(t, l.message || "Unknown error");
1167
1161
  break;
1168
1162
  }
1169
- const c = this.messages.findIndex((h) => h.id === t);
1170
- c !== -1 && (this.messages[c].content = n), this.container.dispatchEvent(v("message", { message: s }));
1163
+ const c = this.messages.findIndex((l) => l.id === t);
1164
+ c !== -1 && (this.messages[c].content = n), this.container.dispatchEvent(g("message", { message: s }));
1171
1165
  } catch (r) {
1172
1166
  this.showErrorInMessage(t, r.message), this.container.dispatchEvent(
1173
- v("error", {
1167
+ g("error", {
1174
1168
  error: {
1175
1169
  message: r.message,
1176
1170
  code: "CHAT_ERROR"
@@ -1235,8 +1229,8 @@ class q {
1235
1229
  <div class="chat-message-avatar">${s}</div>
1236
1230
  <div class="chat-message-content">
1237
1231
  <div class="chat-message-bubble">
1238
- ${i.content ? `<div class="chat-message-text">${O(i.content)}</div>` : ""}
1239
- ${e ? `<div class="chat-streaming"><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="loading-text">${u[this.loadingMessageIndex]}</span></div>` : ""}
1232
+ ${i.content ? `<div class="chat-message-text">${D(i.content)}</div>` : ""}
1233
+ ${e ? `<div class="chat-streaming"><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="chat-streaming-dot"></span><span class="loading-text">${p[this.loadingMessageIndex]}</span></div>` : ""}
1240
1234
  </div>
1241
1235
  <div class="chat-message-metadata">
1242
1236
  <span class="chat-message-time">${N(i.timestamp)}</span>
@@ -1260,8 +1254,8 @@ class q {
1260
1254
  this.isStreaming = i, this.inputElement && (this.inputElement.disabled = i), this.sendButton && (this.sendButton.disabled = i, this.sendButton.innerHTML = i ? '<div class="loading"></div>' : "<span>Send</span>"), i ? this.startLoadingMessages() : this.clearLoadingMessages();
1261
1255
  }
1262
1256
  startLoadingMessages() {
1263
- this.loadingMessageIndex = Math.floor(Math.random() * u.length), this.loadingMessageInterval = setInterval(() => {
1264
- this.loadingMessageIndex = (this.loadingMessageIndex + 1) % u.length, this.isStreaming && this.renderMessages(!0);
1257
+ this.loadingMessageIndex = Math.floor(Math.random() * p.length), this.loadingMessageInterval = setInterval(() => {
1258
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % p.length, this.isStreaming && this.renderMessages(!0);
1265
1259
  }, 2500);
1266
1260
  }
1267
1261
  clearLoadingMessages() {
@@ -1313,7 +1307,7 @@ class K extends HTMLElement {
1313
1307
  return ["api-url", "placeholder", "theme", "hide-branding"];
1314
1308
  }
1315
1309
  connectedCallback() {
1316
- this.render(), this.initializeClient(), this.dispatchEvent(v("ready", void 0));
1310
+ this.render(), this.initializeClient(), this.dispatchEvent(g("ready", void 0));
1317
1311
  }
1318
1312
  disconnectedCallback() {
1319
1313
  this.cleanup();
@@ -1323,10 +1317,10 @@ class K extends HTMLElement {
1323
1317
  }
1324
1318
  getProps() {
1325
1319
  return {
1326
- apiUrl: g(this.getAttribute("api-url"), "http://localhost:3000"),
1327
- placeholder: g(this.getAttribute("placeholder"), "Type a message..."),
1328
- theme: g(this.getAttribute("theme"), "auto"),
1329
- hideBranding: b(this.getAttribute("hide-branding"), !1)
1320
+ apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
1321
+ placeholder: d(this.getAttribute("placeholder"), "Type a message..."),
1322
+ theme: d(this.getAttribute("theme"), "auto"),
1323
+ hideBranding: m(this.getAttribute("hide-branding"), !1)
1330
1324
  };
1331
1325
  }
1332
1326
  initializeClient() {
@@ -1336,14 +1330,14 @@ class K extends HTMLElement {
1336
1330
  return;
1337
1331
  }
1338
1332
  try {
1339
- this.client = y(e.apiUrl);
1333
+ this.client = w(e.apiUrl);
1340
1334
  } catch (t) {
1341
1335
  console.error("ChatBubbleSnippet:", t);
1342
1336
  }
1343
1337
  }
1344
1338
  render() {
1345
1339
  const e = document.createElement("style");
1346
- e.textContent = `${k}
1340
+ e.textContent = `${x}
1347
1341
  ${$}
1348
1342
  ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this.container.className = "chat-bubble-widget", this.container.innerHTML = this.getBaseHTML(), this.shadow.innerHTML = "", this.shadow.appendChild(e), this.shadow.appendChild(this.container), this.attachEventListeners();
1349
1343
  }
@@ -1524,7 +1518,7 @@ ${this.getBubbleStyles()}`, this.container = document.createElement("div"), this
1524
1518
  </div>
1525
1519
  </div>
1526
1520
  <div class="chat-content"></div>
1527
- ${this.getProps().hideBranding ? "" : `<div class="powered-by">${x}</div>`}
1521
+ ${this.getProps().hideBranding ? "" : `<div class="powered-by">${y}</div>`}
1528
1522
  </div>
1529
1523
  `;
1530
1524
  }
@@ -1599,7 +1593,7 @@ class U extends HTMLElement {
1599
1593
  return ["api-url", "placeholder", "theme", "hide-branding"];
1600
1594
  }
1601
1595
  connectedCallback() {
1602
- this.render(), this.initializeClient(), this.setupView(), this.dispatchEvent(v("ready", void 0));
1596
+ this.render(), this.initializeClient(), this.setupView(), this.dispatchEvent(g("ready", void 0));
1603
1597
  }
1604
1598
  disconnectedCallback() {
1605
1599
  this.saveCurrentSession(), this.cleanup();
@@ -1609,10 +1603,10 @@ class U extends HTMLElement {
1609
1603
  }
1610
1604
  getProps() {
1611
1605
  return {
1612
- apiUrl: g(this.getAttribute("api-url"), "http://localhost:3000"),
1613
- placeholder: g(this.getAttribute("placeholder"), "Type a message..."),
1614
- theme: g(this.getAttribute("theme"), "auto"),
1615
- hideBranding: b(this.getAttribute("hide-branding"), !1)
1606
+ apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
1607
+ placeholder: d(this.getAttribute("placeholder"), "Type a message..."),
1608
+ theme: d(this.getAttribute("theme"), "auto"),
1609
+ hideBranding: m(this.getAttribute("hide-branding"), !1)
1616
1610
  };
1617
1611
  }
1618
1612
  initializeClient() {
@@ -1622,14 +1616,14 @@ class U extends HTMLElement {
1622
1616
  return;
1623
1617
  }
1624
1618
  try {
1625
- this.client = y(e.apiUrl);
1619
+ this.client = w(e.apiUrl);
1626
1620
  } catch (t) {
1627
1621
  console.error("ChatPageSnippet:", t);
1628
1622
  }
1629
1623
  }
1630
1624
  render() {
1631
1625
  const e = document.createElement("style");
1632
- e.textContent = `${k}
1626
+ e.textContent = `${x}
1633
1627
  ${$}
1634
1628
  ${this.getPageStyles()}`, this.container = document.createElement("div"), this.container.className = "chat-page-container", this.container.innerHTML = this.getBaseHTML(), this.shadow.innerHTML = "", this.shadow.appendChild(e), this.shadow.appendChild(this.container), this.attachEventListeners();
1635
1629
  }
@@ -1922,7 +1916,7 @@ ${this.getPageStyles()}`, this.container = document.createElement("div"), this.c
1922
1916
  New Chat
1923
1917
  </button>
1924
1918
  <div class="chat-list"></div>
1925
- ${this.getProps().hideBranding ? "" : `<div class="powered-by">${x}</div>`}
1919
+ ${this.getProps().hideBranding ? "" : `<div class="powered-by">${y}</div>`}
1926
1920
  </div>
1927
1921
  <div class="chat-main">
1928
1922
  <div class="chat-page-header">
@@ -2266,15 +2260,13 @@ a.search-result-item {
2266
2260
  height: 64px;
2267
2261
  border-radius: calc(var(--search-snippet-border-radius) - 4px);
2268
2262
  overflow: hidden;
2269
- background: var(--search-snippet-surface);
2270
- border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);
2271
2263
  position: relative;
2272
2264
  }
2273
2265
 
2274
2266
  .search-result-image {
2275
2267
  width: 100%;
2276
2268
  height: 100%;
2277
- object-fit: cover;
2269
+ object-fit: contain;
2278
2270
  opacity: 0;
2279
2271
  transition: opacity var(--search-snippet-transition);
2280
2272
  }
@@ -2387,13 +2379,29 @@ a.search-result-item:focus-visible {
2387
2379
  /* Search footer */
2388
2380
  .search-footer {
2389
2381
  padding: var(--search-snippet-spacing-md);
2390
- border-top: var(--search-snippet-border-width) solid var(--search-snippet-border-color);
2382
+ padding-bottom: var(--search-snippet-spacing-xs);
2391
2383
  display: flex;
2392
2384
  align-items: center;
2393
2385
  justify-content: center;
2394
2386
  gap: var(--search-snippet-spacing-sm);
2395
2387
  }
2396
2388
 
2389
+ /* See more link */
2390
+ .search-see-more {
2391
+ display: inline-flex;
2392
+ align-items: center;
2393
+ gap: var(--search-snippet-spacing-xs);
2394
+ font-size: var(--search-snippet-font-size-sm);
2395
+ color: var(--search-snippet-primary-color);
2396
+ text-decoration: none;
2397
+ font-weight: var(--search-snippet-font-weight-medium);
2398
+ transition: color var(--search-snippet-transition-fast);
2399
+ }
2400
+
2401
+ .search-see-more:hover {
2402
+ text-decoration: underline;
2403
+ }
2404
+
2397
2405
  /* Loading state for search */
2398
2406
  .search-loading {
2399
2407
  display: flex;
@@ -2470,11 +2478,13 @@ class F extends HTMLElement {
2470
2478
  "debounce-ms",
2471
2479
  "theme",
2472
2480
  "hide-branding",
2473
- "show-url"
2481
+ "show-url",
2482
+ "hide-thumbnails",
2483
+ "see-more"
2474
2484
  ];
2475
2485
  }
2476
2486
  connectedCallback() {
2477
- this.initializeClient(), this.render(), this.dispatchEvent(v("ready", void 0));
2487
+ this.initializeClient(), this.render(), this.dispatchEvent(g("ready", void 0));
2478
2488
  }
2479
2489
  disconnectedCallback() {
2480
2490
  this.cleanup();
@@ -2484,13 +2494,15 @@ class F extends HTMLElement {
2484
2494
  }
2485
2495
  getProps() {
2486
2496
  return {
2487
- apiUrl: g(this.getAttribute("api-url"), "http://localhost:3000"),
2488
- placeholder: g(this.getAttribute("placeholder"), "Search..."),
2489
- maxResults: w(this.getAttribute("max-results"), 10),
2490
- debounceMs: w(this.getAttribute("debounce-ms"), 300),
2491
- theme: g(this.getAttribute("theme"), "auto"),
2492
- hideBranding: b(this.getAttribute("hide-branding"), !1),
2493
- showUrl: b(this.getAttribute("show-url"), !1)
2497
+ apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
2498
+ placeholder: d(this.getAttribute("placeholder"), "Search..."),
2499
+ maxResults: f(this.getAttribute("max-results"), 10),
2500
+ debounceMs: f(this.getAttribute("debounce-ms"), 300),
2501
+ theme: d(this.getAttribute("theme"), "auto"),
2502
+ hideBranding: m(this.getAttribute("hide-branding"), !1),
2503
+ showUrl: m(this.getAttribute("show-url"), !1),
2504
+ hideThumbnails: m(this.getAttribute("hide-thumbnails"), !1),
2505
+ seeMore: d(this.getAttribute("see-more"), "")
2494
2506
  };
2495
2507
  }
2496
2508
  initializeClient() {
@@ -2500,7 +2512,7 @@ class F extends HTMLElement {
2500
2512
  return;
2501
2513
  }
2502
2514
  try {
2503
- this.client = y(e.apiUrl);
2515
+ this.client = w(e.apiUrl);
2504
2516
  } catch (t) {
2505
2517
  console.error("SearchBarSnippet:", t);
2506
2518
  }
@@ -2512,7 +2524,7 @@ class F extends HTMLElement {
2512
2524
  e.debounceMs || 400
2513
2525
  );
2514
2526
  const s = document.createElement("style");
2515
- s.textContent = `${k}
2527
+ s.textContent = `${x}
2516
2528
  ${G}`, this.container = document.createElement("div"), this.container.className = "container", this.container.innerHTML = `
2517
2529
  <div class="search-view">
2518
2530
  <div class="search-input-wrapper">
@@ -2521,7 +2533,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2521
2533
  type="text"
2522
2534
  name="search-input"
2523
2535
  class="search-input"
2524
- placeholder="${l(e.placeholder || "Search...")}"
2536
+ placeholder="${h(e.placeholder || "Search...")}"
2525
2537
  aria-label="Search input"
2526
2538
  autocomplete="off"
2527
2539
  />
@@ -2577,7 +2589,12 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2577
2589
  this.showNoResultsState(t);
2578
2590
  return;
2579
2591
  }
2580
- const r = this.getProps().hideBranding ? "" : `<div class="powered-by-inline">${x}</div>`, n = `
2592
+ const s = this.getProps(), r = s.hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = s.seeMore ? `<div class="search-footer">
2593
+ <a href="${h(s.seeMore + encodeURIComponent(t))}" class="search-see-more">
2594
+ <span>See more results</span>
2595
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
2596
+ </a>
2597
+ </div>` : "", c = `
2581
2598
  <div class="search-header">
2582
2599
  <div class="search-count">
2583
2600
  Found ${e.length} result${e.length === 1 ? "" : "s"}
@@ -2585,20 +2602,21 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2585
2602
  ${r}
2586
2603
  </div>
2587
2604
  <div class="search-results">
2588
- ${e.map((c) => this.renderResult(c)).join("")}
2605
+ ${e.map((l) => this.renderResult(l)).join("")}
2589
2606
  </div>
2607
+ ${n}
2590
2608
  `;
2591
- this.resultsContainer.innerHTML = n, this.attachResultHandlers();
2609
+ this.resultsContainer.innerHTML = c, this.attachResultHandlers();
2592
2610
  }
2593
2611
  renderResult(e) {
2594
- const t = this.getProps(), s = this.renderResultImage(e.image, e.title);
2612
+ const t = this.getProps(), s = t.hideThumbnails ? "" : this.renderResultImage(e.image, e.title);
2595
2613
  return `
2596
- <a href="${e.url ? l(e.url) : "#"}" class="search-result-item" data-result-id="${l(e.url || "")}">
2614
+ <a href="${e.url ? h(e.url) : "#"}" class="search-result-item" data-result-id="${h(e.url || "")}">
2597
2615
  ${s}
2598
2616
  <div class="search-result-content">
2599
- <div class="search-result-title">${l(e.title || "")}</div>
2600
- <div class="search-result-snippet">${l(e.description || "")}</div>
2601
- ${t.showUrl && e.url ? `<span class="search-result-url">${l(e.url)}</span>` : ""}
2617
+ <div class="search-result-title">${h(e.title || "")}</div>
2618
+ <div class="search-result-snippet">${h(e.description || "")}</div>
2619
+ ${t.showUrl && e.url ? `<span class="search-result-url">${h(e.url)}</span>` : ""}
2602
2620
  </div>
2603
2621
  </a>
2604
2622
  `;
@@ -2611,8 +2629,8 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2611
2629
  <div class="search-result-image-placeholder" style="display: none;">${s}</div>
2612
2630
  <img
2613
2631
  class="search-result-image"
2614
- src="${l(e)}"
2615
- alt="${l(t)}"
2632
+ src="${h(e)}"
2633
+ alt="${h(t)}"
2616
2634
  loading="lazy"
2617
2635
  />
2618
2636
  </div>
@@ -2643,18 +2661,18 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2643
2661
  });
2644
2662
  }
2645
2663
  showLoadingState() {
2646
- this.resultsContainer && (this.clearLoadingInterval(), this.loadingMessageIndex = Math.floor(Math.random() * u.length), this.resultsContainer.innerHTML = `
2664
+ this.resultsContainer && (this.clearLoadingInterval(), this.loadingMessageIndex = Math.floor(Math.random() * p.length), this.resultsContainer.innerHTML = `
2647
2665
  <div class="search-loading">
2648
2666
  <div class="loading" aria-label="Loading"></div>
2649
- <div class="loading-text loading-text-animate">${u[this.loadingMessageIndex]}</div>
2667
+ <div class="loading-text loading-text-animate">${p[this.loadingMessageIndex]}</div>
2650
2668
  </div>
2651
2669
  `, this.startLoadingInterval());
2652
2670
  }
2653
2671
  startLoadingInterval() {
2654
2672
  this.loadingMessageInterval = setInterval(() => {
2655
- this.loadingMessageIndex = (this.loadingMessageIndex + 1) % u.length;
2673
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % p.length;
2656
2674
  const e = this.resultsContainer?.querySelector(".loading-text");
2657
- e && (e.classList.remove("loading-text-animate"), e.offsetWidth, e.textContent = u[this.loadingMessageIndex], e.classList.add("loading-text-animate"));
2675
+ e && (e.classList.remove("loading-text-animate"), e.offsetWidth, e.textContent = p[this.loadingMessageIndex], e.classList.add("loading-text-animate"));
2658
2676
  }, 2500);
2659
2677
  }
2660
2678
  clearLoadingInterval() {
@@ -2683,7 +2701,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2683
2701
  </svg>
2684
2702
  <div class="search-empty-title">No Results Found</div>
2685
2703
  <div class="search-empty-description">
2686
- No results found for "${l(e)}"
2704
+ No results found for "${h(e)}"
2687
2705
  </div>
2688
2706
  </div>
2689
2707
  `);
@@ -2691,7 +2709,7 @@ ${G}`, this.container = document.createElement("div"), this.container.className
2691
2709
  showErrorState(e) {
2692
2710
  this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
2693
2711
  <div class="error">
2694
- <strong>Error:</strong> ${l(e)}
2712
+ <strong>Error:</strong> ${h(e)}
2695
2713
  </div>
2696
2714
  `);
2697
2715
  }
@@ -2865,15 +2883,13 @@ a.modal-result-item {
2865
2883
  height: 48px;
2866
2884
  border-radius: 6px;
2867
2885
  overflow: hidden;
2868
- background: var(--search-snippet-surface);
2869
- border: var(--search-snippet-border-width) solid var(--search-snippet-border-color);
2870
2886
  position: relative;
2871
2887
  }
2872
2888
 
2873
2889
  .modal-result-image {
2874
2890
  width: 100%;
2875
2891
  height: 100%;
2876
- object-fit: cover;
2892
+ object-fit: contain;
2877
2893
  opacity: 0;
2878
2894
  transition: opacity var(--search-snippet-transition);
2879
2895
  }
@@ -3079,6 +3095,26 @@ a.modal-result-item:focus-visible {
3079
3095
  color: var(--search-snippet-primary-color);
3080
3096
  }
3081
3097
 
3098
+ /* See more link */
3099
+ .modal-see-more {
3100
+ display: flex;
3101
+ align-items: center;
3102
+ justify-content: center;
3103
+ gap: var(--search-snippet-spacing-xs);
3104
+ padding: var(--search-snippet-spacing-md);
3105
+ font-size: var(--search-snippet-font-size-sm);
3106
+ color: var(--search-snippet-primary-color);
3107
+ text-decoration: none;
3108
+ font-weight: var(--search-snippet-font-weight-medium);
3109
+ transition: background var(--search-snippet-transition-fast);
3110
+ padding-bottom: var(--search-snippet-spacing-xs);
3111
+ }
3112
+
3113
+ .modal-see-more:hover {
3114
+ background: var(--search-snippet-hover);
3115
+ text-decoration: underline;
3116
+ }
3117
+
3082
3118
  /* Responsive adjustments */
3083
3119
  @media (max-width: 640px) {
3084
3120
  .modal-container {
@@ -3145,11 +3181,13 @@ class W extends HTMLElement {
3145
3181
  "use-meta-key",
3146
3182
  "debounce-ms",
3147
3183
  "hide-branding",
3148
- "show-url"
3184
+ "show-url",
3185
+ "hide-thumbnails",
3186
+ "see-more"
3149
3187
  ];
3150
3188
  }
3151
3189
  connectedCallback() {
3152
- this.initializeClient(), this.render(), this.attachGlobalKeyboardShortcut(), this.dispatchEvent(v("ready", void 0));
3190
+ this.initializeClient(), this.render(), this.attachGlobalKeyboardShortcut(), this.dispatchEvent(g("ready", void 0));
3153
3191
  }
3154
3192
  disconnectedCallback() {
3155
3193
  this.cleanup();
@@ -3159,15 +3197,17 @@ class W extends HTMLElement {
3159
3197
  }
3160
3198
  getProps() {
3161
3199
  return {
3162
- apiUrl: g(this.getAttribute("api-url"), "http://localhost:3000"),
3163
- placeholder: g(this.getAttribute("placeholder"), "Search..."),
3164
- maxResults: w(this.getAttribute("max-results"), 10),
3165
- debounceMs: w(this.getAttribute("debounce-ms"), 300),
3166
- theme: g(this.getAttribute("theme"), "auto"),
3167
- shortcut: g(this.getAttribute("shortcut"), "k"),
3200
+ apiUrl: d(this.getAttribute("api-url"), "http://localhost:3000"),
3201
+ placeholder: d(this.getAttribute("placeholder"), "Search..."),
3202
+ maxResults: f(this.getAttribute("max-results"), 10),
3203
+ debounceMs: f(this.getAttribute("debounce-ms"), 300),
3204
+ theme: d(this.getAttribute("theme"), "auto"),
3205
+ shortcut: d(this.getAttribute("shortcut"), "k"),
3168
3206
  useMetaKey: this.getAttribute("use-meta-key") !== "false",
3169
- hideBranding: b(this.getAttribute("hide-branding"), !1),
3170
- showUrl: b(this.getAttribute("show-url"), !1)
3207
+ hideBranding: m(this.getAttribute("hide-branding"), !1),
3208
+ showUrl: m(this.getAttribute("show-url"), !1),
3209
+ hideThumbnails: m(this.getAttribute("hide-thumbnails"), !1),
3210
+ seeMore: d(this.getAttribute("see-more"), "")
3171
3211
  };
3172
3212
  }
3173
3213
  initializeClient() {
@@ -3177,7 +3217,7 @@ class W extends HTMLElement {
3177
3217
  return;
3178
3218
  }
3179
3219
  try {
3180
- this.client = y(e.apiUrl);
3220
+ this.client = w(e.apiUrl);
3181
3221
  } catch (t) {
3182
3222
  console.error("SearchModalSnippet:", t);
3183
3223
  }
@@ -3189,9 +3229,9 @@ class W extends HTMLElement {
3189
3229
  e.debounceMs || 300
3190
3230
  );
3191
3231
  const s = document.createElement("style");
3192
- s.textContent = `${k}
3232
+ s.textContent = `${x}
3193
3233
  ${Y}`;
3194
- const r = e.hideBranding ? "" : `<div class="powered-by-inline">${x}</div>`, n = document.createElement("div");
3234
+ const r = e.hideBranding ? "" : `<div class="powered-by-inline">${y}</div>`, n = document.createElement("div");
3195
3235
  n.innerHTML = `
3196
3236
  <div class="modal-backdrop" role="presentation"></div>
3197
3237
  <div class="modal-container" role="dialog" aria-modal="true" aria-labelledby="modal-title">
@@ -3202,7 +3242,7 @@ ${Y}`;
3202
3242
  <input
3203
3243
  type="text"
3204
3244
  class="modal-search-input"
3205
- placeholder="${l(e.placeholder || "Search...")}"
3245
+ placeholder="${h(e.placeholder || "Search...")}"
3206
3246
  aria-label="Search"
3207
3247
  aria-autocomplete="list"
3208
3248
  aria-controls="modal-results-list"
@@ -3285,7 +3325,7 @@ ${Y}`;
3285
3325
  }
3286
3326
  const e = this.results[this.activeIndex];
3287
3327
  this.dispatchEvent(
3288
- v("result-select", {
3328
+ g("result-select", {
3289
3329
  result: e,
3290
3330
  index: this.activeIndex
3291
3331
  })
@@ -3319,27 +3359,30 @@ ${Y}`;
3319
3359
  this.showNoResultsState(t);
3320
3360
  return;
3321
3361
  }
3322
- const s = e.map((r, n) => this.renderResult(r, n)).join("");
3323
- this.resultsContainer.innerHTML = s, this.footerCount && (this.footerCount.textContent = `${e.length} result${e.length === 1 ? "" : "s"}`), this.inputElement && this.inputElement.setAttribute("aria-expanded", "true"), this.attachResultHandlers(), this.updateActiveResult();
3362
+ const s = this.getProps(), r = e.map((c, l) => this.renderResult(c, l)).join(""), n = s.seeMore ? `<a href="${h(s.seeMore + encodeURIComponent(t))}" class="modal-see-more">
3363
+ <span>See more results</span>
3364
+ <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>
3365
+ </a>` : "";
3366
+ this.resultsContainer.innerHTML = r + n, this.footerCount && (this.footerCount.textContent = `${e.length} result${e.length === 1 ? "" : "s"}`), this.inputElement && this.inputElement.setAttribute("aria-expanded", "true"), this.attachResultHandlers(), this.updateActiveResult();
3324
3367
  }
3325
3368
  renderResult(e, t) {
3326
- const s = this.getProps(), r = this.renderResultImage(e.image, e.title);
3369
+ const s = this.getProps(), r = s.hideThumbnails ? "" : this.renderResultImage(e.image, e.title);
3327
3370
  return `
3328
3371
  <a
3329
- href="${e.url ? l(e.url) : "#"}"
3372
+ href="${e.url ? h(e.url) : "#"}"
3330
3373
  class="modal-result-item${t === this.activeIndex ? " active" : ""}"
3331
3374
  role="option"
3332
3375
  id="result-${t}"
3333
3376
  aria-selected="${t === this.activeIndex}"
3334
3377
  tabindex="-1"
3335
3378
  data-index="${t}"
3336
- data-url="${l(e.url || "")}"
3379
+ data-url="${h(e.url || "")}"
3337
3380
  >
3338
3381
  ${r}
3339
3382
  <div class="modal-result-content">
3340
- <div class="modal-result-title">${l(e.title || "")}</div>
3341
- ${e.description ? `<div class="modal-result-description">${l(e.description)}</div>` : ""}
3342
- ${s.showUrl && e.url ? `<span class="modal-result-url">${l(e.url)}</span>` : ""}
3383
+ <div class="modal-result-title">${h(e.title || "")}</div>
3384
+ ${e.description ? `<div class="modal-result-description">${h(e.description)}</div>` : ""}
3385
+ ${s.showUrl && e.url ? `<span class="modal-result-url">${h(e.url)}</span>` : ""}
3343
3386
  </div>
3344
3387
  </a>
3345
3388
  `;
@@ -3352,8 +3395,8 @@ ${Y}`;
3352
3395
  <div class="modal-result-image-placeholder" style="display: none;">${s}</div>
3353
3396
  <img
3354
3397
  class="modal-result-image"
3355
- src="${l(e)}"
3356
- alt="${l(t)}"
3398
+ src="${h(e)}"
3399
+ alt="${h(t)}"
3357
3400
  loading="lazy"
3358
3401
  />
3359
3402
  </div>
@@ -3400,18 +3443,18 @@ ${Y}`;
3400
3443
  this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = this.renderEmptyState(), this.footerCount && (this.footerCount.textContent = ""), this.inputElement && this.inputElement.setAttribute("aria-expanded", "false"));
3401
3444
  }
3402
3445
  showLoadingState() {
3403
- this.resultsContainer && (this.clearLoadingInterval(), this.loadingMessageIndex = Math.floor(Math.random() * u.length), this.resultsContainer.innerHTML = `
3446
+ this.resultsContainer && (this.clearLoadingInterval(), this.loadingMessageIndex = Math.floor(Math.random() * p.length), this.resultsContainer.innerHTML = `
3404
3447
  <div class="modal-loading">
3405
3448
  <div class="loading" aria-label="Loading"></div>
3406
- <div class="loading-text loading-text-animate">${u[this.loadingMessageIndex]}</div>
3449
+ <div class="loading-text loading-text-animate">${p[this.loadingMessageIndex]}</div>
3407
3450
  </div>
3408
- `, this.footerCount && (this.footerCount.textContent = u[this.loadingMessageIndex]), this.startLoadingInterval());
3451
+ `, this.footerCount && (this.footerCount.textContent = p[this.loadingMessageIndex]), this.startLoadingInterval());
3409
3452
  }
3410
3453
  startLoadingInterval() {
3411
3454
  this.loadingMessageInterval = setInterval(() => {
3412
- this.loadingMessageIndex = (this.loadingMessageIndex + 1) % u.length;
3455
+ this.loadingMessageIndex = (this.loadingMessageIndex + 1) % p.length;
3413
3456
  const e = this.resultsContainer?.querySelector(".loading-text");
3414
- e && (e.classList.remove("loading-text-animate"), e.offsetWidth, e.textContent = u[this.loadingMessageIndex], e.classList.add("loading-text-animate")), this.footerCount && (this.footerCount.textContent = u[this.loadingMessageIndex]);
3457
+ e && (e.classList.remove("loading-text-animate"), e.offsetWidth, e.textContent = p[this.loadingMessageIndex], e.classList.add("loading-text-animate")), this.footerCount && (this.footerCount.textContent = p[this.loadingMessageIndex]);
3415
3458
  }, 2500);
3416
3459
  }
3417
3460
  clearLoadingInterval() {
@@ -3425,14 +3468,14 @@ ${Y}`;
3425
3468
  <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
3426
3469
  </svg>
3427
3470
  <div class="modal-empty-title">No results found</div>
3428
- <div class="modal-empty-description">No results for "${l(e)}"</div>
3471
+ <div class="modal-empty-description">No results for "${h(e)}"</div>
3429
3472
  </div>
3430
3473
  `, this.footerCount && (this.footerCount.textContent = "0 results"), this.inputElement && this.inputElement.setAttribute("aria-expanded", "false"));
3431
3474
  }
3432
3475
  showErrorState(e) {
3433
3476
  this.clearLoadingInterval(), this.resultsContainer && (this.resultsContainer.innerHTML = `
3434
3477
  <div class="error">
3435
- <strong>Error:</strong> ${l(e)}
3478
+ <strong>Error:</strong> ${h(e)}
3436
3479
  </div>
3437
3480
  `, this.footerCount && (this.footerCount.textContent = "Error"));
3438
3481
  }
@@ -3466,13 +3509,13 @@ ${Y}`;
3466
3509
  requestAnimationFrame(() => {
3467
3510
  this.inputElement?.focus();
3468
3511
  });
3469
- }), this.lockBodyScroll(), this.dispatchEvent(v("open", void 0)));
3512
+ }), this.lockBodyScroll(), this.dispatchEvent(g("open", void 0)));
3470
3513
  }
3471
3514
  /**
3472
3515
  * Close the search modal
3473
3516
  */
3474
3517
  close() {
3475
- this.isOpen && (this.isOpen = !1, this.backdrop?.classList.remove("open"), this.modal?.classList.remove("open"), this.inputElement && (this.inputElement.value = ""), this.results = [], this.activeIndex = -1, this.showEmptyState(), this.unlockBodyScroll(), this.dispatchEvent(v("close", void 0)));
3518
+ this.isOpen && (this.isOpen = !1, this.backdrop?.classList.remove("open"), this.modal?.classList.remove("open"), this.inputElement && (this.inputElement.value = ""), this.results = [], this.activeIndex = -1, this.showEmptyState(), this.unlockBodyScroll(), this.dispatchEvent(g("close", void 0)));
3476
3519
  }
3477
3520
  /**
3478
3521
  * Toggle the search modal open/closed