daily-soup-widget 0.1.3 → 0.1.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.
package/dist/embed.cjs.js CHANGED
@@ -56,11 +56,18 @@ function t(lang) {
56
56
  }
57
57
 
58
58
  // src/theme.ts
59
+ function isThemeColors(config) {
60
+ return typeof config === "object" && config !== null;
61
+ }
59
62
  function resolveTheme(config) {
63
+ if (isThemeColors(config)) return config.base ?? "light";
60
64
  if (config === "light" || config === "dark") return config;
61
65
  if (typeof window === "undefined" || !window.matchMedia) return "light";
62
66
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
63
67
  }
68
+ function getThemeColors(config) {
69
+ return isThemeColors(config) ? config : null;
70
+ }
64
71
  function watchSystemTheme(cb) {
65
72
  if (typeof window === "undefined" || !window.matchMedia) return () => {
66
73
  };
@@ -101,14 +108,14 @@ var WIDGET_STYLES = `
101
108
  .ds-card {
102
109
  container-type: inline-size;
103
110
  width: 100%;
104
- max-width: 32rem;
111
+ max-width: var(--ds-max-width, 32rem);
105
112
  margin: 0 auto;
106
113
  padding: 1.25rem 1.5rem;
107
114
  border-radius: 0.75rem;
108
115
  border: 1px solid var(--ds-border);
109
116
  background: var(--ds-bg);
110
117
  color: var(--ds-fg);
111
- font-size: clamp(0.875rem, 2.5cqi, 1.125rem);
118
+ font-size: clamp(0.875rem, 2.5cqi, 1.25rem);
112
119
  line-height: 1.7;
113
120
  transition: background 0.2s ease, color 0.2s ease;
114
121
  }
@@ -176,6 +183,13 @@ var WIDGET_STYLES = `
176
183
  }
177
184
  @container (min-width: 500px) {
178
185
  .ds-quote { font-size: 1.25em; }
186
+ .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }
187
+ }
188
+ @container (min-width: 700px) {
189
+ .ds-card { padding: 1.75rem 2rem; }
190
+ .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }
191
+ .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }
192
+ .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }
179
193
  }
180
194
  @media (prefers-reduced-motion: reduce) {
181
195
  .ds-card, .ds-btn { transition: none; }
@@ -289,10 +303,22 @@ function pickQuote(schedule) {
289
303
  }
290
304
  return null;
291
305
  }
306
+ function applyThemeOverrides(card, config, maxWidth) {
307
+ const colors = getThemeColors(config);
308
+ if (colors) {
309
+ if (colors.bg) card.style.setProperty("--ds-bg", colors.bg);
310
+ if (colors.ink) card.style.setProperty("--ds-fg", colors.ink);
311
+ if (colors.muted) card.style.setProperty("--ds-muted", colors.muted);
312
+ if (colors.border) card.style.setProperty("--ds-border", colors.border);
313
+ if (colors.accent) card.style.setProperty("--ds-accent", colors.accent);
314
+ }
315
+ if (maxWidth) card.style.setProperty("--ds-max-width", maxWidth);
316
+ }
292
317
  function mount(host, options = {}) {
293
318
  const lang = options.lang ?? "zh";
294
319
  const themeConfig = options.theme ?? "auto";
295
320
  const scheduleUrl = options.scheduleUrl === void 0 ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;
321
+ const maxWidth = options.maxWidth;
296
322
  let resolvedTheme = resolveTheme(themeConfig);
297
323
  const root = attachRoot(host);
298
324
  if (root === host) {
@@ -302,6 +328,7 @@ function mount(host, options = {}) {
302
328
  }
303
329
  injectStyles(root);
304
330
  const card = buildSkeleton(resolvedTheme);
331
+ applyThemeOverrides(card, themeConfig, maxWidth);
305
332
  root.appendChild(card);
306
333
  const state = {
307
334
  lang,
@@ -362,20 +389,23 @@ function mountAll(selector = "[data-daily-soup], #daily-soup") {
362
389
  const lang = node.dataset.lang ?? "zh";
363
390
  const theme = node.dataset.theme ?? "auto";
364
391
  const scheduleUrl = node.dataset.scheduleUrl;
365
- handles.push(mount(node, { lang, theme, scheduleUrl }));
392
+ const maxWidth = node.dataset.maxWidth;
393
+ handles.push(mount(node, { lang, theme, scheduleUrl, maxWidth }));
366
394
  });
367
395
  return handles;
368
396
  }
369
397
 
370
398
  // src/component.tsx
371
399
  var import_react = require("react");
372
- function DailySoup({ lang = "zh", theme = "auto", scheduleUrl, className }) {
400
+ var import_jsx_runtime = require("react/jsx-runtime");
401
+ function DailySoup({ lang = "zh", theme = "auto", scheduleUrl, className, maxWidth }) {
373
402
  const hostRef = (0, import_react.useRef)(null);
403
+ const themeKey = typeof theme === "string" ? theme : JSON.stringify(theme);
374
404
  (0, import_react.useEffect)(() => {
375
405
  if (!hostRef.current) return;
376
- const handle = mount(hostRef.current, { lang, theme, scheduleUrl });
406
+ const handle = mount(hostRef.current, { lang, theme, scheduleUrl, maxWidth });
377
407
  return () => handle.destroy();
378
- }, [lang, theme, scheduleUrl]);
379
- return /* @__PURE__ */ React.createElement("div", { ref: hostRef, className, "data-daily-soup-host": "" });
408
+ }, [lang, themeKey, scheduleUrl, maxWidth]);
409
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: hostRef, className, "data-daily-soup-host": "" });
380
410
  }
381
411
  //# sourceMappingURL=embed.cjs.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../src/i18n.ts", "../src/theme.ts", "../src/share.ts", "../src/styles.ts", "../src/date.ts", "../src/widget.ts", "../src/component.tsx"],
