@sevenfold/setto-client 0.30.1 → 0.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -12,6 +12,7 @@ export { SettoIcon } from './SettoIcon';
12
12
  export type { SettoIconProps, SettoIconRenderProps } from './SettoIcon';
13
13
  export { SettoImage } from './SettoImage';
14
14
  export type { SettoImageProps, ImageToolsProps } from './SettoImage';
15
+ export { SETTO_IMAGE_QUALITY, SETTO_IMAGE_WIDTHS, isOptimizable, optimizedSrcSet, optimizedUrl, settoVercelImagesConfig, } from './lib/optimized-image';
15
16
  export { SettoRepeater } from './SettoRepeater';
16
17
  export type { SettoRepeaterProps } from './SettoRepeater';
17
18
  export { SettoForm, FORM_FIELD_TYPES, FORM_FIELD_TYPE_LABELS, fieldTypeHasOptions, fieldTypeHasPlaceholder, formFieldsPrefix, isFormFieldType, readLocaleFields, settoSubmissionUrl, } from './modules/forms';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Images through Vercel's Image Optimization, for sites that turned it on.
3
+ *
4
+ * A site keeps one original per image in its repository; the CDN makes each
5
+ * width on first request, in AVIF or WebP as the browser accepts, and caches
6
+ * it by the file's content. A site turns it on with two things that must
7
+ * agree: `"images": { "optimize": true }` in `setto.config.json`, and an
8
+ * `images` block in `vercel.json` whose `sizes` and `qualities` are exactly
9
+ * the constants below — Vercel refuses a `w` or `q` it was not given. The
10
+ * block, for copying: `settoVercelImagesConfig`.
11
+ */
12
+ /** Phone, phone at 2–3×, tablet, laptop, wide and retina desktop. */
13
+ export declare const SETTO_IMAGE_WIDTHS: readonly [384, 640, 828, 1080, 1440, 1920, 2560];
14
+ /** One quality for every image, so each width is one cached variant rather than several. */
15
+ export declare const SETTO_IMAGE_QUALITY = 75;
16
+ /** The `images` block of `vercel.json` that matches `SettoImage`. */
17
+ export declare const settoVercelImagesConfig: {
18
+ readonly sizes: readonly [384, 640, 828, 1080, 1440, 1920, 2560];
19
+ readonly qualities: readonly [75];
20
+ readonly formats: readonly ["image/avif", "image/webp"];
21
+ readonly localPatterns: readonly [{
22
+ readonly pathname: "^/images/.*$";
23
+ readonly search: "";
24
+ }];
25
+ readonly minimumCacheTTL: 2678400;
26
+ };
27
+ /**
28
+ * Whether an image can go through the optimizer: a file of this site's own,
29
+ * under `/images/`, in a format it transforms. A draft's `blob:` preview, an
30
+ * external address, an SVG logo and a moving GIF cannot.
31
+ */
32
+ export declare function isOptimizable(src: string | null | undefined): src is string;
33
+ /**
34
+ * Where there is no optimizer to ask: the Vite dev server and a local
35
+ * preview. A deployment elsewhere without one (a build sandbox) is caught by
36
+ * the image's own error instead.
37
+ */
38
+ export declare function hasNoOptimizer(hostname: string): boolean;
39
+ export declare function optimizedUrl(src: string, width: number): string;
40
+ export declare function optimizedSrcSet(src: string): string;
@@ -35150,8 +35150,8 @@ function createWordRevealer(onReveal) {
35150
35150
  function norwegian(locale) {
35151
35151
  return locale.toLowerCase().startsWith("no");
35152
35152
  }
35153
- function intro(locale, name2) {
35154
- return norwegian(locale) ? `Hei! Jeg er Barista, ${name2 ? `${name2}s` : "nettstedets"} AI-assistent. Jeg svarer ut fra det teamet har delt her, og hjelper deg videre til dem når det trengs.` : `Hello! I’m Barista, the AI assistant for ${name2 ?? "this website"}. I answer from what the team has shared here and help you reach them when needed.`;
35153
+ function intro(locale, name2, agent = "Barista") {
35154
+ return norwegian(locale) ? `Hei! Jeg er ${agent}, ${name2 ? `${name2}s` : "nettstedets"} AI-assistent. Jeg svarer ut fra det teamet har delt her, og hjelper deg videre til dem når det trengs.` : `Hello! I’m ${agent}, the AI assistant for ${name2 ?? "this website"}. I answer from what the team has shared here and help you reach them when needed.`;
35155
35155
  }
35156
35156
  function validColor(value, fallback) {
35157
35157
  return value && (/^#[0-9a-f]{3,8}$/i.test(value) || /^rgba?\(/i.test(value)) ? value : fallback;
@@ -35224,6 +35224,11 @@ function BaristaIcon() {
35224
35224
  }
35225
35225
  ) });
35226
35226
  }