4
- "sourcesContent": ["export { mount, mountAll } from './widget';\nexport { DailySoup } from './component';\nexport type {\n Lang,\n ThemeConfig,\n ResolvedTheme,\n Quote,\n Schedule,\n MountOptions,\n DailySoupProps,\n} from './types';\n", "import type { Lang } from './types';\n\ninterface UiStrings {\n copy: string;\n copied: string;\n share: string;\n source: string;\n poweredBy: string;\n attributedPopular: string;\n shareX: string;\n shareLine: string;\n loadFailed: string;\n}\n\nconst STRINGS: Record<Lang, UiStrings> = {\n zh: {\n copy: '\u8907\u88FD',\n copied: '\u5DF2\u8907\u88FD',\n share: '\u5206\u4EAB',\n source: '\u51FA\u8655',\n poweredBy: '\u7531 mshmwr \u63D0\u4F9B',\n attributedPopular: '\u50B3\u7D71\u6B78\u5C6C',\n shareX: '\u5206\u4EAB\u5230 X',\n shareLine: '\u5206\u4EAB\u5230 LINE',\n loadFailed: '\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557',\n },\n en: {\n copy: 'Copy',\n copied: 'Copied!',\n share: 'Share',\n source: 'Source',\n poweredBy: 'powered by mshmwr',\n attributedPopular: 'popularly attributed',\n shareX: 'Share on X',\n shareLine: 'Share on LINE',\n loadFailed: 'Failed to load daily quote',\n },\n};\n\nexport function t(lang: Lang): UiStrings {\n return STRINGS[lang] ?? STRINGS.zh;\n}\n\nexport type { UiStrings };\n", "import type { ThemeConfig, ResolvedTheme } from './types';\n\nexport function resolveTheme(config: ThemeConfig): ResolvedTheme {\n if (config === 'light' || config === 'dark') return config;\n if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\nexport function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => cb(e.matches ? 'dark' : 'light');\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n}\n", "const SHARE_URL = 'https://daily-soup-widget.vercel.app';\n\nexport interface ShareContent {\n text: string;\n author: string;\n}\n\nexport async function copyToClipboard(content: ShareContent): Promise<boolean> {\n const payload = `${content.text} \u2014 ${content.author}`;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n try {\n await navigator.clipboard.writeText(payload);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n}\n\nexport function buildXShareUrl(content: ShareContent): string {\n const text = encodeURIComponent(`${content.text} \u2014 ${content.author}`);\n const url = encodeURIComponent(SHARE_URL);\n return `https://twitter.com/intent/tweet?text=${text}&url=${url}`;\n}\n\nexport function buildLineShareUrl(content: ShareContent): string {\n const url = encodeURIComponent(`${SHARE_URL} \u2014 ${content.text}`);\n return `https://social-plugins.line.me/lineit/share?url=${url}`;\n}\n", "export const WIDGET_STYLES = `\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: 32rem;\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.125rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n`;\n", "export function todayUtc8(now: Date = new Date()): string {\n const utc8 = new Date(now.getTime() + 8 * 60 * 60 * 1000);\n const yy = utc8.getUTCFullYear();\n const mm = String(utc8.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(utc8.getUTCDate()).padStart(2, '0');\n return `${yy}-${mm}-${dd}`;\n}\n", "import type { Lang, MountOptions, Quote, ResolvedTheme, Schedule, ThemeConfig } from './types';\nimport { t } from './i18n';\nimport { resolveTheme, watchSystemTheme } from './theme';\nimport { buildLineShareUrl, buildXShareUrl, copyToClipboard } from './share';\nimport { WIDGET_STYLES } from './styles';\nimport { todayUtc8 } from './date';\n\nconst DEFAULT_SCHEDULE_BASE = 'https://daily-soup-widget.vercel.app';\n\nexport interface MountHandle {\n destroy(): void;\n}\n\ninterface WidgetState {\n lang: Lang;\n themeConfig: ThemeConfig;\n scheduleUrl: string;\n host: HTMLElement;\n root: ShadowRoot | HTMLElement;\n cardEl: HTMLElement;\n unwatchTheme: () => void;\n}\n\nfunction escape(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction attachRoot(host: HTMLElement): ShadowRoot | HTMLElement {\n if (typeof host.attachShadow === 'function') {\n if (host.shadowRoot) return host.shadowRoot;\n return host.attachShadow({ mode: 'open' });\n }\n console.warn('[daily-soup] attachShadow unsupported, falling back to light DOM');\n return host;\n}\n\nfunction injectStyles(root: ShadowRoot | HTMLElement) {\n const style = document.createElement('style');\n style.textContent = WIDGET_STYLES;\n root.appendChild(style);\n}\n\nfunction buildSkeleton(theme: ResolvedTheme): HTMLElement {\n const card = document.createElement('div');\n card.className = `ds-card ds-${theme} ds-skeleton`;\n card.innerHTML = `\n <div class=\"ds-quote\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>\n <div class=\"ds-meta\"><span class=\"ds-author\">&nbsp;</span><span class=\"ds-source\">&nbsp;</span></div>\n `;\n return card;\n}\n\nfunction renderQuote(card: HTMLElement, quote: Quote, lang: Lang, theme: ResolvedTheme) {\n const s = t(lang);\n card.className = `ds-card ds-${theme}`;\n const sourceLabel = quote.sourceUrl\n ? `<a href=\"${escape(quote.sourceUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escape(quote.source)}</a>`\n : escape(quote.source);\n const flag = quote.attribution === 'popular-attribution'\n ? `<span class=\"ds-flag\">${escape(s.attributedPopular)}</span>`\n : '';\n card.innerHTML = `\n <p class=\"ds-quote\">${escape(quote.text)}</p>\n <div class=\"ds-meta\">\n <span class=\"ds-author\">\u2014 ${escape(quote.author)}${flag}</span>\n ${quote.source ? `<span class=\"ds-source\">${s.source}\uFF1A${sourceLabel}</span>` : ''}\n </div>\n <div class=\"ds-actions\">\n <div class=\"ds-share\">\n <button class=\"ds-btn\" data-action=\"copy\" type=\"button\" aria-label=\"${escape(s.copy)}\">\n <span aria-hidden=\"true\">\u29C9</span><span class=\"ds-share-label\">${escape(s.copy)}</span>\n </button>\n <a class=\"ds-btn\" data-action=\"x\" href=\"${escape(buildXShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareX)}\">\n <span aria-hidden=\"true\">\uD835\uDD4F</span><span class=\"ds-share-label\">X</span>\n </a>\n <a class=\"ds-btn\" data-action=\"line\" href=\"${escape(buildLineShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareLine)}\">\n <span aria-hidden=\"true\">L</span><span class=\"ds-share-label\">LINE</span>\n </a>\n </div>\n <span class=\"ds-powered\"><a href=\"https://personal-site-mocha-chi.vercel.app\" target=\"_blank\" rel=\"noopener noreferrer\">${s.poweredBy}</a></span>\n </div>\n `;\n\n const copyBtn = card.querySelector<HTMLButtonElement>('[data-action=\"copy\"]');\n if (copyBtn) {\n copyBtn.addEventListener('click', async () => {\n const ok = await copyToClipboard({ text: quote.text, author: quote.author });\n if (ok) {\n const label = copyBtn.querySelector('.ds-share-label');\n const originalLabel = label?.textContent ?? '';\n if (label) label.textContent = s.copied;\n copyBtn.classList.add('ds-toast');\n setTimeout(() => {\n if (label) label.textContent = originalLabel;\n copyBtn.classList.remove('ds-toast');\n }, 2000);\n }\n });\n }\n}\n\nfunction renderError(card: HTMLElement, lang: Lang, theme: ResolvedTheme) {\n card.className = `ds-card ds-${theme}`;\n const s = t(lang);\n card.innerHTML = `<p class=\"ds-error\">${escape(s.loadFailed)}</p>`;\n}\n\nasync function fetchSchedule(scheduleUrl: string, lang: Lang): Promise<Schedule | null> {\n const base = scheduleUrl.replace(/\\/$/, '');\n const url = `${base}/schedule-${lang}.json`;\n try {\n const init: RequestInit = base === '' ? { credentials: 'omit' } : { credentials: 'omit', mode: 'cors' };\n const res = await fetch(url, init);\n if (!res.ok) return null;\n return (await res.json()) as Schedule;\n } catch {\n return null;\n }\n}\n\nfunction pickQuote(schedule: Schedule): Quote | null {\n const today = todayUtc8();\n const id = schedule.entries[today];\n if (id && schedule.quotes[id]) return schedule.quotes[id];\n const fallbackId = Object.keys(schedule.quotes).sort()[0];\n if (fallbackId && schedule.quotes[fallbackId]) {\n console.warn('[daily-soup] today entry missing or stale, falling back to first quote');\n return schedule.quotes[fallbackId];\n }\n return null;\n}\n\nexport function mount(host: HTMLElement, options: MountOptions = {}): MountHandle {\n const lang: Lang = options.lang ?? 'zh';\n const themeConfig: ThemeConfig = options.theme ?? 'auto';\n const scheduleUrl = options.scheduleUrl === undefined ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;\n\n let resolvedTheme = resolveTheme(themeConfig);\n const root = attachRoot(host);\n if (root === host) {\n // light DOM fallback \u2014 clear any prior content\n host.textContent = '';\n } else {\n while ((root as ShadowRoot).firstChild) (root as ShadowRoot).removeChild((root as ShadowRoot).firstChild!);\n }\n injectStyles(root);\n\n const card = buildSkeleton(resolvedTheme);\n root.appendChild(card);\n\n const state: WidgetState = {\n lang,\n themeConfig,\n scheduleUrl,\n host,\n root,\n cardEl: card,\n unwatchTheme: () => {},\n };\n\n if (themeConfig === 'auto') {\n state.unwatchTheme = watchSystemTheme((t) => {\n resolvedTheme = t;\n state.cardEl.classList.remove('ds-light', 'ds-dark');\n state.cardEl.classList.add(`ds-${t}`);\n });\n }\n\n let cancelled = false;\n let retried = false;\n\n const load = async () => {\n const schedule = await fetchSchedule(scheduleUrl, lang);\n if (cancelled) return;\n if (!schedule) {\n if (!retried) {\n retried = true;\n setTimeout(load, 2000);\n return;\n }\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n const quote = pickQuote(schedule);\n if (!quote) {\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n renderQuote(state.cardEl, quote, lang, resolvedTheme);\n };\n load();\n\n return {\n destroy() {\n cancelled = true;\n state.unwatchTheme();\n if (root === host) {\n host.textContent = '';\n } else if (host.shadowRoot) {\n while (host.shadowRoot.firstChild) host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n }\n },\n };\n}\n\nexport function mountAll(selector = '[data-daily-soup], #daily-soup'): MountHandle[] {\n if (typeof document === 'undefined') return [];\n const nodes = document.querySelectorAll<HTMLElement>(selector);\n const handles: MountHandle[] = [];\n nodes.forEach((node) => {\n const lang = (node.dataset.lang as Lang | undefined) ?? 'zh';\n const theme = (node.dataset.theme as ThemeConfig | undefined) ?? 'auto';\n const scheduleUrl = node.dataset.scheduleUrl;\n handles.push(mount(node, { lang, theme, scheduleUrl }));\n });\n return handles;\n}\n", "import { useEffect, useRef } from 'react';\nimport { mount } from './widget';\nimport type { DailySoupProps } from './types';\n\nexport function DailySoup({ lang = 'zh', theme = 'auto', scheduleUrl, className }: DailySoupProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!hostRef.current) return;\n const handle = mount(hostRef.current, { lang, theme, scheduleUrl });\n return () => handle.destroy();\n }, [lang, theme, scheduleUrl]);\n\n return <div ref={hostRef} className={className} data-daily-soup-host=\"\" />;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["export { mount, mountAll } from './widget';\nexport { DailySoup } from './component';\nexport type {\n Lang,\n ThemeConfig,\n ResolvedTheme,\n Quote,\n Schedule,\n MountOptions,\n DailySoupProps,\n} from './types';\n", "import type { Lang } from './types';\n\ninterface UiStrings {\n copy: string;\n copied: string;\n share: string;\n source: string;\n poweredBy: string;\n attributedPopular: string;\n shareX: string;\n shareLine: string;\n loadFailed: string;\n}\n\nconst STRINGS: Record<Lang, UiStrings> = {\n zh: {\n copy: '\u8907\u88FD',\n copied: '\u5DF2\u8907\u88FD',\n share: '\u5206\u4EAB',\n source: '\u51FA\u8655',\n poweredBy: '\u7531 mshmwr \u63D0\u4F9B',\n attributedPopular: '\u50B3\u7D71\u6B78\u5C6C',\n shareX: '\u5206\u4EAB\u5230 X',\n shareLine: '\u5206\u4EAB\u5230 LINE',\n loadFailed: '\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557',\n },\n en: {\n copy: 'Copy',\n copied: 'Copied!',\n share: 'Share',\n source: 'Source',\n poweredBy: 'powered by mshmwr',\n attributedPopular: 'popularly attributed',\n shareX: 'Share on X',\n shareLine: 'Share on LINE',\n loadFailed: 'Failed to load daily quote',\n },\n};\n\nexport function t(lang: Lang): UiStrings {\n return STRINGS[lang] ?? STRINGS.zh;\n}\n\nexport type { UiStrings };\n", "import type { ThemeConfig, ResolvedTheme, ThemeColors } from './types';\n\nfunction isThemeColors(config: ThemeConfig): config is ThemeColors {\n return typeof config === 'object' && config !== null;\n}\n\nexport function resolveTheme(config: ThemeConfig): ResolvedTheme {\n if (isThemeColors(config)) return config.base ?? 'light';\n if (config === 'light' || config === 'dark') return config;\n if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\nexport function getThemeColors(config: ThemeConfig): ThemeColors | null {\n return isThemeColors(config) ? config : null;\n}\n\nexport function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => cb(e.matches ? 'dark' : 'light');\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n}\n", "const SHARE_URL = 'https://daily-soup-widget.vercel.app';\n\nexport interface ShareContent {\n text: string;\n author: string;\n}\n\nexport async function copyToClipboard(content: ShareContent): Promise<boolean> {\n const payload = `${content.text} \u2014 ${content.author}`;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n try {\n await navigator.clipboard.writeText(payload);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n}\n\nexport function buildXShareUrl(content: ShareContent): string {\n const text = encodeURIComponent(`${content.text} \u2014 ${content.author}`);\n const url = encodeURIComponent(SHARE_URL);\n return `https://twitter.com/intent/tweet?text=${text}&url=${url}`;\n}\n\nexport function buildLineShareUrl(content: ShareContent): string {\n const url = encodeURIComponent(`${SHARE_URL} \u2014 ${content.text}`);\n return `https://social-plugins.line.me/lineit/share?url=${url}`;\n}\n", "export const WIDGET_STYLES = `\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: var(--ds-max-width, 32rem);\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.25rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }\n }\n @container (min-width: 700px) {\n .ds-card { padding: 1.75rem 2rem; }\n .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }\n .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }\n .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n`;\n", "export function todayUtc8(now: Date = new Date()): string {\n const utc8 = new Date(now.getTime() + 8 * 60 * 60 * 1000);\n const yy = utc8.getUTCFullYear();\n const mm = String(utc8.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(utc8.getUTCDate()).padStart(2, '0');\n return `${yy}-${mm}-${dd}`;\n}\n", "import type { Lang, MountOptions, Quote, ResolvedTheme, Schedule, ThemeConfig } from './types';\nimport { t } from './i18n';\nimport { resolveTheme, watchSystemTheme, getThemeColors } from './theme';\nimport { buildLineShareUrl, buildXShareUrl, copyToClipboard } from './share';\nimport { WIDGET_STYLES } from './styles';\nimport { todayUtc8 } from './date';\n\nconst DEFAULT_SCHEDULE_BASE = 'https://daily-soup-widget.vercel.app';\n\nexport interface MountHandle {\n destroy(): void;\n}\n\ninterface WidgetState {\n lang: Lang;\n themeConfig: ThemeConfig;\n scheduleUrl: string;\n host: HTMLElement;\n root: ShadowRoot | HTMLElement;\n cardEl: HTMLElement;\n unwatchTheme: () => void;\n}\n\nfunction escape(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction attachRoot(host: HTMLElement): ShadowRoot | HTMLElement {\n if (typeof host.attachShadow === 'function') {\n if (host.shadowRoot) return host.shadowRoot;\n return host.attachShadow({ mode: 'open' });\n }\n console.warn('[daily-soup] attachShadow unsupported, falling back to light DOM');\n return host;\n}\n\nfunction injectStyles(root: ShadowRoot | HTMLElement) {\n const style = document.createElement('style');\n style.textContent = WIDGET_STYLES;\n root.appendChild(style);\n}\n\nfunction buildSkeleton(theme: ResolvedTheme): HTMLElement {\n const card = document.createElement('div');\n card.className = `ds-card ds-${theme} ds-skeleton`;\n card.innerHTML = `\n <div class=\"ds-quote\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>\n <div class=\"ds-meta\"><span class=\"ds-author\">&nbsp;</span><span class=\"ds-source\">&nbsp;</span></div>\n `;\n return card;\n}\n\nfunction renderQuote(card: HTMLElement, quote: Quote, lang: Lang, theme: ResolvedTheme) {\n const s = t(lang);\n card.className = `ds-card ds-${theme}`;\n const sourceLabel = quote.sourceUrl\n ? `<a href=\"${escape(quote.sourceUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escape(quote.source)}</a>`\n : escape(quote.source);\n const flag = quote.attribution === 'popular-attribution'\n ? `<span class=\"ds-flag\">${escape(s.attributedPopular)}</span>`\n : '';\n card.innerHTML = `\n <p class=\"ds-quote\">${escape(quote.text)}</p>\n <div class=\"ds-meta\">\n <span class=\"ds-author\">\u2014 ${escape(quote.author)}${flag}</span>\n ${quote.source ? `<span class=\"ds-source\">${s.source}\uFF1A${sourceLabel}</span>` : ''}\n </div>\n <div class=\"ds-actions\">\n <div class=\"ds-share\">\n <button class=\"ds-btn\" data-action=\"copy\" type=\"button\" aria-label=\"${escape(s.copy)}\">\n <span aria-hidden=\"true\">\u29C9</span><span class=\"ds-share-label\">${escape(s.copy)}</span>\n </button>\n <a class=\"ds-btn\" data-action=\"x\" href=\"${escape(buildXShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareX)}\">\n <span aria-hidden=\"true\">\uD835\uDD4F</span><span class=\"ds-share-label\">X</span>\n </a>\n <a class=\"ds-btn\" data-action=\"line\" href=\"${escape(buildLineShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareLine)}\">\n <span aria-hidden=\"true\">L</span><span class=\"ds-share-label\">LINE</span>\n </a>\n </div>\n <span class=\"ds-powered\"><a href=\"https://personal-site-mocha-chi.vercel.app\" target=\"_blank\" rel=\"noopener noreferrer\">${s.poweredBy}</a></span>\n </div>\n `;\n\n const copyBtn = card.querySelector<HTMLButtonElement>('[data-action=\"copy\"]');\n if (copyBtn) {\n copyBtn.addEventListener('click', async () => {\n const ok = await copyToClipboard({ text: quote.text, author: quote.author });\n if (ok) {\n const label = copyBtn.querySelector('.ds-share-label');\n const originalLabel = label?.textContent ?? '';\n if (label) label.textContent = s.copied;\n copyBtn.classList.add('ds-toast');\n setTimeout(() => {\n if (label) label.textContent = originalLabel;\n copyBtn.classList.remove('ds-toast');\n }, 2000);\n }\n });\n }\n}\n\nfunction renderError(card: HTMLElement, lang: Lang, theme: ResolvedTheme) {\n card.className = `ds-card ds-${theme}`;\n const s = t(lang);\n card.innerHTML = `<p class=\"ds-error\">${escape(s.loadFailed)}</p>`;\n}\n\nasync function fetchSchedule(scheduleUrl: string, lang: Lang): Promise<Schedule | null> {\n const base = scheduleUrl.replace(/\\/$/, '');\n const url = `${base}/schedule-${lang}.json`;\n try {\n const init: RequestInit = base === '' ? { credentials: 'omit' } : { credentials: 'omit', mode: 'cors' };\n const res = await fetch(url, init);\n if (!res.ok) return null;\n return (await res.json()) as Schedule;\n } catch {\n return null;\n }\n}\n\nfunction pickQuote(schedule: Schedule): Quote | null {\n const today = todayUtc8();\n const id = schedule.entries[today];\n if (id && schedule.quotes[id]) return schedule.quotes[id];\n const fallbackId = Object.keys(schedule.quotes).sort()[0];\n if (fallbackId && schedule.quotes[fallbackId]) {\n console.warn('[daily-soup] today entry missing or stale, falling back to first quote');\n return schedule.quotes[fallbackId];\n }\n return null;\n}\n\nfunction applyThemeOverrides(card: HTMLElement, config: ThemeConfig, maxWidth?: string) {\n const colors = getThemeColors(config);\n if (colors) {\n if (colors.bg) card.style.setProperty('--ds-bg', colors.bg);\n if (colors.ink) card.style.setProperty('--ds-fg', colors.ink);\n if (colors.muted) card.style.setProperty('--ds-muted', colors.muted);\n if (colors.border) card.style.setProperty('--ds-border', colors.border);\n if (colors.accent) card.style.setProperty('--ds-accent', colors.accent);\n }\n if (maxWidth) card.style.setProperty('--ds-max-width', maxWidth);\n}\n\nexport function mount(host: HTMLElement, options: MountOptions = {}): MountHandle {\n const lang: Lang = options.lang ?? 'zh';\n const themeConfig: ThemeConfig = options.theme ?? 'auto';\n const scheduleUrl = options.scheduleUrl === undefined ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;\n const maxWidth = options.maxWidth;\n\n let resolvedTheme = resolveTheme(themeConfig);\n const root = attachRoot(host);\n if (root === host) {\n // light DOM fallback \u2014 clear any prior content\n host.textContent = '';\n } else {\n while ((root as ShadowRoot).firstChild) (root as ShadowRoot).removeChild((root as ShadowRoot).firstChild!);\n }\n injectStyles(root);\n\n const card = buildSkeleton(resolvedTheme);\n applyThemeOverrides(card, themeConfig, maxWidth);\n root.appendChild(card);\n\n const state: WidgetState = {\n lang,\n themeConfig,\n scheduleUrl,\n host,\n root,\n cardEl: card,\n unwatchTheme: () => {},\n };\n\n if (themeConfig === 'auto') {\n state.unwatchTheme = watchSystemTheme((t) => {\n resolvedTheme = t;\n state.cardEl.classList.remove('ds-light', 'ds-dark');\n state.cardEl.classList.add(`ds-${t}`);\n });\n }\n\n let cancelled = false;\n let retried = false;\n\n const load = async () => {\n const schedule = await fetchSchedule(scheduleUrl, lang);\n if (cancelled) return;\n if (!schedule) {\n if (!retried) {\n retried = true;\n setTimeout(load, 2000);\n return;\n }\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n const quote = pickQuote(schedule);\n if (!quote) {\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n renderQuote(state.cardEl, quote, lang, resolvedTheme);\n };\n load();\n\n return {\n destroy() {\n cancelled = true;\n state.unwatchTheme();\n if (root === host) {\n host.textContent = '';\n } else if (host.shadowRoot) {\n while (host.shadowRoot.firstChild) host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n }\n },\n };\n}\n\nexport function mountAll(selector = '[data-daily-soup], #daily-soup'): MountHandle[] {\n if (typeof document === 'undefined') return [];\n const nodes = document.querySelectorAll<HTMLElement>(selector);\n const handles: MountHandle[] = [];\n nodes.forEach((node) => {\n const lang = (node.dataset.lang as Lang | undefined) ?? 'zh';\n const theme = (node.dataset.theme as 'auto' | 'light' | 'dark' | undefined) ?? 'auto';\n const scheduleUrl = node.dataset.scheduleUrl;\n const maxWidth = node.dataset.maxWidth;\n handles.push(mount(node, { lang, theme, scheduleUrl, maxWidth }));\n });\n return handles;\n}\n", "import { useEffect, useRef } from 'react';\nimport { mount } from './widget';\nimport type { DailySoupProps } from './types';\n\nexport function DailySoup({ lang = 'zh', theme = 'auto', scheduleUrl, className, maxWidth }: DailySoupProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n const themeKey = typeof theme === 'string' ? theme : JSON.stringify(theme);\n useEffect(() => {\n if (!hostRef.current) return;\n const handle = mount(hostRef.current, { lang, theme, scheduleUrl, maxWidth });\n return () => handle.destroy();\n }, [lang, themeKey, scheduleUrl, maxWidth]);\n\n return <div ref={hostRef} className={className} data-daily-soup-host=\"\" />;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["t"]
7
7
  }
package/dist/embed.esm.js CHANGED
@@ -28,11 +28,18 @@ function t(lang) {
28
28
  }
29
29
 
30
30
  // src/theme.ts
31
+ function isThemeColors(config) {
32
+ return typeof config === "object" && config !== null;
33
+ }
31
34
  function resolveTheme(config) {
35
+ if (isThemeColors(config)) return config.base ?? "light";
32
36
  if (config === "light" || config === "dark") return config;
33
37
  if (typeof window === "undefined" || !window.matchMedia) return "light";
34
38
  return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
35
39
  }
40
+ function getThemeColors(config) {
41
+ return isThemeColors(config) ? config : null;
42
+ }
36
43
  function watchSystemTheme(cb) {
37
44
  if (typeof window === "undefined" || !window.matchMedia) return () => {
38
45
  };
@@ -73,14 +80,14 @@ var WIDGET_STYLES = `
73
80
  .ds-card {
74
81
  container-type: inline-size;
75
82
  width: 100%;
76
- max-width: 32rem;
83
+ max-width: var(--ds-max-width, 32rem);
77
84
  margin: 0 auto;
78
85
  padding: 1.25rem 1.5rem;
79
86
  border-radius: 0.75rem;
80
87
  border: 1px solid var(--ds-border);
81
88
  background: var(--ds-bg);
82
89
  color: var(--ds-fg);
83
- font-size: clamp(0.875rem, 2.5cqi, 1.125rem);
90
+ font-size: clamp(0.875rem, 2.5cqi, 1.25rem);
84
91
  line-height: 1.7;
85
92
  transition: background 0.2s ease, color 0.2s ease;
86
93
  }
@@ -148,6 +155,13 @@ var WIDGET_STYLES = `
148
155
  }
149
156
  @container (min-width: 500px) {
150
157
  .ds-quote { font-size: 1.25em; }
158
+ .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }
159
+ }
160
+ @container (min-width: 700px) {
161
+ .ds-card { padding: 1.75rem 2rem; }
162
+ .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }
163
+ .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }
164
+ .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }
151
165
  }