35227
+ function AgentAvatar({ url }) {
35228
+ const [failed, setFailed] = useState(false);
35229
+ useEffect(() => setFailed(false), [url]);
35230
+ return url && !failed ? /* @__PURE__ */ jsx("img", { src: url, alt: "", onError: () => setFailed(true) }) : /* @__PURE__ */ jsx(BaristaIcon, {});
35231
+ }
35227
35232
  function PersonIcon() {
35228
35233
  return /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", width: "20", height: "20", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
35229
35234
  "path",
@@ -35828,14 +35833,17 @@ function SettoChat() {
35828
35833
  const locale = i18n.language || "no";
35829
35834
  const isNo = norwegian(locale);
35830
35835
  const siteName = settings?.displayName?.trim() || config.displayName?.trim() || null;
35836
+ const agentName = settings?.agentName?.trim() || "Barista";
35837
+ const agentAvatarUrl = settings?.agentAvatarUrl ?? null;
35831
35838
  const labels = isNo ? {
35832
35839
  open: siteName ? `Åpne chat med ${siteName}` : "Åpne chat",
35833
35840
  close: "Lukk chatten",
35834
- title: "Spør Barista",
35841
+ title: `Spør ${agentName}`,
35842
+ ai: "AI-assistent",
35835
35843
  chats: "Chats",
35836
35844
  newChat: "Ny chat",
35837
35845
  placeholder: "Hva vil du spørre om?",
35838
- humanPlaceholder: "Skriv til teamet · bruk @barista for AI",
35846
+ humanPlaceholder: `Skriv til teamet · bruk @barista for ${agentName}`,
35839
35847
  send: "Send melding",
35840
35848
  sending: "Svarer …",
35841
35849
  attach: "Legg ved bilde",
@@ -35848,11 +35856,12 @@ function SettoChat() {
35848
35856
  } : {
35849
35857
  open: siteName ? `Open chat with ${siteName}` : "Open chat",
35850
35858
  close: "Close chat",
35851
- title: "Ask Barista",
35859
+ title: `Ask ${agentName}`,
35860
+ ai: "AI assistant",
35852
35861
  chats: "Chats",
35853
35862
  newChat: "New chat",
35854
35863
  placeholder: "What would you like to ask?",
35855
- humanPlaceholder: "Message the team · use @barista for AI",
35864
+ humanPlaceholder: `Message the team · use @barista for ${agentName}`,
35856
35865
  send: "Send message",
35857
35866
  sending: "Replying …",
35858
35867
  attach: "Attach image",
@@ -36009,7 +36018,7 @@ function SettoChat() {
36009
36018
  }, [apiUrl, config.siteId, settings]);
36010
36019
  useEffect(() => {
36011
36020
  if (!mounted || !settings || conversationId.current) return;
36012
- const welcome = intro(locale, settings.displayName ?? void 0);
36021
+ const welcome = intro(locale, settings.displayName ?? void 0, settings.agentName?.trim() || void 0);
36013
36022
  setMessages((current) => {
36014
36023
  if (current.length === 0) return [{ role: "assistant", content: welcome }];
36015
36024
  if (current.length === 1 && current[0]?.role === "assistant" && !current[0].id) {
@@ -36154,7 +36163,7 @@ function SettoChat() {
36154
36163
  setRealtime(null);
36155
36164
  setTeamTypingUntil(null);
36156
36165
  setHumanJoined(false);
36157
- setMessages([{ role: "assistant", content: intro(locale, settings?.displayName ?? void 0) }]);
36166
+ setMessages([{ role: "assistant", content: intro(locale, settings?.displayName ?? void 0, agentName) }]);
36158
36167
  setDraft("");
36159
36168
  setQueued(false);
36160
36169
  setDrawer(false);
@@ -36358,7 +36367,7 @@ function SettoChat() {
36358
36367
  ),
36359
36368
  /* @__PURE__ */ jsxs("div", { className: "setto-chat__brand", children: [
36360
36369
  /* @__PURE__ */ jsx("h2", { id: `${formId}-title`, children: labels.title }),
36361
- /* @__PURE__ */ jsx("p", { children: siteName ?? "Barista" })
36370
+ /* @__PURE__ */ jsx("p", { children: siteName ? `${labels.ai} · ${siteName}` : labels.ai })
36362
36371
  ] }),
36363
36372
  /* @__PURE__ */ jsx(
36364
36373
  "button",
@@ -36391,11 +36400,11 @@ function SettoChat() {
36391
36400
  {
36392
36401
  className: `setto-chat__avatar setto-chat__avatar--${item.role}`,
36393
36402
  "aria-hidden": "true",
36394
- children: item.role === "human" && item.avatarUrl ? /* @__PURE__ */ jsx("img", { src: item.avatarUrl, alt: "" }) : item.role === "human" ? /* @__PURE__ */ jsx(PersonIcon, {}) : /* @__PURE__ */ jsx(BaristaIcon, {})
36403
+ children: item.role === "human" && item.avatarUrl ? /* @__PURE__ */ jsx("img", { src: item.avatarUrl, alt: "" }) : item.role === "human" ? /* @__PURE__ */ jsx(PersonIcon, {}) : /* @__PURE__ */ jsx(AgentAvatar, { url: agentAvatarUrl })
36395
36404
  }
36396
36405
  ) : null,
36397
36406
  /* @__PURE__ */ jsxs("div", { className: "setto-chat__message-stack", children: [
36398
- item.role === "assistant" || item.role === "human" ? /* @__PURE__ */ jsx("span", { className: "setto-chat__speaker", children: item.role === "human" ? item.authorName || labels.team : "Barista" }) : null,
36407
+ item.role === "assistant" || item.role === "human" ? /* @__PURE__ */ jsx("span", { className: "setto-chat__speaker", children: item.role === "human" ? item.authorName || labels.team : `${agentName} · ${labels.ai}` }) : null,
36399
36408
  /* @__PURE__ */ jsxs("div", { className: "setto-chat__message-bubble", children: [
36400
36409
  /* @__PURE__ */ jsx("div", { className: "setto-chat__message-copy", children: item.content ? item.role === "assistant" ? /* @__PURE__ */ jsx(SiteChatMarkdown, { content: item.content, reveal: item.reveal }) : item.content : /* @__PURE__ */ jsx("span", { className: "setto-chat__typing", children: "···" }) }),
36401
36410
  item.attachments?.map((attachment) => /* @__PURE__ */ jsx(
@@ -36465,7 +36474,7 @@ function SettoChat() {
36465
36474
  onClick: show,
36466
36475
  "aria-label": labels.open,
36467
36476
  title: labels.open,
36468
- children: availability.humanAvailable && availability.avatarUrl ? /* @__PURE__ */ jsx("img", { src: availability.avatarUrl, alt: "" }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx(BaristaIcon, {}) })
36477
+ children: availability.humanAvailable && availability.avatarUrl ? /* @__PURE__ */ jsx("img", { src: availability.avatarUrl, alt: "" }) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: /* @__PURE__ */ jsx(AgentAvatar, { url: agentAvatarUrl }) })
36469
36478
  }
36470
36479
  ) : null
36471
36480
  ]
@@ -36506,7 +36515,7 @@ function useChatStyles() {
36506
36515
  .setto-chat__message--agent-joined{justify-content:flex-start;align-items:center;gap:.55rem;padding:.1rem .4rem;color:color-mix(in srgb,var(--setto-chat-ink) 62%,transparent);font-size:.8rem;line-height:1.4;text-align:left}.setto-chat__message--agent-joined .setto-chat__message-stack{max-width:calc(100% - 38px);align-items:flex-start}.setto-chat__message--agent-joined .setto-chat__message-bubble{min-width:0;padding:.2rem 0;background:transparent;white-space:normal}.setto-chat__avatar--joined{flex-basis:30px;width:30px;height:30px;margin:0;border-width:1px;box-shadow:0 2px 7px color-mix(in srgb,var(--setto-chat-ink) 12%,transparent)}
36507
36516
  .setto-chat__receipt{display:block;margin:.26rem .45rem 0 0;color:color-mix(in srgb,var(--setto-chat-ink) 52%,transparent);font-size:.69rem;font-weight:500;line-height:1.2}.setto-chat__message--typing{animation:setto-chat-typing-in 180ms cubic-bezier(.2,.8,.2,1) both}.setto-chat__message--typing .setto-chat__message-bubble{min-width:3.25rem;text-align:center}.setto-chat__message--typing .setto-chat__typing{font-weight:700;letter-spacing:.06em}@keyframes setto-chat-typing-in{from{opacity:0;transform:translateY(4px)}}@media(prefers-reduced-motion:reduce){.setto-chat__message--typing{animation:none}}
36508
36517
  .setto-chat__composer-shell{position:absolute;left:0;right:0;bottom:0;z-index:25;display:grid;grid-template-columns:minmax(0,1fr);padding:1.5rem .75rem 0;background:transparent;isolation:isolate}.setto-chat__composer-shell::before{content:"";position:absolute;inset:0;pointer-events:none;background:linear-gradient(to bottom,transparent 0%,color-mix(in srgb,var(--setto-chat-canvas) 82%,transparent) 46%,var(--setto-chat-canvas) 66%);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);-webkit-mask-image:linear-gradient(to bottom,rgba(0,0,0,0) 0%,rgba(0,0,0,.4) 34%,rgba(0,0,0,1) 66%);mask-image:linear-gradient(to bottom,rgba(0,0,0,0) 0%,rgba(0,0,0,.4) 34%,rgba(0,0,0,1) 66%)}.setto-chat__composer{position:relative;z-index:1;display:flex;flex-direction:column;gap:.15rem;width:100%;min-width:0;margin:0;padding:.35rem .4rem;border:2px solid color-mix(in srgb,var(--setto-chat-ink) 10%,transparent);border-radius:24px;background:var(--setto-chat-canvas);box-shadow:0 8px 24px -16px color-mix(in srgb,var(--setto-chat-ink) 28%,transparent);transition:padding 220ms cubic-bezier(.16,1,.3,1),border-color 200ms ease,box-shadow 360ms cubic-bezier(.16,1,.3,1)}.setto-chat__composer.is-open{padding:.55rem .5rem}.setto-chat__composer:focus-within{border-color:var(--setto-chat-accent)}.setto-chat__composer textarea,.setto-chat__composer textarea:hover,.setto-chat__composer textarea:focus,.setto-chat__composer textarea:focus-visible{width:100%;min-height:36px;max-height:${MAX_COMPOSER_HEIGHT}px;overflow-y:auto;padding:.45rem .25rem;resize:none;-webkit-appearance:none!important;appearance:none!important;border:0!important;border-radius:0!important;outline:0!important;box-shadow:none!important;background:transparent!important;color:var(--setto-chat-ink);font-family:"Archivo Variable",Archivo,system-ui,sans-serif;font-size:16px;line-height:1.35;transition:min-height 220ms cubic-bezier(.16,1,.3,1)}.setto-chat__composer.is-open textarea{min-height:40px}.setto-chat__composer textarea::placeholder{color:color-mix(in srgb,var(--setto-chat-ink) 52%,transparent)}.setto-chat__composer textarea::-webkit-scrollbar{width:6px}.setto-chat__composer textarea::-webkit-scrollbar-track{background:transparent}.setto-chat__composer textarea::-webkit-scrollbar-thumb{border-radius:999px;background:color-mix(in srgb,var(--setto-chat-ink) 24%,transparent)}.setto-chat__composer textarea::-webkit-scrollbar-button{display:none;height:0}@supports not selector(::-webkit-scrollbar){.setto-chat__composer textarea{scrollbar-width:thin;scrollbar-color:color-mix(in srgb,var(--setto-chat-ink) 24%,transparent) transparent}}.setto-chat__composer-tools{display:flex;align-items:center;gap:.4rem;width:100%;min-width:0}.setto-chat__attach{flex:none;width:34px;height:34px;padding:0;border:0;border-radius:50%;background:transparent;color:color-mix(in srgb,var(--setto-chat-ink) 58%,transparent);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:background 160ms ease,color 160ms ease}.setto-chat__attach:hover:not(:disabled){background:color-mix(in srgb,var(--setto-chat-ink) 6%,transparent);color:var(--setto-chat-ink)}.setto-chat__attach:disabled{opacity:.4;cursor:default}.setto-chat__send{flex:none;width:36px;height:36px;margin-left:auto;padding:0;border:0;border-radius:50%;background:var(--setto-chat-accent);color:var(--setto-chat-raised);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:transform 360ms cubic-bezier(.16,1,.3,1),box-shadow 360ms cubic-bezier(.16,1,.3,1),background 200ms ease,opacity 200ms ease}.setto-chat__send:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 12px 24px -12px color-mix(in srgb,var(--setto-chat-ink) 45%,transparent)}.setto-chat__send:active:not(:disabled){transform:translateY(0);box-shadow:0 4px 10px -8px color-mix(in srgb,var(--setto-chat-ink) 40%,transparent);transition-duration:90ms}.setto-chat__send:disabled{opacity:.35;cursor:default}.setto-chat__send.is-queued{animation:setto-chat-queued 1.1s ease-in-out infinite}.setto-chat__attachments{display:flex;flex-wrap:wrap;gap:.4rem;list-style:none;margin:0;padding:.15rem .15rem 0}.setto-chat__attachments li{position:relative;width:56px;height:56px;border-radius:10px;overflow:hidden;border:1px solid color-mix(in srgb,var(--setto-chat-ink) 12%,transparent);background:var(--setto-chat-crema)}.setto-chat__attachments img{display:block;width:100%;height:100%;object-fit:cover}.setto-chat__attachments button{position:absolute;top:2px;right:2px;width:18px;height:18px;padding:0;border:0;border-radius:50%;background:color-mix(in srgb,var(--setto-chat-ink) 72%,transparent);color:#fff;display:inline-flex;align-items:center;justify-content:center;cursor:pointer}.setto-chat__composer-floor{position:relative;z-index:1;width:calc(100% + 1.5rem);height:max(.35rem,env(safe-area-inset-bottom));margin-left:-.75rem;background:var(--setto-chat-canvas)}
36509
- .setto-chat__launcher{width:58px;height:58px;padding:3px;border:1px solid rgba(255,255,255,.54);border-radius:50%;background:color-mix(in srgb,var(--setto-chat-raised) 35%,transparent);box-shadow:0 10px 30px color-mix(in srgb,var(--setto-chat-ink) 24%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--setto-chat-ink) 9%,transparent);backdrop-filter:blur(14px) saturate(115%);-webkit-backdrop-filter:blur(14px) saturate(115%);color:var(--setto-chat-ink);display:grid;place-items:center;cursor:pointer;transition:transform 180ms ease,box-shadow 180ms ease}.setto-chat__launcher:hover{transform:translateY(-2px);box-shadow:0 15px 35px color-mix(in srgb,var(--setto-chat-ink) 28%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--setto-chat-ink) 9%,transparent)}.setto-chat__launcher span{width:46px;height:46px;border-radius:50%;display:grid;place-items:center;background:var(--setto-chat-accent);color:var(--setto-chat-raised)}.setto-chat__launcher img{display:block;width:50px;height:50px;border-radius:50%;object-fit:cover}.setto-chat__launcher:focus-visible,.setto-chat button:focus-visible,.setto-chat input:focus-visible{outline:2px solid var(--setto-chat-accent);outline-offset:2px}@keyframes setto-chat-pulse{50%{opacity:.35}}@keyframes setto-chat-queued{50%{opacity:.55}}
36518
+ .setto-chat__launcher{width:58px;height:58px;padding:3px;border:1px solid rgba(255,255,255,.54);border-radius:50%;background:color-mix(in srgb,var(--setto-chat-raised) 35%,transparent);box-shadow:0 10px 30px color-mix(in srgb,var(--setto-chat-ink) 24%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--setto-chat-ink) 9%,transparent);backdrop-filter:blur(14px) saturate(115%);-webkit-backdrop-filter:blur(14px) saturate(115%);color:var(--setto-chat-ink);display:grid;place-items:center;cursor:pointer;transition:transform 180ms ease,box-shadow 180ms ease}.setto-chat__launcher:hover{transform:translateY(-2px);box-shadow:0 15px 35px color-mix(in srgb,var(--setto-chat-ink) 28%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--setto-chat-ink) 9%,transparent)}.setto-chat__launcher span{width:46px;height:46px;border-radius:50%;display:grid;place-items:center;background:var(--setto-chat-accent);color:var(--setto-chat-raised)}.setto-chat__launcher img{display:block;width:50px;height:50px;border-radius:50%;object-fit:cover}.setto-chat__launcher span{overflow:hidden}.setto-chat__launcher span img{width:100%;height:100%}.setto-chat__launcher:focus-visible,.setto-chat button:focus-visible,.setto-chat input:focus-visible{outline:2px solid var(--setto-chat-accent);outline-offset:2px}@keyframes setto-chat-pulse{50%{opacity:.35}}@keyframes setto-chat-queued{50%{opacity:.55}}
36510
36519
  @media(max-width:700px){.setto-chat__chats{position:absolute;inset:0 auto 0 0;transform:translateX(-100%);transition:transform 260ms cubic-bezier(.16,1,.3,1);box-shadow:14px 0 35px color-mix(in srgb,var(--setto-chat-ink) 16%,transparent)}.setto-chat__chats--open{transform:none}.setto-chat__main{width:100%;max-width:none;margin:0}.setto-chat__log{padding-left:.75rem;padding-right:.75rem}}@media(min-width:701px){.setto-chat--mounted{top:auto;right:max(18px,env(safe-area-inset-right));bottom:max(18px,env(safe-area-inset-bottom));left:auto;width:min(440px,calc(100vw - 36px));height:min(720px,calc(100dvh - 36px));overflow:visible;background:transparent}.setto-chat__shell{position:relative;top:auto;left:auto;width:100%;height:100%;border:1px solid color-mix(in srgb,var(--setto-chat-ink) 14%,transparent);border-radius:26px;background:var(--setto-chat-canvas);box-shadow:0 28px 80px -24px color-mix(in srgb,var(--setto-chat-ink) 42%,transparent),0 8px 24px -12px color-mix(in srgb,var(--setto-chat-ink) 24%,transparent);transform:translateY(16px) scale(.975);transform-origin:right bottom}.setto-chat--visible .setto-chat__shell{transform:none}.setto-chat__chats{position:absolute;inset:0 auto 0 0;width:min(82%,280px);height:100%;transform:translateX(-100%);transition:transform 260ms cubic-bezier(.16,1,.3,1);box-shadow:14px 0 35px color-mix(in srgb,var(--setto-chat-ink) 16%,transparent)}.setto-chat__chats--open{transform:none}.setto-chat__main{width:100%;max-width:none;margin:0}.setto-chat__header,.setto-chat__log{padding-left:.9rem;padding-right:.9rem}.setto-chat__composer-shell{padding-left:.9rem;padding-right:.9rem}.setto-chat__composer-floor{width:calc(100% + 1.8rem);height:.45rem;margin-left:-.9rem}.setto-chat__message{font-size:15.5px}.setto-chat__message-stack{max-width:82%}}@media(prefers-reduced-motion:reduce){.setto-chat,.setto-chat__shell,.setto-chat__chats,.setto-chat__launcher,.setto-chat__composer,.setto-chat__composer textarea,.setto-chat__send{transition:none!important}.setto-chat__typing,.setto-chat__send.is-queued{animation:none}}
36511
36520
  `;
36512
36521
  style.textContent += "@media(prefers-reduced-motion:reduce){.setto-chat__markdown.is-revealing .setto-chat__word{opacity:1;transform:none;filter:none;animation:none}}";
@@ -37496,6 +37505,29 @@ function SettoIcon({ k, icons, size = 24, className, style }) {
37496
37505
  )
37497
37506
  ] });
37498
37507
  }
37508
+ const SETTO_IMAGE_WIDTHS = [384, 640, 828, 1080, 1440, 1920, 2560];
37509
+ const SETTO_IMAGE_QUALITY = 75;
37510
+ const settoVercelImagesConfig = {
37511
+ sizes: [...SETTO_IMAGE_WIDTHS],
37512
+ qualities: [SETTO_IMAGE_QUALITY],
37513
+ formats: ["image/avif", "image/webp"],
37514
+ localPatterns: [{ pathname: "^/images/.*$", search: "" }],
37515
+ minimumCacheTTL: 2678400
37516
+ };
37517
+ const OPTIMIZABLE = /\.(jpe?g|png|webp|avif)$/i;
37518
+ function isOptimizable(src) {
37519
+ if (!src || !src.startsWith("/images/")) return false;
37520
+ return OPTIMIZABLE.test(src.split(/[?#]/)[0]);
37521
+ }
37522
+ function hasNoOptimizer(hostname) {
37523
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname.endsWith(".localhost");
37524
+ }
37525
+ function optimizedUrl(src, width) {
37526
+ return `/_vercel/image?url=${encodeURIComponent(src)}&w=${width}&q=${SETTO_IMAGE_QUALITY}`;
37527
+ }
37528
+ function optimizedSrcSet(src) {
37529
+ return SETTO_IMAGE_WIDTHS.map((w) => `${optimizedUrl(src, w)} ${w}w`).join(", ");
37530
+ }
37499
37531
  const ACCEPT = "image/png,image/jpeg,image/webp,image/svg+xml";
37500
37532
  function setSrcAllLanguages(store, i18n, srcKey, value) {
37501
37533
  const langs = i18n.languages?.length ? i18n.languages : [i18n.language];
@@ -37503,9 +37535,34 @@ function setSrcAllLanguages(store, i18n, srcKey, value) {
37503
37535
  store.set(srcKey, lng, value);
37504
37536
  }
37505
37537
  }
37538
+ function PublishedImage({
37539
+ src,
37540
+ optimize,
37541
+ sizes,
37542
+ srcSet,
37543
+ onError,
37544
+ ...rest
37545
+ }) {
37546
+ const [direct, setDirect] = useState(false);
37547
+ const optimized = optimize && !direct && !srcSet && isOptimizable(src) && !(typeof window !== "undefined" && hasNoOptimizer(window.location.hostname));
37548
+ if (!optimized) return /* @__PURE__ */ jsx("img", { src, srcSet, sizes, onError, ...rest });
37549
+ return /* @__PURE__ */ jsx(
37550
+ "img",
37551
+ {
37552
+ src: optimizedUrl(src, 1080),
37553
+ srcSet: optimizedSrcSet(src),
37554
+ sizes: sizes ?? "100vw",
37555
+ onError: (e) => {
37556
+ setDirect(true);
37557
+ onError?.(e);
37558
+ },
37559
+ ...rest
37560
+ }
37561
+ );
37562
+ }
37506
37563
  function SettoImage({ srcKey, alt, className, style, ...rest }) {
37507
37564
  const { t, i18n } = useTranslation();
37508
- const { editMode, store, assetStore } = useSetto();
37565
+ const { editMode, store, assetStore, config } = useSetto();
37509
37566
  const fileRef = useRef(null);
37510
37567
  const [hovered, setHovered] = useState(false);
37511
37568
  const [uploading, setUploading] = useState(false);
@@ -37525,7 +37582,17 @@ function SettoImage({ srcKey, alt, className, style, ...rest }) {
37525
37582
  const previewUrl = assetStore?.getPreviewUrl(srcKey);
37526
37583
  const src = previewUrl ?? srcPath;
37527
37584
  if (!editMode) {
37528
- return /* @__PURE__ */ jsx("img", { src: srcPath, alt, className, style, ...rest });
37585
+ return /* @__PURE__ */ jsx(
37586
+ PublishedImage,
37587
+ {
37588
+ src: srcPath,
37589
+ optimize: config.images?.optimize === true,
37590
+ alt,
37591
+ className,
37592
+ style,
37593
+ ...rest
37594
+ }
37595
+ );
37529
37596
  }
37530
37597
  const isFullWidth = className?.includes("w-full");
37531
37598
  const isFullHeight = className?.includes("h-full");
@@ -40002,6 +40069,8 @@ export {
40002
40069
  PAGES_PATH,
40003
40070
  PageStore,
40004
40071
  SETTO_BASE,
40072
+ SETTO_IMAGE_QUALITY,
40073
+ SETTO_IMAGE_WIDTHS,
40005
40074
  SETTO_MODULES,
40006
40075
  SettoAdminApp,
40007
40076
  SettoAnimation,
@@ -40042,11 +40111,14 @@ export {
40042
40111
  isAdminRoute,
40043
40112
  isFormFieldType,
40044
40113
  isLinkContext,
40114
+ isOptimizable,
40045
40115
  isSafeHref,
40046
40116
  languageFromPath,
40047
40117
  languageName,
40048
40118
  nodeChildren,
40049
40119
  normalisePath,
40120
+ optimizedSrcSet,
40121
+ optimizedUrl,
40050
40122
  pageById,
40051
40123
  pageForPath,
40052
40124
  pageTitleKey,
@@ -40058,6 +40130,7 @@ export {
40058
40130
  redirectForVisitor,
40059
40131
  serialiseManifest,
40060
40132
  settoSubmissionUrl,
40133
+ settoVercelImagesConfig,
40061
40134
  siteHomeUrl,
40062
40135
  siteLanguages,
40063
40136
  useCoarsePointer,