152
166
  @media (prefers-reduced-motion: reduce) {
153
167
  .ds-card, .ds-btn { transition: none; }
@@ -261,10 +275,22 @@ function pickQuote(schedule) {
261
275
  }
262
276
  return null;
263
277
  }
278
+ function applyThemeOverrides(card, config, maxWidth) {
279
+ const colors = getThemeColors(config);
280
+ if (colors) {
281
+ if (colors.bg) card.style.setProperty("--ds-bg", colors.bg);
282
+ if (colors.ink) card.style.setProperty("--ds-fg", colors.ink);
283
+ if (colors.muted) card.style.setProperty("--ds-muted", colors.muted);
284
+ if (colors.border) card.style.setProperty("--ds-border", colors.border);
285
+ if (colors.accent) card.style.setProperty("--ds-accent", colors.accent);
286
+ }
287
+ if (maxWidth) card.style.setProperty("--ds-max-width", maxWidth);
288
+ }
264
289
  function mount(host, options = {}) {
265
290
  const lang = options.lang ?? "zh";
266
291
  const themeConfig = options.theme ?? "auto";
267
292
  const scheduleUrl = options.scheduleUrl === void 0 ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;
293
+ const maxWidth = options.maxWidth;
268
294
  let resolvedTheme = resolveTheme(themeConfig);
269
295
  const root = attachRoot(host);
270
296
  if (root === host) {
@@ -274,6 +300,7 @@ function mount(host, options = {}) {
274
300
  }
275
301
  injectStyles(root);
276
302
  const card = buildSkeleton(resolvedTheme);
303
+ applyThemeOverrides(card, themeConfig, maxWidth);
277
304
  root.appendChild(card);
278
305
  const state = {
279
306
  lang,
@@ -334,21 +361,24 @@ function mountAll(selector = "[data-daily-soup], #daily-soup") {
334
361
  const lang = node.dataset.lang ?? "zh";
335
362
  const theme = node.dataset.theme ?? "auto";
336
363
  const scheduleUrl = node.dataset.scheduleUrl;
337
- handles.push(mount(node, { lang, theme, scheduleUrl }));
364
+ const maxWidth = node.dataset.maxWidth;
365
+ handles.push(mount(node, { lang, theme, scheduleUrl, maxWidth }));
338
366
  });
339
367
  return handles;
340
368
  }
341
369
 
342
370
  // src/component.tsx
343
371
  import { useEffect, useRef } from "react";
344
- function DailySoup({ lang = "zh", theme = "auto", scheduleUrl, className }) {
372
+ import { jsx } from "react/jsx-runtime";
373
+ function DailySoup({ lang = "zh", theme = "auto", scheduleUrl, className, maxWidth }) {
345
374
  const hostRef = useRef(null);
375
+ const themeKey = typeof theme === "string" ? theme : JSON.stringify(theme);
346
376
  useEffect(() => {
347
377
  if (!hostRef.current) return;
348
- const handle = mount(hostRef.current, { lang, theme, scheduleUrl });
378
+ const handle = mount(hostRef.current, { lang, theme, scheduleUrl, maxWidth });
349
379
  return () => handle.destroy();
350
- }, [lang, theme, scheduleUrl]);
351
- return /* @__PURE__ */ React.createElement("div", { ref: hostRef, className, "data-daily-soup-host": "" });
380
+ }, [lang, themeKey, scheduleUrl, maxWidth]);
381
+ return /* @__PURE__ */ jsx("div", { ref: hostRef, className, "data-daily-soup-host": "" });
352
382
  }
353
383
  export {
354
384
  DailySoup,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/i18n.ts", "../src/theme.ts", "../src/share.ts", "../src/styles.ts", "../src/date.ts", "../src/widget.ts", "../src/component.tsx"],
4
- "sourcesContent": ["import type { Lang } from './types';\n\ninterface UiStrings {\n copy: string;\n copied: string;\n share: string;\n source: string;\n poweredBy: string;\n attributedPopular: string;\n shareX: string;\n shareLine: string;\n loadFailed: string;\n}\n\nconst STRINGS: Record<Lang, UiStrings> = {\n zh: {\n copy: '\u8907\u88FD',\n copied: '\u5DF2\u8907\u88FD',\n share: '\u5206\u4EAB',\n source: '\u51FA\u8655',\n poweredBy: '\u7531 mshmwr \u63D0\u4F9B',\n attributedPopular: '\u50B3\u7D71\u6B78\u5C6C',\n shareX: '\u5206\u4EAB\u5230 X',\n shareLine: '\u5206\u4EAB\u5230 LINE',\n loadFailed: '\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557',\n },\n en: {\n copy: 'Copy',\n copied: 'Copied!',\n share: 'Share',\n source: 'Source',\n poweredBy: 'powered by mshmwr',\n attributedPopular: 'popularly attributed',\n shareX: 'Share on X',\n shareLine: 'Share on LINE',\n loadFailed: 'Failed to load daily quote',\n },\n};\n\nexport function t(lang: Lang): UiStrings {\n return STRINGS[lang] ?? STRINGS.zh;\n}\n\nexport type { UiStrings };\n", "import type { ThemeConfig, ResolvedTheme } from './types';\n\nexport function resolveTheme(config: ThemeConfig): ResolvedTheme {\n if (config === 'light' || config === 'dark') return config;\n if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\nexport function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => cb(e.matches ? 'dark' : 'light');\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n}\n", "const SHARE_URL = 'https://daily-soup-widget.vercel.app';\n\nexport interface ShareContent {\n text: string;\n author: string;\n}\n\nexport async function copyToClipboard(content: ShareContent): Promise<boolean> {\n const payload = `${content.text} \u2014 ${content.author}`;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n try {\n await navigator.clipboard.writeText(payload);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n}\n\nexport function buildXShareUrl(content: ShareContent): string {\n const text = encodeURIComponent(`${content.text} \u2014 ${content.author}`);\n const url = encodeURIComponent(SHARE_URL);\n return `https://twitter.com/intent/tweet?text=${text}&url=${url}`;\n}\n\nexport function buildLineShareUrl(content: ShareContent): string {\n const url = encodeURIComponent(`${SHARE_URL} \u2014 ${content.text}`);\n return `https://social-plugins.line.me/lineit/share?url=${url}`;\n}\n", "export const WIDGET_STYLES = `\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: 32rem;\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.125rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n`;\n", "export function todayUtc8(now: Date = new Date()): string {\n const utc8 = new Date(now.getTime() + 8 * 60 * 60 * 1000);\n const yy = utc8.getUTCFullYear();\n const mm = String(utc8.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(utc8.getUTCDate()).padStart(2, '0');\n return `${yy}-${mm}-${dd}`;\n}\n", "import type { Lang, MountOptions, Quote, ResolvedTheme, Schedule, ThemeConfig } from './types';\nimport { t } from './i18n';\nimport { resolveTheme, watchSystemTheme } from './theme';\nimport { buildLineShareUrl, buildXShareUrl, copyToClipboard } from './share';\nimport { WIDGET_STYLES } from './styles';\nimport { todayUtc8 } from './date';\n\nconst DEFAULT_SCHEDULE_BASE = 'https://daily-soup-widget.vercel.app';\n\nexport interface MountHandle {\n destroy(): void;\n}\n\ninterface WidgetState {\n lang: Lang;\n themeConfig: ThemeConfig;\n scheduleUrl: string;\n host: HTMLElement;\n root: ShadowRoot | HTMLElement;\n cardEl: HTMLElement;\n unwatchTheme: () => void;\n}\n\nfunction escape(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction attachRoot(host: HTMLElement): ShadowRoot | HTMLElement {\n if (typeof host.attachShadow === 'function') {\n if (host.shadowRoot) return host.shadowRoot;\n return host.attachShadow({ mode: 'open' });\n }\n console.warn('[daily-soup] attachShadow unsupported, falling back to light DOM');\n return host;\n}\n\nfunction injectStyles(root: ShadowRoot | HTMLElement) {\n const style = document.createElement('style');\n style.textContent = WIDGET_STYLES;\n root.appendChild(style);\n}\n\nfunction buildSkeleton(theme: ResolvedTheme): HTMLElement {\n const card = document.createElement('div');\n card.className = `ds-card ds-${theme} ds-skeleton`;\n card.innerHTML = `\n <div class=\"ds-quote\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>\n <div class=\"ds-meta\"><span class=\"ds-author\">&nbsp;</span><span class=\"ds-source\">&nbsp;</span></div>\n `;\n return card;\n}\n\nfunction renderQuote(card: HTMLElement, quote: Quote, lang: Lang, theme: ResolvedTheme) {\n const s = t(lang);\n card.className = `ds-card ds-${theme}`;\n const sourceLabel = quote.sourceUrl\n ? `<a href=\"${escape(quote.sourceUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escape(quote.source)}</a>`\n : escape(quote.source);\n const flag = quote.attribution === 'popular-attribution'\n ? `<span class=\"ds-flag\">${escape(s.attributedPopular)}</span>`\n : '';\n card.innerHTML = `\n <p class=\"ds-quote\">${escape(quote.text)}</p>\n <div class=\"ds-meta\">\n <span class=\"ds-author\">\u2014 ${escape(quote.author)}${flag}</span>\n ${quote.source ? `<span class=\"ds-source\">${s.source}\uFF1A${sourceLabel}</span>` : ''}\n </div>\n <div class=\"ds-actions\">\n <div class=\"ds-share\">\n <button class=\"ds-btn\" data-action=\"copy\" type=\"button\" aria-label=\"${escape(s.copy)}\">\n <span aria-hidden=\"true\">\u29C9</span><span class=\"ds-share-label\">${escape(s.copy)}</span>\n </button>\n <a class=\"ds-btn\" data-action=\"x\" href=\"${escape(buildXShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareX)}\">\n <span aria-hidden=\"true\">\uD835\uDD4F</span><span class=\"ds-share-label\">X</span>\n </a>\n <a class=\"ds-btn\" data-action=\"line\" href=\"${escape(buildLineShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareLine)}\">\n <span aria-hidden=\"true\">L</span><span class=\"ds-share-label\">LINE</span>\n </a>\n </div>\n <span class=\"ds-powered\"><a href=\"https://personal-site-mocha-chi.vercel.app\" target=\"_blank\" rel=\"noopener noreferrer\">${s.poweredBy}</a></span>\n </div>\n `;\n\n const copyBtn = card.querySelector<HTMLButtonElement>('[data-action=\"copy\"]');\n if (copyBtn) {\n copyBtn.addEventListener('click', async () => {\n const ok = await copyToClipboard({ text: quote.text, author: quote.author });\n if (ok) {\n const label = copyBtn.querySelector('.ds-share-label');\n const originalLabel = label?.textContent ?? '';\n if (label) label.textContent = s.copied;\n copyBtn.classList.add('ds-toast');\n setTimeout(() => {\n if (label) label.textContent = originalLabel;\n copyBtn.classList.remove('ds-toast');\n }, 2000);\n }\n });\n }\n}\n\nfunction renderError(card: HTMLElement, lang: Lang, theme: ResolvedTheme) {\n card.className = `ds-card ds-${theme}`;\n const s = t(lang);\n card.innerHTML = `<p class=\"ds-error\">${escape(s.loadFailed)}</p>`;\n}\n\nasync function fetchSchedule(scheduleUrl: string, lang: Lang): Promise<Schedule | null> {\n const base = scheduleUrl.replace(/\\/$/, '');\n const url = `${base}/schedule-${lang}.json`;\n try {\n const init: RequestInit = base === '' ? { credentials: 'omit' } : { credentials: 'omit', mode: 'cors' };\n const res = await fetch(url, init);\n if (!res.ok) return null;\n return (await res.json()) as Schedule;\n } catch {\n return null;\n }\n}\n\nfunction pickQuote(schedule: Schedule): Quote | null {\n const today = todayUtc8();\n const id = schedule.entries[today];\n if (id && schedule.quotes[id]) return schedule.quotes[id];\n const fallbackId = Object.keys(schedule.quotes).sort()[0];\n if (fallbackId && schedule.quotes[fallbackId]) {\n console.warn('[daily-soup] today entry missing or stale, falling back to first quote');\n return schedule.quotes[fallbackId];\n }\n return null;\n}\n\nexport function mount(host: HTMLElement, options: MountOptions = {}): MountHandle {\n const lang: Lang = options.lang ?? 'zh';\n const themeConfig: ThemeConfig = options.theme ?? 'auto';\n const scheduleUrl = options.scheduleUrl === undefined ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;\n\n let resolvedTheme = resolveTheme(themeConfig);\n const root = attachRoot(host);\n if (root === host) {\n // light DOM fallback \u2014 clear any prior content\n host.textContent = '';\n } else {\n while ((root as ShadowRoot).firstChild) (root as ShadowRoot).removeChild((root as ShadowRoot).firstChild!);\n }\n injectStyles(root);\n\n const card = buildSkeleton(resolvedTheme);\n root.appendChild(card);\n\n const state: WidgetState = {\n lang,\n themeConfig,\n scheduleUrl,\n host,\n root,\n cardEl: card,\n unwatchTheme: () => {},\n };\n\n if (themeConfig === 'auto') {\n state.unwatchTheme = watchSystemTheme((t) => {\n resolvedTheme = t;\n state.cardEl.classList.remove('ds-light', 'ds-dark');\n state.cardEl.classList.add(`ds-${t}`);\n });\n }\n\n let cancelled = false;\n let retried = false;\n\n const load = async () => {\n const schedule = await fetchSchedule(scheduleUrl, lang);\n if (cancelled) return;\n if (!schedule) {\n if (!retried) {\n retried = true;\n setTimeout(load, 2000);\n return;\n }\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n const quote = pickQuote(schedule);\n if (!quote) {\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n renderQuote(state.cardEl, quote, lang, resolvedTheme);\n };\n load();\n\n return {\n destroy() {\n cancelled = true;\n state.unwatchTheme();\n if (root === host) {\n host.textContent = '';\n } else if (host.shadowRoot) {\n while (host.shadowRoot.firstChild) host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n }\n },\n };\n}\n\nexport function mountAll(selector = '[data-daily-soup], #daily-soup'): MountHandle[] {\n if (typeof document === 'undefined') return [];\n const nodes = document.querySelectorAll<HTMLElement>(selector);\n const handles: MountHandle[] = [];\n nodes.forEach((node) => {\n const lang = (node.dataset.lang as Lang | undefined) ?? 'zh';\n const theme = (node.dataset.theme as ThemeConfig | undefined) ?? 'auto';\n const scheduleUrl = node.dataset.scheduleUrl;\n handles.push(mount(node, { lang, theme, scheduleUrl }));\n });\n return handles;\n}\n", "import { useEffect, useRef } from 'react';\nimport { mount } from './widget';\nimport type { DailySoupProps } from './types';\n\nexport function DailySoup({ lang = 'zh', theme = 'auto', scheduleUrl, className }: DailySoupProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n useEffect(() => {\n if (!hostRef.current) return;\n const handle = mount(hostRef.current, { lang, theme, scheduleUrl });\n return () => handle.destroy();\n }, [lang, theme, scheduleUrl]);\n\n return <div ref={hostRef} className={className} data-daily-soup-host=\"\" />;\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { Lang } from './types';\n\ninterface UiStrings {\n copy: string;\n copied: string;\n share: string;\n source: string;\n poweredBy: string;\n attributedPopular: string;\n shareX: string;\n shareLine: string;\n loadFailed: string;\n}\n\nconst STRINGS: Record<Lang, UiStrings> = {\n zh: {\n copy: '\u8907\u88FD',\n copied: '\u5DF2\u8907\u88FD',\n share: '\u5206\u4EAB',\n source: '\u51FA\u8655',\n poweredBy: '\u7531 mshmwr \u63D0\u4F9B',\n attributedPopular: '\u50B3\u7D71\u6B78\u5C6C',\n shareX: '\u5206\u4EAB\u5230 X',\n shareLine: '\u5206\u4EAB\u5230 LINE',\n loadFailed: '\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557',\n },\n en: {\n copy: 'Copy',\n copied: 'Copied!',\n share: 'Share',\n source: 'Source',\n poweredBy: 'powered by mshmwr',\n attributedPopular: 'popularly attributed',\n shareX: 'Share on X',\n shareLine: 'Share on LINE',\n loadFailed: 'Failed to load daily quote',\n },\n};\n\nexport function t(lang: Lang): UiStrings {\n return STRINGS[lang] ?? STRINGS.zh;\n}\n\nexport type { UiStrings };\n", "import type { ThemeConfig, ResolvedTheme, ThemeColors } from './types';\n\nfunction isThemeColors(config: ThemeConfig): config is ThemeColors {\n return typeof config === 'object' && config !== null;\n}\n\nexport function resolveTheme(config: ThemeConfig): ResolvedTheme {\n if (isThemeColors(config)) return config.base ?? 'light';\n if (config === 'light' || config === 'dark') return config;\n if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\nexport function getThemeColors(config: ThemeConfig): ThemeColors | null {\n return isThemeColors(config) ? config : null;\n}\n\nexport function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => cb(e.matches ? 'dark' : 'light');\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n}\n", "const SHARE_URL = 'https://daily-soup-widget.vercel.app';\n\nexport interface ShareContent {\n text: string;\n author: string;\n}\n\nexport async function copyToClipboard(content: ShareContent): Promise<boolean> {\n const payload = `${content.text} \u2014 ${content.author}`;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n try {\n await navigator.clipboard.writeText(payload);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n}\n\nexport function buildXShareUrl(content: ShareContent): string {\n const text = encodeURIComponent(`${content.text} \u2014 ${content.author}`);\n const url = encodeURIComponent(SHARE_URL);\n return `https://twitter.com/intent/tweet?text=${text}&url=${url}`;\n}\n\nexport function buildLineShareUrl(content: ShareContent): string {\n const url = encodeURIComponent(`${SHARE_URL} \u2014 ${content.text}`);\n return `https://social-plugins.line.me/lineit/share?url=${url}`;\n}\n", "export const WIDGET_STYLES = `\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: var(--ds-max-width, 32rem);\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.25rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }\n }\n @container (min-width: 700px) {\n .ds-card { padding: 1.75rem 2rem; }\n .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }\n .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }\n .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n`;\n", "export function todayUtc8(now: Date = new Date()): string {\n const utc8 = new Date(now.getTime() + 8 * 60 * 60 * 1000);\n const yy = utc8.getUTCFullYear();\n const mm = String(utc8.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(utc8.getUTCDate()).padStart(2, '0');\n return `${yy}-${mm}-${dd}`;\n}\n", "import type { Lang, MountOptions, Quote, ResolvedTheme, Schedule, ThemeConfig } from './types';\nimport { t } from './i18n';\nimport { resolveTheme, watchSystemTheme, getThemeColors } from './theme';\nimport { buildLineShareUrl, buildXShareUrl, copyToClipboard } from './share';\nimport { WIDGET_STYLES } from './styles';\nimport { todayUtc8 } from './date';\n\nconst DEFAULT_SCHEDULE_BASE = 'https://daily-soup-widget.vercel.app';\n\nexport interface MountHandle {\n destroy(): void;\n}\n\ninterface WidgetState {\n lang: Lang;\n themeConfig: ThemeConfig;\n scheduleUrl: string;\n host: HTMLElement;\n root: ShadowRoot | HTMLElement;\n cardEl: HTMLElement;\n unwatchTheme: () => void;\n}\n\nfunction escape(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction attachRoot(host: HTMLElement): ShadowRoot | HTMLElement {\n if (typeof host.attachShadow === 'function') {\n if (host.shadowRoot) return host.shadowRoot;\n return host.attachShadow({ mode: 'open' });\n }\n console.warn('[daily-soup] attachShadow unsupported, falling back to light DOM');\n return host;\n}\n\nfunction injectStyles(root: ShadowRoot | HTMLElement) {\n const style = document.createElement('style');\n style.textContent = WIDGET_STYLES;\n root.appendChild(style);\n}\n\nfunction buildSkeleton(theme: ResolvedTheme): HTMLElement {\n const card = document.createElement('div');\n card.className = `ds-card ds-${theme} ds-skeleton`;\n card.innerHTML = `\n <div class=\"ds-quote\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>\n <div class=\"ds-meta\"><span class=\"ds-author\">&nbsp;</span><span class=\"ds-source\">&nbsp;</span></div>\n `;\n return card;\n}\n\nfunction renderQuote(card: HTMLElement, quote: Quote, lang: Lang, theme: ResolvedTheme) {\n const s = t(lang);\n card.className = `ds-card ds-${theme}`;\n const sourceLabel = quote.sourceUrl\n ? `<a href=\"${escape(quote.sourceUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escape(quote.source)}</a>`\n : escape(quote.source);\n const flag = quote.attribution === 'popular-attribution'\n ? `<span class=\"ds-flag\">${escape(s.attributedPopular)}</span>`\n : '';\n card.innerHTML = `\n <p class=\"ds-quote\">${escape(quote.text)}</p>\n <div class=\"ds-meta\">\n <span class=\"ds-author\">\u2014 ${escape(quote.author)}${flag}</span>\n ${quote.source ? `<span class=\"ds-source\">${s.source}\uFF1A${sourceLabel}</span>` : ''}\n </div>\n <div class=\"ds-actions\">\n <div class=\"ds-share\">\n <button class=\"ds-btn\" data-action=\"copy\" type=\"button\" aria-label=\"${escape(s.copy)}\">\n <span aria-hidden=\"true\">\u29C9</span><span class=\"ds-share-label\">${escape(s.copy)}</span>\n </button>\n <a class=\"ds-btn\" data-action=\"x\" href=\"${escape(buildXShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareX)}\">\n <span aria-hidden=\"true\">\uD835\uDD4F</span><span class=\"ds-share-label\">X</span>\n </a>\n <a class=\"ds-btn\" data-action=\"line\" href=\"${escape(buildLineShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareLine)}\">\n <span aria-hidden=\"true\">L</span><span class=\"ds-share-label\">LINE</span>\n </a>\n </div>\n <span class=\"ds-powered\"><a href=\"https://personal-site-mocha-chi.vercel.app\" target=\"_blank\" rel=\"noopener noreferrer\">${s.poweredBy}</a></span>\n </div>\n `;\n\n const copyBtn = card.querySelector<HTMLButtonElement>('[data-action=\"copy\"]');\n if (copyBtn) {\n copyBtn.addEventListener('click', async () => {\n const ok = await copyToClipboard({ text: quote.text, author: quote.author });\n if (ok) {\n const label = copyBtn.querySelector('.ds-share-label');\n const originalLabel = label?.textContent ?? '';\n if (label) label.textContent = s.copied;\n copyBtn.classList.add('ds-toast');\n setTimeout(() => {\n if (label) label.textContent = originalLabel;\n copyBtn.classList.remove('ds-toast');\n }, 2000);\n }\n });\n }\n}\n\nfunction renderError(card: HTMLElement, lang: Lang, theme: ResolvedTheme) {\n card.className = `ds-card ds-${theme}`;\n const s = t(lang);\n card.innerHTML = `<p class=\"ds-error\">${escape(s.loadFailed)}</p>`;\n}\n\nasync function fetchSchedule(scheduleUrl: string, lang: Lang): Promise<Schedule | null> {\n const base = scheduleUrl.replace(/\\/$/, '');\n const url = `${base}/schedule-${lang}.json`;\n try {\n const init: RequestInit = base === '' ? { credentials: 'omit' } : { credentials: 'omit', mode: 'cors' };\n const res = await fetch(url, init);\n if (!res.ok) return null;\n return (await res.json()) as Schedule;\n } catch {\n return null;\n }\n}\n\nfunction pickQuote(schedule: Schedule): Quote | null {\n const today = todayUtc8();\n const id = schedule.entries[today];\n if (id && schedule.quotes[id]) return schedule.quotes[id];\n const fallbackId = Object.keys(schedule.quotes).sort()[0];\n if (fallbackId && schedule.quotes[fallbackId]) {\n console.warn('[daily-soup] today entry missing or stale, falling back to first quote');\n return schedule.quotes[fallbackId];\n }\n return null;\n}\n\nfunction applyThemeOverrides(card: HTMLElement, config: ThemeConfig, maxWidth?: string) {\n const colors = getThemeColors(config);\n if (colors) {\n if (colors.bg) card.style.setProperty('--ds-bg', colors.bg);\n if (colors.ink) card.style.setProperty('--ds-fg', colors.ink);\n if (colors.muted) card.style.setProperty('--ds-muted', colors.muted);\n if (colors.border) card.style.setProperty('--ds-border', colors.border);\n if (colors.accent) card.style.setProperty('--ds-accent', colors.accent);\n }\n if (maxWidth) card.style.setProperty('--ds-max-width', maxWidth);\n}\n\nexport function mount(host: HTMLElement, options: MountOptions = {}): MountHandle {\n const lang: Lang = options.lang ?? 'zh';\n const themeConfig: ThemeConfig = options.theme ?? 'auto';\n const scheduleUrl = options.scheduleUrl === undefined ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;\n const maxWidth = options.maxWidth;\n\n let resolvedTheme = resolveTheme(themeConfig);\n const root = attachRoot(host);\n if (root === host) {\n // light DOM fallback \u2014 clear any prior content\n host.textContent = '';\n } else {\n while ((root as ShadowRoot).firstChild) (root as ShadowRoot).removeChild((root as ShadowRoot).firstChild!);\n }\n injectStyles(root);\n\n const card = buildSkeleton(resolvedTheme);\n applyThemeOverrides(card, themeConfig, maxWidth);\n root.appendChild(card);\n\n const state: WidgetState = {\n lang,\n themeConfig,\n scheduleUrl,\n host,\n root,\n cardEl: card,\n unwatchTheme: () => {},\n };\n\n if (themeConfig === 'auto') {\n state.unwatchTheme = watchSystemTheme((t) => {\n resolvedTheme = t;\n state.cardEl.classList.remove('ds-light', 'ds-dark');\n state.cardEl.classList.add(`ds-${t}`);\n });\n }\n\n let cancelled = false;\n let retried = false;\n\n const load = async () => {\n const schedule = await fetchSchedule(scheduleUrl, lang);\n if (cancelled) return;\n if (!schedule) {\n if (!retried) {\n retried = true;\n setTimeout(load, 2000);\n return;\n }\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n const quote = pickQuote(schedule);\n if (!quote) {\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n renderQuote(state.cardEl, quote, lang, resolvedTheme);\n };\n load();\n\n return {\n destroy() {\n cancelled = true;\n state.unwatchTheme();\n if (root === host) {\n host.textContent = '';\n } else if (host.shadowRoot) {\n while (host.shadowRoot.firstChild) host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n }\n },\n };\n}\n\nexport function mountAll(selector = '[data-daily-soup], #daily-soup'): MountHandle[] {\n if (typeof document === 'undefined') return [];\n const nodes = document.querySelectorAll<HTMLElement>(selector);\n const handles: MountHandle[] = [];\n nodes.forEach((node) => {\n const lang = (node.dataset.lang as Lang | undefined) ?? 'zh';\n const theme = (node.dataset.theme as 'auto' | 'light' | 'dark' | undefined) ?? 'auto';\n const scheduleUrl = node.dataset.scheduleUrl;\n const maxWidth = node.dataset.maxWidth;\n handles.push(mount(node, { lang, theme, scheduleUrl, maxWidth }));\n });\n return handles;\n}\n", "import { useEffect, useRef } from 'react';\nimport { mount } from './widget';\nimport type { DailySoupProps } from './types';\n\nexport function DailySoup({ lang = 'zh', theme = 'auto', scheduleUrl, className, maxWidth }: DailySoupProps) {\n const hostRef = useRef<HTMLDivElement | null>(null);\n\n const themeKey = typeof theme === 'string' ? theme : JSON.stringify(theme);\n useEffect(() => {\n if (!hostRef.current) return;\n const handle = mount(hostRef.current, { lang, theme, scheduleUrl, maxWidth });\n return () => handle.destroy();\n }, [lang, themeKey, scheduleUrl, maxWidth]);\n\n return <div ref={hostRef} className={className} data-daily-soup-host=\"\" />;\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["t"]
7
7
  }
package/dist/embed.js CHANGED
@@ -1,17 +1,17 @@
1
- "use strict";var DailySoup=(()=>{var b=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var N=Object.getOwnPropertyNames;var B=Object.prototype.hasOwnProperty;var u=(e,t)=>()=>(e&&(t=e(e=0)),t);var S=(e,t)=>{for(var n in t)b(e,n,{get:t[n],enumerable:!0})},F=(e,t,n,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of N(t))!B.call(e,o)&&o!==n&&b(e,o,{get:()=>t[o],enumerable:!(r=_(t,o))||r.enumerable});return e};var P=e=>F(b({},"__esModule",{value:!0}),e);function y(e){return x[e]??x.zh}var x,T=u(()=>{"use strict";x={zh:{copy:"\u8907\u88FD",copied:"\u5DF2\u8907\u88FD",share:"\u5206\u4EAB",source:"\u51FA\u8655",poweredBy:"\u7531 mshmwr \u63D0\u4F9B",attributedPopular:"\u50B3\u7D71\u6B78\u5C6C",shareX:"\u5206\u4EAB\u5230 X",shareLine:"\u5206\u4EAB\u5230 LINE",loadFailed:"\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557"},en:{copy:"Copy",copied:"Copied!",share:"Share",source:"Source",poweredBy:"powered by mshmwr",attributedPopular:"popularly attributed",shareX:"Share on X",shareLine:"Share on LINE",loadFailed:"Failed to load daily quote"}}});function L(e){return e==="light"||e==="dark"?e:typeof window>"u"||!window.matchMedia?"light":window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function C(e){if(typeof window>"u"||!window.matchMedia)return()=>{};let t=window.matchMedia("(prefers-color-scheme: dark)"),n=r=>e(r.matches?"dark":"light");return t.addEventListener("change",n),()=>t.removeEventListener("change",n)}var E=u(()=>{"use strict"});async function k(e){let t=`${e.text} \u2014 ${e.author}`;if(typeof navigator<"u"&&navigator.clipboard)try{return await navigator.clipboard.writeText(t),!0}catch{return!1}return!1}function M(e){let t=encodeURIComponent(`${e.text} \u2014 ${e.author}`),n=encodeURIComponent($);return`https://twitter.com/intent/tweet?text=${t}&url=${n}`}function R(e){return`https://social-plugins.line.me/lineit/share?url=${encodeURIComponent(`${$} \u2014 ${e.text}`)}`}var $,U=u(()=>{"use strict";$="https://daily-soup-widget.vercel.app"});var H,D=u(()=>{"use strict";H=`
1
+ "use strict";var DailySoup=(()=>{var b=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var F=Object.prototype.hasOwnProperty;var c=(e,t)=>()=>(e&&(t=e(e=0)),t);var T=(e,t)=>{for(var o in t)b(e,o,{get:t[o],enumerable:!0})},j=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of B(t))!F.call(e,n)&&n!==o&&b(e,n,{get:()=>t[n],enumerable:!(r=N(t,n))||r.enumerable});return e};var O=e=>j(b({},"__esModule",{value:!0}),e);function y(e){return S[e]??S.zh}var S,L=c(()=>{"use strict";S={zh:{copy:"\u8907\u88FD",copied:"\u5DF2\u8907\u88FD",share:"\u5206\u4EAB",source:"\u51FA\u8655",poweredBy:"\u7531 mshmwr \u63D0\u4F9B",attributedPopular:"\u50B3\u7D71\u6B78\u5C6C",shareX:"\u5206\u4EAB\u5230 X",shareLine:"\u5206\u4EAB\u5230 LINE",loadFailed:"\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557"},en:{copy:"Copy",copied:"Copied!",share:"Share",source:"Source",poweredBy:"powered by mshmwr",attributedPopular:"popularly attributed",shareX:"Share on X",shareLine:"Share on LINE",loadFailed:"Failed to load daily quote"}}});function C(e){return typeof e=="object"&&e!==null}function E(e){return C(e)?e.base??"light":e==="light"||e==="dark"?e:typeof window>"u"||!window.matchMedia?"light":window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function k(e){return C(e)?e:null}function $(e){if(typeof window>"u"||!window.matchMedia)return()=>{};let t=window.matchMedia("(prefers-color-scheme: dark)"),o=r=>e(r.matches?"dark":"light");return t.addEventListener("change",o),()=>t.removeEventListener("change",o)}var M=c(()=>{"use strict"});async function U(e){let t=`${e.text} \u2014 ${e.author}`;if(typeof navigator<"u"&&navigator.clipboard)try{return await navigator.clipboard.writeText(t),!0}catch{return!1}return!1}function H(e){let t=encodeURIComponent(`${e.text} \u2014 ${e.author}`),o=encodeURIComponent(R);return`https://twitter.com/intent/tweet?text=${t}&url=${o}`}function D(e){return`https://social-plugins.line.me/lineit/share?url=${encodeURIComponent(`${R} \u2014 ${e.text}`)}`}var R,z=c(()=>{"use strict";R="https://daily-soup-widget.vercel.app"});var q,I=c(()=>{"use strict";q=`
2
2
  :host { all: initial; display: block; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans TC", sans-serif; }
3
3
  * { box-sizing: border-box; }
4
4
  .ds-card {
5
5
  container-type: inline-size;
6
6
  width: 100%;
7
- max-width: 32rem;
7
+ max-width: var(--ds-max-width, 32rem);
8
8
  margin: 0 auto;
9
9
  padding: 1.25rem 1.5rem;
10
10
  border-radius: 0.75rem;
11
11
  border: 1px solid var(--ds-border);
12
12
  background: var(--ds-bg);
13
13
  color: var(--ds-fg);
14
- font-size: clamp(0.875rem, 2.5cqi, 1.125rem);
14
+ font-size: clamp(0.875rem, 2.5cqi, 1.25rem);
15
15
  line-height: 1.7;
16
16
  transition: background 0.2s ease, color 0.2s ease;
17
17
  }
@@ -79,32 +79,39 @@
79
79
  }
80
80
  @container (min-width: 500px) {
81
81
  .ds-quote { font-size: 1.25em; }
82
+ .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }
83
+ }
84
+ @container (min-width: 700px) {
85
+ .ds-card { padding: 1.75rem 2rem; }
86
+ .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }
87
+ .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }
88
+ .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }
82
89
  }
83
90
  @media (prefers-reduced-motion: reduce) {
84
91
  .ds-card, .ds-btn { transition: none; }
85
92
  }
86
- `});function z(e=new Date){let t=new Date(e.getTime()+288e5),n=t.getUTCFullYear(),r=String(t.getUTCMonth()+1).padStart(2,"0"),o=String(t.getUTCDate()).padStart(2,"0");return`${n}-${r}-${o}`}var I=u(()=>{"use strict"});var A={};S(A,{mount:()=>f,mountAll:()=>p});function a(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function W(e){return typeof e.attachShadow=="function"?e.shadowRoot?e.shadowRoot:e.attachShadow({mode:"open"}):(console.warn("[daily-soup] attachShadow unsupported, falling back to light DOM"),e)}function j(e){let t=document.createElement("style");t.textContent=H,e.appendChild(t)}function O(e){let t=document.createElement("div");return t.className=`ds-card ds-${e} ds-skeleton`,t.innerHTML=`
93
+ `});function P(e=new Date){let t=new Date(e.getTime()+288e5),o=t.getUTCFullYear(),r=String(t.getUTCMonth()+1).padStart(2,"0"),n=String(t.getUTCDate()).padStart(2,"0");return`${o}-${r}-${n}`}var A=c(()=>{"use strict"});var X={};T(X,{mount:()=>f,mountAll:()=>p});function d(e){return e.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function G(e){return typeof e.attachShadow=="function"?e.shadowRoot?e.shadowRoot:e.attachShadow({mode:"open"}):(console.warn("[daily-soup] attachShadow unsupported, falling back to light DOM"),e)}function Y(e){let t=document.createElement("style");t.textContent=q,e.appendChild(t)}function J(e){let t=document.createElement("div");return t.className=`ds-card ds-${e} ds-skeleton`,t.innerHTML=`
87
94
  <div class="ds-quote">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
88
95
  <div class="ds-meta"><span class="ds-author">&nbsp;</span><span class="ds-source">&nbsp;</span></div>
89
- `,t}function G(e,t,n,r){let o=y(n);e.className=`ds-card ds-${r}`;let s=t.sourceUrl?`<a href="${a(t.sourceUrl)}" target="_blank" rel="noopener noreferrer">${a(t.source)}</a>`:a(t.source),d=t.attribution==="popular-attribution"?`<span class="ds-flag">${a(o.attributedPopular)}</span>`:"";e.innerHTML=`
90
- <p class="ds-quote">${a(t.text)}</p>
96
+ `,t}function K(e,t,o,r){let n=y(o);e.className=`ds-card ds-${r}`;let l=t.sourceUrl?`<a href="${d(t.sourceUrl)}" target="_blank" rel="noopener noreferrer">${d(t.source)}</a>`:d(t.source),i=t.attribution==="popular-attribution"?`<span class="ds-flag">${d(n.attributedPopular)}</span>`:"";e.innerHTML=`
97
+ <p class="ds-quote">${d(t.text)}</p>
91
98
  <div class="ds-meta">
92
- <span class="ds-author">\u2014 ${a(t.author)}${d}</span>
93
- ${t.source?`<span class="ds-source">${o.source}\uFF1A${s}</span>`:""}
99
+ <span class="ds-author">\u2014 ${d(t.author)}${i}</span>
100
+ ${t.source?`<span class="ds-source">${n.source}\uFF1A${l}</span>`:""}
94
101
  </div>
95
102
  <div class="ds-actions">
96
103
  <div class="ds-share">
97
- <button class="ds-btn" data-action="copy" type="button" aria-label="${a(o.copy)}">
98
- <span aria-hidden="true">\u29C9</span><span class="ds-share-label">${a(o.copy)}</span>
104
+ <button class="ds-btn" data-action="copy" type="button" aria-label="${d(n.copy)}">
105
+ <span aria-hidden="true">\u29C9</span><span class="ds-share-label">${d(n.copy)}</span>
99
106
  </button>
100
- <a class="ds-btn" data-action="x" href="${a(M({text:t.text,author:t.author}))}" target="_blank" rel="noopener noreferrer" aria-label="${a(o.shareX)}">
107
+ <a class="ds-btn" data-action="x" href="${d(H({text:t.text,author:t.author}))}" target="_blank" rel="noopener noreferrer" aria-label="${d(n.shareX)}">
101
108
  <span aria-hidden="true">\u{1D54F}</span><span class="ds-share-label">X</span>
102
109
  </a>
103
- <a class="ds-btn" data-action="line" href="${a(R({text:t.text,author:t.author}))}" target="_blank" rel="noopener noreferrer" aria-label="${a(o.shareLine)}">
110
+ <a class="ds-btn" data-action="line" href="${d(D({text:t.text,author:t.author}))}" target="_blank" rel="noopener noreferrer" aria-label="${d(n.shareLine)}">
104
111
  <span aria-hidden="true">L</span><span class="ds-share-label">LINE</span>
105
112
  </a>
106
113
  </div>
107
- <span class="ds-powered"><a href="https://personal-site-mocha-chi.vercel.app" target="_blank" rel="noopener noreferrer">${o.poweredBy}</a></span>
114
+ <span class="ds-powered"><a href="https://personal-site-mocha-chi.vercel.app" target="_blank" rel="noopener noreferrer">${n.poweredBy}</a></span>
108
115
  </div>
109
- `;let i=e.querySelector('[data-action="copy"]');i&&i.addEventListener("click",async()=>{if(await k({text:t.text,author:t.author})){let c=i.querySelector(".ds-share-label"),h=c?.textContent??"";c&&(c.textContent=o.copied),i.classList.add("ds-toast"),setTimeout(()=>{c&&(c.textContent=h),i.classList.remove("ds-toast")},2e3)}})}function q(e,t,n){e.className=`ds-card ds-${n}`;let r=y(t);e.innerHTML=`<p class="ds-error">${a(r.loadFailed)}</p>`}async function Y(e,t){let n=e.replace(/\/$/,""),r=`${n}/schedule-${t}.json`;try{let s=await fetch(r,n===""?{credentials:"omit"}:{credentials:"omit",mode:"cors"});return s.ok?await s.json():null}catch{return null}}function J(e){let t=z(),n=e.entries[t];if(n&&e.quotes[n])return e.quotes[n];let r=Object.keys(e.quotes).sort()[0];return r&&e.quotes[r]?(console.warn("[daily-soup] today entry missing or stale, falling back to first quote"),e.quotes[r]):null}function f(e,t={}){let n=t.lang??"zh",r=t.theme??"auto",o=t.scheduleUrl===void 0?Q:t.scheduleUrl,s=L(r),d=W(e);if(d===e)e.textContent="";else for(;d.firstChild;)d.removeChild(d.firstChild);j(d);let i=O(s);d.appendChild(i);let l={lang:n,themeConfig:r,scheduleUrl:o,host:e,root:d,cardEl:i,unwatchTheme:()=>{}};r==="auto"&&(l.unwatchTheme=C(m=>{s=m,l.cardEl.classList.remove("ds-light","ds-dark"),l.cardEl.classList.add(`ds-${m}`)}));let c=!1,h=!1,w=async()=>{let m=await Y(o,n);if(c)return;if(!m){if(!h){h=!0,setTimeout(w,2e3);return}q(l.cardEl,n,s);return}let v=J(m);if(!v){q(l.cardEl,n,s);return}G(l.cardEl,v,n,s)};return w(),{destroy(){if(c=!0,l.unwatchTheme(),d===e)e.textContent="";else if(e.shadowRoot)for(;e.shadowRoot.firstChild;)e.shadowRoot.removeChild(e.shadowRoot.firstChild)}}}function p(e="[data-daily-soup], #daily-soup"){if(typeof document>"u")return[];let t=document.querySelectorAll(e),n=[];return t.forEach(r=>{let o=r.dataset.lang??"zh",s=r.dataset.theme??"auto",d=r.dataset.scheduleUrl;n.push(f(r,{lang:o,theme:s,scheduleUrl:d}))}),n}var Q,g=u(()=>{"use strict";T();E();U();D();I();Q="https://daily-soup-widget.vercel.app"});var K={};S(K,{mount:()=>f,mountAll:()=>p});g();g();function X(){let e=p();return typeof window<"u"&&(window.DailySoup=window.DailySoup??{},Promise.resolve().then(()=>(g(),A)).then(({mount:t})=>{window.DailySoup&&(window.DailySoup.mount=t,window.DailySoup.mountAll=p)})),e}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",X,{once:!0}):X());return P(K);})();
116
+ `;let a=e.querySelector('[data-action="copy"]');a&&a.addEventListener("click",async()=>{if(await U({text:t.text,author:t.author})){let s=a.querySelector(".ds-share-label"),h=s?.textContent??"";s&&(s.textContent=n.copied),a.classList.add("ds-toast"),setTimeout(()=>{s&&(s.textContent=h),a.classList.remove("ds-toast")},2e3)}})}function W(e,t,o){e.className=`ds-card ds-${o}`;let r=y(t);e.innerHTML=`<p class="ds-error">${d(r.loadFailed)}</p>`}async function V(e,t){let o=e.replace(/\/$/,""),r=`${o}/schedule-${t}.json`;try{let l=await fetch(r,o===""?{credentials:"omit"}:{credentials:"omit",mode:"cors"});return l.ok?await l.json():null}catch{return null}}function Z(e){let t=P(),o=e.entries[t];if(o&&e.quotes[o])return e.quotes[o];let r=Object.keys(e.quotes).sort()[0];return r&&e.quotes[r]?(console.warn("[daily-soup] today entry missing or stale, falling back to first quote"),e.quotes[r]):null}function ee(e,t,o){let r=k(t);r&&(r.bg&&e.style.setProperty("--ds-bg",r.bg),r.ink&&e.style.setProperty("--ds-fg",r.ink),r.muted&&e.style.setProperty("--ds-muted",r.muted),r.border&&e.style.setProperty("--ds-border",r.border),r.accent&&e.style.setProperty("--ds-accent",r.accent)),o&&e.style.setProperty("--ds-max-width",o)}function f(e,t={}){let o=t.lang??"zh",r=t.theme??"auto",n=t.scheduleUrl===void 0?Q:t.scheduleUrl,l=t.maxWidth,i=E(r),a=G(e);if(a===e)e.textContent="";else for(;a.firstChild;)a.removeChild(a.firstChild);Y(a);let m=J(i);ee(m,r,l),a.appendChild(m);let s={lang:o,themeConfig:r,scheduleUrl:n,host:e,root:a,cardEl:m,unwatchTheme:()=>{}};r==="auto"&&(s.unwatchTheme=$(u=>{i=u,s.cardEl.classList.remove("ds-light","ds-dark"),s.cardEl.classList.add(`ds-${u}`)}));let h=!1,w=!1,v=async()=>{let u=await V(n,o);if(h)return;if(!u){if(!w){w=!0,setTimeout(v,2e3);return}W(s.cardEl,o,i);return}let x=Z(u);if(!x){W(s.cardEl,o,i);return}K(s.cardEl,x,o,i)};return v(),{destroy(){if(h=!0,s.unwatchTheme(),a===e)e.textContent="";else if(e.shadowRoot)for(;e.shadowRoot.firstChild;)e.shadowRoot.removeChild(e.shadowRoot.firstChild)}}}function p(e="[data-daily-soup], #daily-soup"){if(typeof document>"u")return[];let t=document.querySelectorAll(e),o=[];return t.forEach(r=>{let n=r.dataset.lang??"zh",l=r.dataset.theme??"auto",i=r.dataset.scheduleUrl,a=r.dataset.maxWidth;o.push(f(r,{lang:n,theme:l,scheduleUrl:i,maxWidth:a}))}),o}var Q,g=c(()=>{"use strict";L();M();z();I();A();Q="https://daily-soup-widget.vercel.app"});var te={};T(te,{mount:()=>f,mountAll:()=>p});g();g();function _(){let e=p();return typeof window<"u"&&(window.DailySoup=window.DailySoup??{},Promise.resolve().then(()=>(g(),X)).then(({mount:t})=>{window.DailySoup&&(window.DailySoup.mount=t,window.DailySoup.mountAll=p)})),e}typeof document<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",_,{once:!0}):_());return O(te);})();
110
117
  //# sourceMappingURL=embed.js.map
package/dist/embed.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/i18n.ts", "../src/theme.ts", "../src/share.ts", "../src/styles.ts", "../src/date.ts", "../src/widget.ts", "../src/embed.ts"],
4
- "sourcesContent": ["import type { Lang } from './types';\n\ninterface UiStrings {\n copy: string;\n copied: string;\n share: string;\n source: string;\n poweredBy: string;\n attributedPopular: string;\n shareX: string;\n shareLine: string;\n loadFailed: string;\n}\n\nconst STRINGS: Record<Lang, UiStrings> = {\n zh: {\n copy: '\u8907\u88FD',\n copied: '\u5DF2\u8907\u88FD',\n share: '\u5206\u4EAB',\n source: '\u51FA\u8655',\n poweredBy: '\u7531 mshmwr \u63D0\u4F9B',\n attributedPopular: '\u50B3\u7D71\u6B78\u5C6C',\n shareX: '\u5206\u4EAB\u5230 X',\n shareLine: '\u5206\u4EAB\u5230 LINE',\n loadFailed: '\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557',\n },\n en: {\n copy: 'Copy',\n copied: 'Copied!',\n share: 'Share',\n source: 'Source',\n poweredBy: 'powered by mshmwr',\n attributedPopular: 'popularly attributed',\n shareX: 'Share on X',\n shareLine: 'Share on LINE',\n loadFailed: 'Failed to load daily quote',\n },\n};\n\nexport function t(lang: Lang): UiStrings {\n return STRINGS[lang] ?? STRINGS.zh;\n}\n\nexport type { UiStrings };\n", "import type { ThemeConfig, ResolvedTheme } from './types';\n\nexport function resolveTheme(config: ThemeConfig): ResolvedTheme {\n if (config === 'light' || config === 'dark') return config;\n if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\nexport function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => cb(e.matches ? 'dark' : 'light');\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n}\n", "const SHARE_URL = 'https://daily-soup-widget.vercel.app';\n\nexport interface ShareContent {\n text: string;\n author: string;\n}\n\nexport async function copyToClipboard(content: ShareContent): Promise<boolean> {\n const payload = `${content.text} \u2014 ${content.author}`;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n try {\n await navigator.clipboard.writeText(payload);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n}\n\nexport function buildXShareUrl(content: ShareContent): string {\n const text = encodeURIComponent(`${content.text} \u2014 ${content.author}`);\n const url = encodeURIComponent(SHARE_URL);\n return `https://twitter.com/intent/tweet?text=${text}&url=${url}`;\n}\n\nexport function buildLineShareUrl(content: ShareContent): string {\n const url = encodeURIComponent(`${SHARE_URL} \u2014 ${content.text}`);\n return `https://social-plugins.line.me/lineit/share?url=${url}`;\n}\n", "export const WIDGET_STYLES = `\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: 32rem;\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.125rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n`;\n", "export function todayUtc8(now: Date = new Date()): string {\n const utc8 = new Date(now.getTime() + 8 * 60 * 60 * 1000);\n const yy = utc8.getUTCFullYear();\n const mm = String(utc8.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(utc8.getUTCDate()).padStart(2, '0');\n return `${yy}-${mm}-${dd}`;\n}\n", "import type { Lang, MountOptions, Quote, ResolvedTheme, Schedule, ThemeConfig } from './types';\nimport { t } from './i18n';\nimport { resolveTheme, watchSystemTheme } from './theme';\nimport { buildLineShareUrl, buildXShareUrl, copyToClipboard } from './share';\nimport { WIDGET_STYLES } from './styles';\nimport { todayUtc8 } from './date';\n\nconst DEFAULT_SCHEDULE_BASE = 'https://daily-soup-widget.vercel.app';\n\nexport interface MountHandle {\n destroy(): void;\n}\n\ninterface WidgetState {\n lang: Lang;\n themeConfig: ThemeConfig;\n scheduleUrl: string;\n host: HTMLElement;\n root: ShadowRoot | HTMLElement;\n cardEl: HTMLElement;\n unwatchTheme: () => void;\n}\n\nfunction escape(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction attachRoot(host: HTMLElement): ShadowRoot | HTMLElement {\n if (typeof host.attachShadow === 'function') {\n if (host.shadowRoot) return host.shadowRoot;\n return host.attachShadow({ mode: 'open' });\n }\n console.warn('[daily-soup] attachShadow unsupported, falling back to light DOM');\n return host;\n}\n\nfunction injectStyles(root: ShadowRoot | HTMLElement) {\n const style = document.createElement('style');\n style.textContent = WIDGET_STYLES;\n root.appendChild(style);\n}\n\nfunction buildSkeleton(theme: ResolvedTheme): HTMLElement {\n const card = document.createElement('div');\n card.className = `ds-card ds-${theme} ds-skeleton`;\n card.innerHTML = `\n <div class=\"ds-quote\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>\n <div class=\"ds-meta\"><span class=\"ds-author\">&nbsp;</span><span class=\"ds-source\">&nbsp;</span></div>\n `;\n return card;\n}\n\nfunction renderQuote(card: HTMLElement, quote: Quote, lang: Lang, theme: ResolvedTheme) {\n const s = t(lang);\n card.className = `ds-card ds-${theme}`;\n const sourceLabel = quote.sourceUrl\n ? `<a href=\"${escape(quote.sourceUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escape(quote.source)}</a>`\n : escape(quote.source);\n const flag = quote.attribution === 'popular-attribution'\n ? `<span class=\"ds-flag\">${escape(s.attributedPopular)}</span>`\n : '';\n card.innerHTML = `\n <p class=\"ds-quote\">${escape(quote.text)}</p>\n <div class=\"ds-meta\">\n <span class=\"ds-author\">\u2014 ${escape(quote.author)}${flag}</span>\n ${quote.source ? `<span class=\"ds-source\">${s.source}\uFF1A${sourceLabel}</span>` : ''}\n </div>\n <div class=\"ds-actions\">\n <div class=\"ds-share\">\n <button class=\"ds-btn\" data-action=\"copy\" type=\"button\" aria-label=\"${escape(s.copy)}\">\n <span aria-hidden=\"true\">\u29C9</span><span class=\"ds-share-label\">${escape(s.copy)}</span>\n </button>\n <a class=\"ds-btn\" data-action=\"x\" href=\"${escape(buildXShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareX)}\">\n <span aria-hidden=\"true\">\uD835\uDD4F</span><span class=\"ds-share-label\">X</span>\n </a>\n <a class=\"ds-btn\" data-action=\"line\" href=\"${escape(buildLineShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareLine)}\">\n <span aria-hidden=\"true\">L</span><span class=\"ds-share-label\">LINE</span>\n </a>\n </div>\n <span class=\"ds-powered\"><a href=\"https://personal-site-mocha-chi.vercel.app\" target=\"_blank\" rel=\"noopener noreferrer\">${s.poweredBy}</a></span>\n </div>\n `;\n\n const copyBtn = card.querySelector<HTMLButtonElement>('[data-action=\"copy\"]');\n if (copyBtn) {\n copyBtn.addEventListener('click', async () => {\n const ok = await copyToClipboard({ text: quote.text, author: quote.author });\n if (ok) {\n const label = copyBtn.querySelector('.ds-share-label');\n const originalLabel = label?.textContent ?? '';\n if (label) label.textContent = s.copied;\n copyBtn.classList.add('ds-toast');\n setTimeout(() => {\n if (label) label.textContent = originalLabel;\n copyBtn.classList.remove('ds-toast');\n }, 2000);\n }\n });\n }\n}\n\nfunction renderError(card: HTMLElement, lang: Lang, theme: ResolvedTheme) {\n card.className = `ds-card ds-${theme}`;\n const s = t(lang);\n card.innerHTML = `<p class=\"ds-error\">${escape(s.loadFailed)}</p>`;\n}\n\nasync function fetchSchedule(scheduleUrl: string, lang: Lang): Promise<Schedule | null> {\n const base = scheduleUrl.replace(/\\/$/, '');\n const url = `${base}/schedule-${lang}.json`;\n try {\n const init: RequestInit = base === '' ? { credentials: 'omit' } : { credentials: 'omit', mode: 'cors' };\n const res = await fetch(url, init);\n if (!res.ok) return null;\n return (await res.json()) as Schedule;\n } catch {\n return null;\n }\n}\n\nfunction pickQuote(schedule: Schedule): Quote | null {\n const today = todayUtc8();\n const id = schedule.entries[today];\n if (id && schedule.quotes[id]) return schedule.quotes[id];\n const fallbackId = Object.keys(schedule.quotes).sort()[0];\n if (fallbackId && schedule.quotes[fallbackId]) {\n console.warn('[daily-soup] today entry missing or stale, falling back to first quote');\n return schedule.quotes[fallbackId];\n }\n return null;\n}\n\nexport function mount(host: HTMLElement, options: MountOptions = {}): MountHandle {\n const lang: Lang = options.lang ?? 'zh';\n const themeConfig: ThemeConfig = options.theme ?? 'auto';\n const scheduleUrl = options.scheduleUrl === undefined ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;\n\n let resolvedTheme = resolveTheme(themeConfig);\n const root = attachRoot(host);\n if (root === host) {\n // light DOM fallback \u2014 clear any prior content\n host.textContent = '';\n } else {\n while ((root as ShadowRoot).firstChild) (root as ShadowRoot).removeChild((root as ShadowRoot).firstChild!);\n }\n injectStyles(root);\n\n const card = buildSkeleton(resolvedTheme);\n root.appendChild(card);\n\n const state: WidgetState = {\n lang,\n themeConfig,\n scheduleUrl,\n host,\n root,\n cardEl: card,\n unwatchTheme: () => {},\n };\n\n if (themeConfig === 'auto') {\n state.unwatchTheme = watchSystemTheme((t) => {\n resolvedTheme = t;\n state.cardEl.classList.remove('ds-light', 'ds-dark');\n state.cardEl.classList.add(`ds-${t}`);\n });\n }\n\n let cancelled = false;\n let retried = false;\n\n const load = async () => {\n const schedule = await fetchSchedule(scheduleUrl, lang);\n if (cancelled) return;\n if (!schedule) {\n if (!retried) {\n retried = true;\n setTimeout(load, 2000);\n return;\n }\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n const quote = pickQuote(schedule);\n if (!quote) {\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n renderQuote(state.cardEl, quote, lang, resolvedTheme);\n };\n load();\n\n return {\n destroy() {\n cancelled = true;\n state.unwatchTheme();\n if (root === host) {\n host.textContent = '';\n } else if (host.shadowRoot) {\n while (host.shadowRoot.firstChild) host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n }\n },\n };\n}\n\nexport function mountAll(selector = '[data-daily-soup], #daily-soup'): MountHandle[] {\n if (typeof document === 'undefined') return [];\n const nodes = document.querySelectorAll<HTMLElement>(selector);\n const handles: MountHandle[] = [];\n nodes.forEach((node) => {\n const lang = (node.dataset.lang as Lang | undefined) ?? 'zh';\n const theme = (node.dataset.theme as ThemeConfig | undefined) ?? 'auto';\n const scheduleUrl = node.dataset.scheduleUrl;\n handles.push(mount(node, { lang, theme, scheduleUrl }));\n });\n return handles;\n}\n", "import { mountAll } from './widget';\n\ndeclare global {\n interface Window {\n DailySoup?: { mount: typeof import('./widget').mount; mountAll: typeof mountAll };\n }\n}\n\nfunction init() {\n const handles = mountAll();\n if (typeof window !== 'undefined') {\n window.DailySoup = window.DailySoup ?? ({} as Window['DailySoup']);\n // expose mount + mountAll for advanced consumers\n import('./widget').then(({ mount }) => {\n if (window.DailySoup) {\n window.DailySoup.mount = mount;\n window.DailySoup.mountAll = mountAll;\n }\n });\n }\n return handles;\n}\n\nif (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init, { once: true });\n } else {\n init();\n }\n}\n\nexport { mount, mountAll } from './widget';\n"],
5
- "mappings": "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",
6
- "names": ["t", "lang", "STRINGS", "init_i18n", "__esmMin", "resolveTheme", "config", "watchSystemTheme", "cb", "mql", "handler", "e", "init_theme", "__esmMin", "copyToClipboard", "content", "payload", "buildXShareUrl", "text", "url", "SHARE_URL", "buildLineShareUrl", "init_share", "__esmMin", "WIDGET_STYLES", "init_styles", "__esmMin", "todayUtc8", "now", "utc8", "yy", "mm", "dd", "init_date", "__esmMin", "widget_exports", "__export", "mount", "mountAll", "escape", "s", "attachRoot", "host", "injectStyles", "root", "style", "WIDGET_STYLES", "buildSkeleton", "theme", "card", "renderQuote", "quote", "lang", "t", "sourceLabel", "flag", "buildXShareUrl", "buildLineShareUrl", "copyBtn", "copyToClipboard", "label", "originalLabel", "renderError", "fetchSchedule", "scheduleUrl", "base", "url", "res", "pickQuote", "schedule", "today", "todayUtc8", "id", "fallbackId", "options", "themeConfig", "DEFAULT_SCHEDULE_BASE", "resolvedTheme", "resolveTheme", "state", "watchSystemTheme", "cancelled", "retried", "load", "selector", "nodes", "handles", "node", "init_widget", "__esmMin", "init_i18n", "init_theme", "init_share", "init_styles", "init_date", "embed_exports", "__export", "mount", "mountAll", "init_widget", "init", "handles"]
4
+ "sourcesContent": ["import type { Lang } from './types';\n\ninterface UiStrings {\n copy: string;\n copied: string;\n share: string;\n source: string;\n poweredBy: string;\n attributedPopular: string;\n shareX: string;\n shareLine: string;\n loadFailed: string;\n}\n\nconst STRINGS: Record<Lang, UiStrings> = {\n zh: {\n copy: '\u8907\u88FD',\n copied: '\u5DF2\u8907\u88FD',\n share: '\u5206\u4EAB',\n source: '\u51FA\u8655',\n poweredBy: '\u7531 mshmwr \u63D0\u4F9B',\n attributedPopular: '\u50B3\u7D71\u6B78\u5C6C',\n shareX: '\u5206\u4EAB\u5230 X',\n shareLine: '\u5206\u4EAB\u5230 LINE',\n loadFailed: '\u672C\u65E5\u5C0F\u8A9E\u8F09\u5165\u5931\u6557',\n },\n en: {\n copy: 'Copy',\n copied: 'Copied!',\n share: 'Share',\n source: 'Source',\n poweredBy: 'powered by mshmwr',\n attributedPopular: 'popularly attributed',\n shareX: 'Share on X',\n shareLine: 'Share on LINE',\n loadFailed: 'Failed to load daily quote',\n },\n};\n\nexport function t(lang: Lang): UiStrings {\n return STRINGS[lang] ?? STRINGS.zh;\n}\n\nexport type { UiStrings };\n", "import type { ThemeConfig, ResolvedTheme, ThemeColors } from './types';\n\nfunction isThemeColors(config: ThemeConfig): config is ThemeColors {\n return typeof config === 'object' && config !== null;\n}\n\nexport function resolveTheme(config: ThemeConfig): ResolvedTheme {\n if (isThemeColors(config)) return config.base ?? 'light';\n if (config === 'light' || config === 'dark') return config;\n if (typeof window === 'undefined' || !window.matchMedia) return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';\n}\n\nexport function getThemeColors(config: ThemeConfig): ThemeColors | null {\n return isThemeColors(config) ? config : null;\n}\n\nexport function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void {\n if (typeof window === 'undefined' || !window.matchMedia) return () => {};\n const mql = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) => cb(e.matches ? 'dark' : 'light');\n mql.addEventListener('change', handler);\n return () => mql.removeEventListener('change', handler);\n}\n", "const SHARE_URL = 'https://daily-soup-widget.vercel.app';\n\nexport interface ShareContent {\n text: string;\n author: string;\n}\n\nexport async function copyToClipboard(content: ShareContent): Promise<boolean> {\n const payload = `${content.text} \u2014 ${content.author}`;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n try {\n await navigator.clipboard.writeText(payload);\n return true;\n } catch {\n return false;\n }\n }\n return false;\n}\n\nexport function buildXShareUrl(content: ShareContent): string {\n const text = encodeURIComponent(`${content.text} \u2014 ${content.author}`);\n const url = encodeURIComponent(SHARE_URL);\n return `https://twitter.com/intent/tweet?text=${text}&url=${url}`;\n}\n\nexport function buildLineShareUrl(content: ShareContent): string {\n const url = encodeURIComponent(`${SHARE_URL} \u2014 ${content.text}`);\n return `https://social-plugins.line.me/lineit/share?url=${url}`;\n}\n", "export const WIDGET_STYLES = `\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: var(--ds-max-width, 32rem);\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.25rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }\n }\n @container (min-width: 700px) {\n .ds-card { padding: 1.75rem 2rem; }\n .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }\n .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }\n .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n`;\n", "export function todayUtc8(now: Date = new Date()): string {\n const utc8 = new Date(now.getTime() + 8 * 60 * 60 * 1000);\n const yy = utc8.getUTCFullYear();\n const mm = String(utc8.getUTCMonth() + 1).padStart(2, '0');\n const dd = String(utc8.getUTCDate()).padStart(2, '0');\n return `${yy}-${mm}-${dd}`;\n}\n", "import type { Lang, MountOptions, Quote, ResolvedTheme, Schedule, ThemeConfig } from './types';\nimport { t } from './i18n';\nimport { resolveTheme, watchSystemTheme, getThemeColors } from './theme';\nimport { buildLineShareUrl, buildXShareUrl, copyToClipboard } from './share';\nimport { WIDGET_STYLES } from './styles';\nimport { todayUtc8 } from './date';\n\nconst DEFAULT_SCHEDULE_BASE = 'https://daily-soup-widget.vercel.app';\n\nexport interface MountHandle {\n destroy(): void;\n}\n\ninterface WidgetState {\n lang: Lang;\n themeConfig: ThemeConfig;\n scheduleUrl: string;\n host: HTMLElement;\n root: ShadowRoot | HTMLElement;\n cardEl: HTMLElement;\n unwatchTheme: () => void;\n}\n\nfunction escape(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nfunction attachRoot(host: HTMLElement): ShadowRoot | HTMLElement {\n if (typeof host.attachShadow === 'function') {\n if (host.shadowRoot) return host.shadowRoot;\n return host.attachShadow({ mode: 'open' });\n }\n console.warn('[daily-soup] attachShadow unsupported, falling back to light DOM');\n return host;\n}\n\nfunction injectStyles(root: ShadowRoot | HTMLElement) {\n const style = document.createElement('style');\n style.textContent = WIDGET_STYLES;\n root.appendChild(style);\n}\n\nfunction buildSkeleton(theme: ResolvedTheme): HTMLElement {\n const card = document.createElement('div');\n card.className = `ds-card ds-${theme} ds-skeleton`;\n card.innerHTML = `\n <div class=\"ds-quote\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>\n <div class=\"ds-meta\"><span class=\"ds-author\">&nbsp;</span><span class=\"ds-source\">&nbsp;</span></div>\n `;\n return card;\n}\n\nfunction renderQuote(card: HTMLElement, quote: Quote, lang: Lang, theme: ResolvedTheme) {\n const s = t(lang);\n card.className = `ds-card ds-${theme}`;\n const sourceLabel = quote.sourceUrl\n ? `<a href=\"${escape(quote.sourceUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\">${escape(quote.source)}</a>`\n : escape(quote.source);\n const flag = quote.attribution === 'popular-attribution'\n ? `<span class=\"ds-flag\">${escape(s.attributedPopular)}</span>`\n : '';\n card.innerHTML = `\n <p class=\"ds-quote\">${escape(quote.text)}</p>\n <div class=\"ds-meta\">\n <span class=\"ds-author\">\u2014 ${escape(quote.author)}${flag}</span>\n ${quote.source ? `<span class=\"ds-source\">${s.source}\uFF1A${sourceLabel}</span>` : ''}\n </div>\n <div class=\"ds-actions\">\n <div class=\"ds-share\">\n <button class=\"ds-btn\" data-action=\"copy\" type=\"button\" aria-label=\"${escape(s.copy)}\">\n <span aria-hidden=\"true\">\u29C9</span><span class=\"ds-share-label\">${escape(s.copy)}</span>\n </button>\n <a class=\"ds-btn\" data-action=\"x\" href=\"${escape(buildXShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareX)}\">\n <span aria-hidden=\"true\">\uD835\uDD4F</span><span class=\"ds-share-label\">X</span>\n </a>\n <a class=\"ds-btn\" data-action=\"line\" href=\"${escape(buildLineShareUrl({ text: quote.text, author: quote.author }))}\" target=\"_blank\" rel=\"noopener noreferrer\" aria-label=\"${escape(s.shareLine)}\">\n <span aria-hidden=\"true\">L</span><span class=\"ds-share-label\">LINE</span>\n </a>\n </div>\n <span class=\"ds-powered\"><a href=\"https://personal-site-mocha-chi.vercel.app\" target=\"_blank\" rel=\"noopener noreferrer\">${s.poweredBy}</a></span>\n </div>\n `;\n\n const copyBtn = card.querySelector<HTMLButtonElement>('[data-action=\"copy\"]');\n if (copyBtn) {\n copyBtn.addEventListener('click', async () => {\n const ok = await copyToClipboard({ text: quote.text, author: quote.author });\n if (ok) {\n const label = copyBtn.querySelector('.ds-share-label');\n const originalLabel = label?.textContent ?? '';\n if (label) label.textContent = s.copied;\n copyBtn.classList.add('ds-toast');\n setTimeout(() => {\n if (label) label.textContent = originalLabel;\n copyBtn.classList.remove('ds-toast');\n }, 2000);\n }\n });\n }\n}\n\nfunction renderError(card: HTMLElement, lang: Lang, theme: ResolvedTheme) {\n card.className = `ds-card ds-${theme}`;\n const s = t(lang);\n card.innerHTML = `<p class=\"ds-error\">${escape(s.loadFailed)}</p>`;\n}\n\nasync function fetchSchedule(scheduleUrl: string, lang: Lang): Promise<Schedule | null> {\n const base = scheduleUrl.replace(/\\/$/, '');\n const url = `${base}/schedule-${lang}.json`;\n try {\n const init: RequestInit = base === '' ? { credentials: 'omit' } : { credentials: 'omit', mode: 'cors' };\n const res = await fetch(url, init);\n if (!res.ok) return null;\n return (await res.json()) as Schedule;\n } catch {\n return null;\n }\n}\n\nfunction pickQuote(schedule: Schedule): Quote | null {\n const today = todayUtc8();\n const id = schedule.entries[today];\n if (id && schedule.quotes[id]) return schedule.quotes[id];\n const fallbackId = Object.keys(schedule.quotes).sort()[0];\n if (fallbackId && schedule.quotes[fallbackId]) {\n console.warn('[daily-soup] today entry missing or stale, falling back to first quote');\n return schedule.quotes[fallbackId];\n }\n return null;\n}\n\nfunction applyThemeOverrides(card: HTMLElement, config: ThemeConfig, maxWidth?: string) {\n const colors = getThemeColors(config);\n if (colors) {\n if (colors.bg) card.style.setProperty('--ds-bg', colors.bg);\n if (colors.ink) card.style.setProperty('--ds-fg', colors.ink);\n if (colors.muted) card.style.setProperty('--ds-muted', colors.muted);\n if (colors.border) card.style.setProperty('--ds-border', colors.border);\n if (colors.accent) card.style.setProperty('--ds-accent', colors.accent);\n }\n if (maxWidth) card.style.setProperty('--ds-max-width', maxWidth);\n}\n\nexport function mount(host: HTMLElement, options: MountOptions = {}): MountHandle {\n const lang: Lang = options.lang ?? 'zh';\n const themeConfig: ThemeConfig = options.theme ?? 'auto';\n const scheduleUrl = options.scheduleUrl === undefined ? DEFAULT_SCHEDULE_BASE : options.scheduleUrl;\n const maxWidth = options.maxWidth;\n\n let resolvedTheme = resolveTheme(themeConfig);\n const root = attachRoot(host);\n if (root === host) {\n // light DOM fallback \u2014 clear any prior content\n host.textContent = '';\n } else {\n while ((root as ShadowRoot).firstChild) (root as ShadowRoot).removeChild((root as ShadowRoot).firstChild!);\n }\n injectStyles(root);\n\n const card = buildSkeleton(resolvedTheme);\n applyThemeOverrides(card, themeConfig, maxWidth);\n root.appendChild(card);\n\n const state: WidgetState = {\n lang,\n themeConfig,\n scheduleUrl,\n host,\n root,\n cardEl: card,\n unwatchTheme: () => {},\n };\n\n if (themeConfig === 'auto') {\n state.unwatchTheme = watchSystemTheme((t) => {\n resolvedTheme = t;\n state.cardEl.classList.remove('ds-light', 'ds-dark');\n state.cardEl.classList.add(`ds-${t}`);\n });\n }\n\n let cancelled = false;\n let retried = false;\n\n const load = async () => {\n const schedule = await fetchSchedule(scheduleUrl, lang);\n if (cancelled) return;\n if (!schedule) {\n if (!retried) {\n retried = true;\n setTimeout(load, 2000);\n return;\n }\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n const quote = pickQuote(schedule);\n if (!quote) {\n renderError(state.cardEl, lang, resolvedTheme);\n return;\n }\n renderQuote(state.cardEl, quote, lang, resolvedTheme);\n };\n load();\n\n return {\n destroy() {\n cancelled = true;\n state.unwatchTheme();\n if (root === host) {\n host.textContent = '';\n } else if (host.shadowRoot) {\n while (host.shadowRoot.firstChild) host.shadowRoot.removeChild(host.shadowRoot.firstChild);\n }\n },\n };\n}\n\nexport function mountAll(selector = '[data-daily-soup], #daily-soup'): MountHandle[] {\n if (typeof document === 'undefined') return [];\n const nodes = document.querySelectorAll<HTMLElement>(selector);\n const handles: MountHandle[] = [];\n nodes.forEach((node) => {\n const lang = (node.dataset.lang as Lang | undefined) ?? 'zh';\n const theme = (node.dataset.theme as 'auto' | 'light' | 'dark' | undefined) ?? 'auto';\n const scheduleUrl = node.dataset.scheduleUrl;\n const maxWidth = node.dataset.maxWidth;\n handles.push(mount(node, { lang, theme, scheduleUrl, maxWidth }));\n });\n return handles;\n}\n", "import { mountAll } from './widget';\n\ndeclare global {\n interface Window {\n DailySoup?: { mount: typeof import('./widget').mount; mountAll: typeof mountAll };\n }\n}\n\nfunction init() {\n const handles = mountAll();\n if (typeof window !== 'undefined') {\n window.DailySoup = window.DailySoup ?? ({} as Window['DailySoup']);\n // expose mount + mountAll for advanced consumers\n import('./widget').then(({ mount }) => {\n if (window.DailySoup) {\n window.DailySoup.mount = mount;\n window.DailySoup.mountAll = mountAll;\n }\n });\n }\n return handles;\n}\n\nif (typeof document !== 'undefined') {\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', init, { once: true });\n } else {\n init();\n }\n}\n\nexport { mount, mountAll } from './widget';\n"],
5
+ "mappings": "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",
6
+ "names": ["t", "lang", "STRINGS", "init_i18n", "__esmMin", "isThemeColors", "config", "resolveTheme", "getThemeColors", "watchSystemTheme", "cb", "mql", "handler", "e", "init_theme", "__esmMin", "copyToClipboard", "content", "payload", "buildXShareUrl", "text", "url", "SHARE_URL", "buildLineShareUrl", "init_share", "__esmMin", "WIDGET_STYLES", "init_styles", "__esmMin", "todayUtc8", "now", "utc8", "yy", "mm", "dd", "init_date", "__esmMin", "widget_exports", "__export", "mount", "mountAll", "escape", "s", "attachRoot", "host", "injectStyles", "root", "style", "WIDGET_STYLES", "buildSkeleton", "theme", "card", "renderQuote", "quote", "lang", "t", "sourceLabel", "flag", "buildXShareUrl", "buildLineShareUrl", "copyBtn", "copyToClipboard", "label", "originalLabel", "renderError", "fetchSchedule", "scheduleUrl", "base", "url", "res", "pickQuote", "schedule", "today", "todayUtc8", "id", "fallbackId", "applyThemeOverrides", "config", "maxWidth", "colors", "getThemeColors", "options", "themeConfig", "DEFAULT_SCHEDULE_BASE", "resolvedTheme", "resolveTheme", "state", "watchSystemTheme", "cancelled", "retried", "load", "selector", "nodes", "handles", "node", "init_widget", "__esmMin", "init_i18n", "init_theme", "init_share", "init_styles", "init_date", "embed_exports", "__export", "mount", "mountAll", "init_widget", "init", "handles"]
7
7
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "launchDate": "2026-05-15",
3
- "generatedAt": "2026-05-15T16:40:34.373Z",
3
+ "generatedAt": "2026-05-15T18:27:53.468Z",
4
4
  "lang": "en",
5
5
  "entries": {
6
6
  "2026-05-15": "0002",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "launchDate": "2026-05-15",
3
- "generatedAt": "2026-05-15T16:40:34.372Z",
3
+ "generatedAt": "2026-05-15T18:27:53.467Z",
4
4
  "lang": "zh",
5
5
  "entries": {
6
6
  "2026-05-15": "0001",
@@ -1,2 +1,2 @@
1
1
  import type { DailySoupProps } from './types';
2
- export declare function DailySoup({ lang, theme, scheduleUrl, className }: DailySoupProps): import("react/jsx-runtime").JSX.Element;
2
+ export declare function DailySoup({ lang, theme, scheduleUrl, className, maxWidth }: DailySoupProps): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- export declare const WIDGET_STYLES = "\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: 32rem;\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.125rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n";
1
+ export declare const WIDGET_STYLES = "\n :host { all: initial; display: block; font-family: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Noto Sans TC\", sans-serif; }\n * { box-sizing: border-box; }\n .ds-card {\n container-type: inline-size;\n width: 100%;\n max-width: var(--ds-max-width, 32rem);\n margin: 0 auto;\n padding: 1.25rem 1.5rem;\n border-radius: 0.75rem;\n border: 1px solid var(--ds-border);\n background: var(--ds-bg);\n color: var(--ds-fg);\n font-size: clamp(0.875rem, 2.5cqi, 1.25rem);\n line-height: 1.7;\n transition: background 0.2s ease, color 0.2s ease;\n }\n .ds-card.ds-light {\n --ds-bg: #fdfcf7;\n --ds-fg: #1f2933;\n --ds-accent: #5b6b9e;\n --ds-muted: #6b7280;\n --ds-border: #e5e7eb;\n }\n .ds-card.ds-dark {\n --ds-bg: #1a1d24;\n --ds-fg: #e5e7eb;\n --ds-accent: #9aa9d4;\n --ds-muted: #9ca3af;\n --ds-border: #2d323d;\n }\n .ds-quote {\n margin: 0 0 0.875rem;\n font-size: 1.1em;\n font-weight: 500;\n letter-spacing: 0.01em;\n white-space: pre-wrap;\n }\n .ds-quote::before { content: '\\201C'; margin-right: 0.15em; color: var(--ds-accent); }\n .ds-quote::after { content: '\\201D'; margin-left: 0.15em; color: var(--ds-accent); }\n .ds-meta { display: flex; flex-direction: column; gap: 0.15rem; margin-bottom: 0.875rem; font-size: 0.875em; color: var(--ds-muted); }\n .ds-author { font-weight: 500; color: var(--ds-fg); }\n .ds-source { font-size: 0.95em; }\n .ds-source a { color: var(--ds-accent); text-decoration: none; }\n .ds-source a:hover { text-decoration: underline; }\n .ds-flag { display: inline-block; margin-left: 0.25rem; padding: 0 0.4rem; font-size: 0.75em; border: 1px solid var(--ds-border); border-radius: 9999px; color: var(--ds-muted); }\n .ds-actions { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.875rem; padding-top: 0.875rem; border-top: 1px solid var(--ds-border); }\n .ds-share { display: flex; gap: 0.35rem; }\n .ds-btn {\n appearance: none;\n background: transparent;\n color: var(--ds-fg);\n border: 1px solid var(--ds-border);\n border-radius: 0.5rem;\n padding: 0.3rem 0.7rem;\n font-size: 0.85em;\n font-family: inherit;\n cursor: pointer;\n transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n text-decoration: none;\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .ds-btn:hover { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-btn:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }\n .ds-btn.ds-toast { background: var(--ds-accent); color: var(--ds-bg); border-color: var(--ds-accent); }\n .ds-powered { font-size: 0.75em; color: var(--ds-muted); }\n .ds-powered a { color: var(--ds-muted); text-decoration: none; }\n .ds-powered a:hover { text-decoration: underline; }\n .ds-skeleton .ds-quote { background: var(--ds-border); border-radius: 0.25rem; color: transparent; }\n .ds-skeleton .ds-quote::before, .ds-skeleton .ds-quote::after { content: ''; }\n .ds-error { color: var(--ds-muted); font-size: 0.875em; }\n\n @container (max-width: 320px) {\n .ds-card { padding: 1rem 1.1rem; }\n .ds-share-label { display: none; }\n .ds-actions { flex-wrap: wrap; }\n }\n @container (min-width: 500px) {\n .ds-quote { font-size: 1.25em; }\n .ds-meta { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.75rem; }\n }\n @container (min-width: 700px) {\n .ds-card { padding: 1.75rem 2rem; }\n .ds-quote { font-size: 1.35em; margin-bottom: 1.125rem; }\n .ds-meta { gap: 0.25rem 1rem; margin-bottom: 1.125rem; }\n .ds-actions { margin-top: 1.125rem; padding-top: 1.125rem; }\n }\n @media (prefers-reduced-motion: reduce) {\n .ds-card, .ds-btn { transition: none; }\n }\n";
@@ -1,3 +1,4 @@
1
- import type { ThemeConfig, ResolvedTheme } from './types';
1
+ import type { ThemeConfig, ResolvedTheme, ThemeColors } from './types';
2
2
  export declare function resolveTheme(config: ThemeConfig): ResolvedTheme;
3
+ export declare function getThemeColors(config: ThemeConfig): ThemeColors | null;
3
4
  export declare function watchSystemTheme(cb: (theme: ResolvedTheme) => void): () => void;
@@ -1,5 +1,13 @@
1
1
  export type Lang = 'zh' | 'en';
2
- export type ThemeConfig = 'auto' | 'light' | 'dark';
2
+ export interface ThemeColors {
3
+ base?: 'light' | 'dark';
4
+ bg?: string;
5
+ ink?: string;
6
+ muted?: string;
7
+ border?: string;
8
+ accent?: string;
9
+ }
10
+ export type ThemeConfig = 'auto' | 'light' | 'dark' | ThemeColors;
3
11
  export type ResolvedTheme = 'light' | 'dark';
4
12
  export interface Quote {
5
13
  text: string;
@@ -21,10 +29,12 @@ export interface MountOptions {
21
29
  lang?: Lang;
22
30
  theme?: ThemeConfig;
23
31
  scheduleUrl?: string;
32
+ maxWidth?: string;
24
33
  }
25
34
  export interface DailySoupProps {
26
35
  lang?: Lang;
27
36
  theme?: ThemeConfig;
28
37
  scheduleUrl?: string;
29
38
  className?: string;
39
+ maxWidth?: string;
30
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "daily-soup-widget",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Embeddable daily quote widget — growth-themed, deterministic, copyright-safe. Drop a script tag or npm install.",
5
5
  "keywords": ["widget", "embed", "daily-quote", "shadow-dom", "react", "umd"],
6
6
  "homepage": "https://daily-soup-widget.vercel.app",
@@ -32,7 +32,9 @@
32
32
  "build:schedule": "tsx scripts/build-schedule.ts",
33
33
  "build:bundle": "tsx scripts/build-bundle.ts",
34
34
  "build:types": "tsc -p tsconfig.build.json",
35
- "build": "npm run build:schedule && npm run build:bundle && npm run build:types && next build",
35
+ "build:lib": "npm run build:schedule && npm run build:bundle && npm run build:types",
36
+ "build": "npm run build:lib && next build",
37
+ "prepublishOnly": "npm run build:lib",
36
38
  "dev": "next dev",
37
39
  "start": "next start",
38
40
  "test": "vitest run",