@scalemule/news-publication 0.0.61 → 0.0.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/dist/chunk-3QU6BJVF.js +540 -0
  2. package/dist/chunk-4WVAT5M2.js +213 -0
  3. package/dist/chunk-6SBK3D3B.js +347 -0
  4. package/dist/chunk-CHF3YPDV.js +314 -0
  5. package/dist/chunk-FHRO2Z3F.js +174 -0
  6. package/dist/{chunk-DM4KQNJH.js → chunk-FWEYKWKP.js} +1 -1
  7. package/dist/{chunk-FMCHQI7K.js → chunk-KYUVXEJY.js} +34 -12
  8. package/dist/{chunk-F53CPZQO.js → chunk-Q77T2S7B.js} +1 -1
  9. package/dist/chunk-SKG5C3MS.js +379 -0
  10. package/dist/{chunk-GYYUJYI4.js → chunk-X7AU7DV6.js} +2 -3
  11. package/dist/{chunk-XPOZGZTM.js → chunk-XSAVJJVW.js} +11 -4
  12. package/dist/{chunk-6S5FARL3.js → chunk-XWXPERLK.js} +2 -2
  13. package/dist/cookie-consent-banner.cjs +10 -3
  14. package/dist/cookie-consent-banner.d.cts +1 -1
  15. package/dist/cookie-consent-banner.d.ts +1 -1
  16. package/dist/cookie-consent-banner.js +2 -2
  17. package/dist/cookie-settings-view.cjs +2 -3
  18. package/dist/cookie-settings-view.js +2 -2
  19. package/dist/index.cjs +60 -18
  20. package/dist/index.d.cts +8 -7
  21. package/dist/index.d.ts +8 -7
  22. package/dist/index.js +10 -8
  23. package/dist/meet-view.d.cts +1 -1
  24. package/dist/meet-view.d.ts +1 -1
  25. package/dist/network-bar.js +2 -2
  26. package/dist/network-copyright.js +2 -2
  27. package/dist/network.js +1 -1
  28. package/dist/pets-plugin.js +4 -347
  29. package/dist/{snapshot-DmRw8G_B.d.ts → snapshot-CjP7bSXJ.d.ts} +1 -1
  30. package/dist/snapshot-file.d.cts +2 -2
  31. package/dist/snapshot-file.d.ts +2 -2
  32. package/dist/{snapshot-Dx4Lv-lB.d.cts → snapshot-qj4BeNzB.d.cts} +1 -1
  33. package/dist/toys-forms.cjs +609 -0
  34. package/dist/toys-forms.d.cts +35 -0
  35. package/dist/toys-forms.d.ts +35 -0
  36. package/dist/toys-forms.js +4 -0
  37. package/dist/toys-interactions.cjs +594 -0
  38. package/dist/toys-interactions.d.cts +54 -0
  39. package/dist/toys-interactions.d.ts +54 -0
  40. package/dist/toys-interactions.js +520 -0
  41. package/dist/toys-plugin.cjs +713 -0
  42. package/dist/toys-plugin.d.cts +88 -0
  43. package/dist/toys-plugin.d.ts +88 -0
  44. package/dist/toys-plugin.js +10 -0
  45. package/dist/toys-publication.cjs +437 -0
  46. package/dist/toys-publication.d.cts +26 -0
  47. package/dist/toys-publication.d.ts +26 -0
  48. package/dist/toys-publication.js +72 -0
  49. package/dist/toys-server.cjs +275 -0
  50. package/dist/toys-server.d.cts +28 -0
  51. package/dist/toys-server.d.ts +28 -0
  52. package/dist/toys-server.js +4 -0
  53. package/dist/toys-view.cjs +420 -0
  54. package/dist/toys-view.d.cts +55 -0
  55. package/dist/toys-view.d.ts +55 -0
  56. package/dist/toys-view.js +2 -0
  57. package/dist/toys.cjs +196 -0
  58. package/dist/toys.d.cts +278 -0
  59. package/dist/toys.d.ts +278 -0
  60. package/dist/toys.js +1 -0
  61. package/dist/{types-BJFCWWi0.d.cts → types-DBi49N8m.d.cts} +12 -3
  62. package/dist/{types-BJFCWWi0.d.ts → types-DBi49N8m.d.ts} +12 -3
  63. package/dist/verified-card.cjs +34 -12
  64. package/dist/verified-card.d.cts +1 -1
  65. package/dist/verified-card.d.ts +1 -1
  66. package/dist/verified-card.js +1 -1
  67. package/package.json +41 -4
  68. package/toys.css +823 -0
@@ -0,0 +1,314 @@
1
+ import { safeToyLink, toyOptionLabel, TOY_AGE_RANGES, TOY_CONDITIONS, TOY_CATEGORIES, hoursSummary, TOY_HOW_IT_WORKS, TOY_SAFETY, TOY_EXCLUSIONS, TOY_BRAND, TOY_STATUS_LABELS } from './chunk-FHRO2Z3F.js';
2
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
+
4
+ function ToyRoundMark({ size = 40 }) {
5
+ return /* @__PURE__ */ jsxs("svg", { className: "toy-mark", width: size, height: size, viewBox: "0 0 64 64", "aria-hidden": "true", focusable: "false", children: [
6
+ /* @__PURE__ */ jsx("circle", { cx: "32", cy: "32", r: "24", fill: "none", stroke: "var(--toy-logo-ring, #1f2a44)", strokeWidth: "7" }),
7
+ /* @__PURE__ */ jsx("circle", { cx: "32", cy: "32", r: "24", fill: "none", stroke: "var(--toy-logo-arc, #ffb703)", strokeWidth: "7", strokeDasharray: "52 200", strokeLinecap: "round", transform: "rotate(-70 32 32)" }),
8
+ /* @__PURE__ */ jsx("rect", { x: "40", y: "6", width: "16", height: "16", rx: "4", fill: "var(--toy-logo-block, #ef6351)", transform: "rotate(14 48 14)" }),
9
+ /* @__PURE__ */ jsx("circle", { cx: "32", cy: "32", r: "8", fill: "var(--toy-logo-core, #2a9d8f)" })
10
+ ] });
11
+ }
12
+ function ToyWordmark({ size = 34, href = "/" }) {
13
+ return /* @__PURE__ */ jsxs("a", { className: "toy-brand", href: safeToyLink(href) || "/", children: [
14
+ /* @__PURE__ */ jsx(ToyRoundMark, { size }),
15
+ /* @__PURE__ */ jsxs("span", { children: [
16
+ "Toy",
17
+ /* @__PURE__ */ jsx("em", { children: "Round" })
18
+ ] })
19
+ ] });
20
+ }
21
+ function ToyPhoto({ listing, mediaUrl, large = false, index = 0 }) {
22
+ const photo = listing.media[index];
23
+ const src = photo && safeToyLink(mediaUrl(listing.id, photo.id));
24
+ if (!src)
25
+ return /* @__PURE__ */ jsx("div", { className: "toy-photo-empty", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ToyRoundMark, { size: 48 }) });
26
+ const separator = src.includes("?") ? "&" : "?";
27
+ return /* @__PURE__ */ jsx("figure", { className: "toy-photo", children: /* @__PURE__ */ jsxs("picture", { children: [
28
+ /* @__PURE__ */ jsx("source", { type: "image/webp", srcSet: `${src}${separator}width=640&format=webp 640w, ${src}${separator}width=1280&format=webp 1280w`, sizes: large ? "(max-width: 700px) 100vw, 60vw" : "(max-width: 700px) 100vw, 30vw" }),
29
+ /* @__PURE__ */ jsx("img", { src: `${src}${separator}width=${large ? 1280 : 640}&format=jpeg`, alt: photo.caption || listing.content.title, width: large ? 1200 : 640, height: large ? 900 : 480, loading: large ? "eager" : "lazy" })
30
+ ] }) });
31
+ }
32
+ function ToyBadges({ listing }) {
33
+ return /* @__PURE__ */ jsxs("p", { className: "toy-badges", children: [
34
+ /* @__PURE__ */ jsx("span", { className: `toy-badge toy-badge-${listing.exchange_type}`, children: listing.exchange_type === "swap" ? "Swap" : "Free" }),
35
+ /* @__PURE__ */ jsx("span", { className: "toy-badge", children: toyOptionLabel(TOY_AGE_RANGES, listing.age_range) }),
36
+ /* @__PURE__ */ jsx("span", { className: "toy-badge", children: toyOptionLabel(TOY_CONDITIONS, listing.condition) }),
37
+ listing.status === "reserved" && /* @__PURE__ */ jsx("span", { className: "toy-badge toy-badge-reserved", children: "Reserved" })
38
+ ] });
39
+ }
40
+ function ToyListingCard(props) {
41
+ const href = safeToyLink(props.href);
42
+ const { listing } = props;
43
+ return /* @__PURE__ */ jsxs("article", { className: `toy-card${listing.status === "reserved" ? " toy-card-reserved" : ""}`, children: [
44
+ /* @__PURE__ */ jsx(ToyPhoto, { ...props }),
45
+ /* @__PURE__ */ jsxs("div", { className: "toy-card-copy", children: [
46
+ /* @__PURE__ */ jsx(ToyBadges, { listing }),
47
+ /* @__PURE__ */ jsx("h3", { children: href ? /* @__PURE__ */ jsx("a", { href, children: listing.content.title }) : listing.content.title }),
48
+ /* @__PURE__ */ jsxs("p", { className: "toy-context", children: [
49
+ toyOptionLabel(TOY_CATEGORIES, listing.category),
50
+ listing.community ? ` \xB7 ${listing.community}` : ""
51
+ ] }),
52
+ listing.content.completeness === "missing_parts" && /* @__PURE__ */ jsx("p", { className: "toy-note", children: "Missing parts disclosed" })
53
+ ] })
54
+ ] });
55
+ }
56
+ function ToyLocationCard({ location }) {
57
+ const map = safeToyLink(location.map_url);
58
+ const source = safeToyLink(location.source_url);
59
+ const kind = location.kind === "official_exchange_zone" ? "Official exchange zone" : location.kind === "participating_business" ? "Participating business" : "Public meeting place";
60
+ return /* @__PURE__ */ jsxs("article", { className: "toy-location", children: [
61
+ /* @__PURE__ */ jsx("p", { className: "toy-context", children: kind }),
62
+ /* @__PURE__ */ jsx("h3", { children: location.name }),
63
+ /* @__PURE__ */ jsx("p", { children: location.address }),
64
+ /* @__PURE__ */ jsxs("p", { className: "toy-note", children: [
65
+ "Hours: ",
66
+ hoursSummary(location.hours) || "See source"
67
+ ] }),
68
+ location.restrictions && /* @__PURE__ */ jsx("p", { className: "toy-note", children: location.restrictions }),
69
+ Object.entries(location.verified_facts).map(([key, fact]) => /* @__PURE__ */ jsxs("p", { className: "toy-note", children: [
70
+ /* @__PURE__ */ jsxs("strong", { children: [
71
+ key,
72
+ ":"
73
+ ] }),
74
+ " ",
75
+ fact.text,
76
+ fact.source_url && safeToyLink(fact.source_url) && /* @__PURE__ */ jsxs(Fragment, { children: [
77
+ " ",
78
+ /* @__PURE__ */ jsx("a", { href: safeToyLink(fact.source_url), rel: "noopener noreferrer", children: "source" })
79
+ ] })
80
+ ] }, key)),
81
+ location.hosting_partnership && /* @__PURE__ */ jsxs("p", { className: "toy-note", children: [
82
+ "Hosting partner: ",
83
+ location.partnership_note
84
+ ] }),
85
+ /* @__PURE__ */ jsxs("p", { className: "toy-location-links", children: [
86
+ map && /* @__PURE__ */ jsx("a", { href: map, rel: "noopener noreferrer", children: "Map" }),
87
+ source && /* @__PURE__ */ jsx("a", { href: source, rel: "noopener noreferrer", children: "Source" }),
88
+ location.last_checked_on && /* @__PURE__ */ jsxs("small", { children: [
89
+ "Last checked ",
90
+ location.last_checked_on
91
+ ] })
92
+ ] })
93
+ ] });
94
+ }
95
+ function ToyHowItWorks() {
96
+ return /* @__PURE__ */ jsxs("section", { className: "toy-how", "aria-labelledby": "toy-how-title", children: [
97
+ /* @__PURE__ */ jsx("h2", { id: "toy-how-title", children: "How it works" }),
98
+ /* @__PURE__ */ jsx("ol", { children: TOY_HOW_IT_WORKS.map((step, index) => /* @__PURE__ */ jsxs("li", { children: [
99
+ /* @__PURE__ */ jsx("span", { className: "toy-step-number", "aria-hidden": "true", children: index + 1 }),
100
+ /* @__PURE__ */ jsx("strong", { children: step.title }),
101
+ /* @__PURE__ */ jsx("p", { children: step.detail })
102
+ ] }, step.title)) }),
103
+ /* @__PURE__ */ jsx("p", { className: "toy-safety", children: TOY_SAFETY.summary })
104
+ ] });
105
+ }
106
+ function ToyRulesContent() {
107
+ return /* @__PURE__ */ jsxs("div", { className: "toy-rules", children: [
108
+ /* @__PURE__ */ jsxs("section", { children: [
109
+ /* @__PURE__ */ jsx("h2", { children: "Community rules" }),
110
+ /* @__PURE__ */ jsxs("ul", { children: [
111
+ /* @__PURE__ */ jsx("li", { children: "Adults only. Posting and requesting need an 18+ statement plus a verified email and phone. Browsing is open to everyone." }),
112
+ /* @__PURE__ */ jsx("li", { children: "Free giveaways and direct swaps only. No sales, payments, deposits, shipping or delivery fees \u2014 ever." }),
113
+ /* @__PURE__ */ jsx("li", { children: "Real photos of the actual toy, with wear, damage and missing pieces disclosed." }),
114
+ /* @__PURE__ */ jsx("li", { children: "Exchanges happen at listed public places, during the day, with both neighbors confirming the time. No home or porch pickups." }),
115
+ /* @__PURE__ */ jsx("li", { children: "Keep coordination inside ToyRound. Use report and block if anything feels off." }),
116
+ /* @__PURE__ */ jsx("li", { children: "Editors review every listing before it appears, and may decline, edit or remove listings and suspend accounts." })
117
+ ] })
118
+ ] }),
119
+ /* @__PURE__ */ jsxs("section", { children: [
120
+ /* @__PURE__ */ jsx("h2", { children: "Prohibited items" }),
121
+ /* @__PURE__ */ jsx("p", { children: "ToyRound is for ordinary toys, puzzles, games and play sets. These are not accepted:" }),
122
+ /* @__PURE__ */ jsx("ul", { children: TOY_EXCLUSIONS.map((item) => /* @__PURE__ */ jsx("li", { children: item.label }, item.key)) }),
123
+ /* @__PURE__ */ jsxs("p", { children: [
124
+ "Before listing, search the",
125
+ " ",
126
+ /* @__PURE__ */ jsx("a", { href: "https://www.cpsc.gov/Recalls", rel: "noopener noreferrer", children: "CPSC recall database" }),
127
+ " ",
128
+ "for the brand and model. ",
129
+ TOY_SAFETY.recall
130
+ ] })
131
+ ] }),
132
+ /* @__PURE__ */ jsxs("section", { children: [
133
+ /* @__PURE__ */ jsx("h2", { children: "Privacy and safety" }),
134
+ /* @__PURE__ */ jsxs("ul", { children: [
135
+ /* @__PURE__ */ jsx("li", { children: "Public profiles show a first name or chosen display name, community, join month and participant-confirmed completed exchanges. Nothing else." }),
136
+ /* @__PURE__ */ jsx("li", { children: "Legal names, phone numbers, email addresses and home addresses are never shown. ToyRound does not collect identity documents." }),
137
+ /* @__PURE__ */ jsx("li", { children: "Location data and other metadata are removed from uploaded photos." }),
138
+ /* @__PURE__ */ jsx("li", { children: TOY_SAFETY.children }),
139
+ /* @__PURE__ */ jsx("li", { children: TOY_SAFETY.verification }),
140
+ /* @__PURE__ */ jsx("li", { children: "Conversations, appointments and drafts are private to the two neighbors involved. Reported conversations may be reviewed by editors as moderation evidence." }),
141
+ /* @__PURE__ */ jsx("li", { children: "You can delete your ToyRound account from your account page. Listings are withdrawn, open exchanges are cancelled, and your profile is anonymized. Reports and blocks are retained under the platform's moderation retention policy." }),
142
+ /* @__PURE__ */ jsx("li", { children: TOY_SAFETY.summary })
143
+ ] })
144
+ ] })
145
+ ] });
146
+ }
147
+ function ToysSection({
148
+ communities,
149
+ community,
150
+ listings,
151
+ basePath = "/toys",
152
+ mediaUrl,
153
+ listingBasePath,
154
+ browsePath,
155
+ submitUrl,
156
+ accountUrl,
157
+ locationsUrl,
158
+ rulesUrl,
159
+ regionLabel,
160
+ nextUrl,
161
+ unavailable,
162
+ submissionsOpen = true,
163
+ locationCount,
164
+ filters = {},
165
+ embedded = false,
166
+ signedIn = false
167
+ }) {
168
+ const link = (id) => `${listingBasePath || basePath}/${encodeURIComponent(id)}`;
169
+ const location = community?.name || regionLabel || "the Bay Area";
170
+ const browse = browsePath || basePath;
171
+ const query = new URLSearchParams(Object.entries(filters).filter((e) => typeof e[1] === "string" && e[1] !== ""));
172
+ if (community) query.set("community", community.slug);
173
+ const find = browse + (query.size ? "?" + query : "");
174
+ return /* @__PURE__ */ jsxs("div", { className: `toy${embedded ? " toy-embedded" : ""}`, children: [
175
+ /* @__PURE__ */ jsxs("header", { className: "toy-masthead", children: [
176
+ /* @__PURE__ */ jsx(ToyWordmark, { href: embedded ? basePath : "/" }),
177
+ /* @__PURE__ */ jsx("p", { className: "toy-tagline", children: TOY_BRAND.tagline }),
178
+ /* @__PURE__ */ jsxs("nav", { className: "toy-masthead-links", "aria-label": "ToyRound", children: [
179
+ rulesUrl && /* @__PURE__ */ jsx("a", { href: safeToyLink(rulesUrl), children: "Rules & safety" }),
180
+ locationsUrl && /* @__PURE__ */ jsx("a", { href: safeToyLink(locationsUrl), children: "Where to meet" }),
181
+ accountUrl && /* @__PURE__ */ jsx("a", { href: safeToyLink(accountUrl), children: signedIn ? "My toys" : "Sign in" })
182
+ ] })
183
+ ] }),
184
+ unavailable ? /* @__PURE__ */ jsxs("div", { role: "status", className: "toy-empty", children: [
185
+ /* @__PURE__ */ jsx("h1", { children: "ToyRound is taking a short break." }),
186
+ /* @__PURE__ */ jsx("p", { children: "We can't load the exchange right now. Please try again shortly." })
187
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
188
+ /* @__PURE__ */ jsxs("section", { className: "toy-hero", "aria-labelledby": "toy-hero-title", children: [
189
+ /* @__PURE__ */ jsxs("div", { className: "toy-hero-copy", children: [
190
+ /* @__PURE__ */ jsxs("p", { className: "toy-eyebrow", children: [
191
+ "Free giveaways and swaps in ",
192
+ location
193
+ ] }),
194
+ /* @__PURE__ */ jsxs("h1", { id: "toy-hero-title", children: [
195
+ "Pass along",
196
+ /* @__PURE__ */ jsx("br", {}),
197
+ "the play."
198
+ ] }),
199
+ /* @__PURE__ */ jsx("p", { className: "toy-hero-detail", children: "Outgrown toys find new homes with neighbors. No money changes hands, and exchanges happen at public places during the day." }),
200
+ /* @__PURE__ */ jsxs("div", { className: "toy-hero-actions", children: [
201
+ /* @__PURE__ */ jsx("a", { className: "toy-button", href: find, children: "Find a toy" }),
202
+ submitUrl && /* @__PURE__ */ jsx("a", { className: "toy-button toy-button-secondary", href: safeToyLink(submitUrl), children: "Give or swap a toy" })
203
+ ] }),
204
+ !submissionsOpen && /* @__PURE__ */ jsx("p", { className: "toy-note", children: "New listings are paused while our review team gets ready. Browsing stays open." })
205
+ ] }),
206
+ /* @__PURE__ */ jsx("div", { className: "toy-hero-art", "aria-hidden": "true", children: /* @__PURE__ */ jsx(ToyRoundMark, { size: 180 }) })
207
+ ] }),
208
+ /* @__PURE__ */ jsxs("section", { className: "toy-community", "aria-label": "Choose your community", children: [
209
+ /* @__PURE__ */ jsxs("form", { action: browse, method: "get", className: "toy-filters", children: [
210
+ /* @__PURE__ */ jsxs("label", { children: [
211
+ "Community",
212
+ /* @__PURE__ */ jsxs("select", { name: "community", defaultValue: community?.slug || "", children: [
213
+ /* @__PURE__ */ jsx("option", { value: "", children: "All communities" }),
214
+ communities.map((c) => /* @__PURE__ */ jsx("option", { value: c.slug, children: c.name }, c.id))
215
+ ] })
216
+ ] }),
217
+ /* @__PURE__ */ jsxs("label", { children: [
218
+ "Category",
219
+ /* @__PURE__ */ jsxs("select", { name: "category", defaultValue: filters.category || "", children: [
220
+ /* @__PURE__ */ jsx("option", { value: "", children: "Any category" }),
221
+ TOY_CATEGORIES.map((c) => /* @__PURE__ */ jsx("option", { value: c.key, children: c.label }, c.key))
222
+ ] })
223
+ ] }),
224
+ /* @__PURE__ */ jsxs("label", { children: [
225
+ "Age guidance",
226
+ /* @__PURE__ */ jsxs("select", { name: "age_range", defaultValue: filters.age_range || "", children: [
227
+ /* @__PURE__ */ jsx("option", { value: "", children: "Any age" }),
228
+ TOY_AGE_RANGES.map((c) => /* @__PURE__ */ jsx("option", { value: c.key, children: c.label }, c.key))
229
+ ] })
230
+ ] }),
231
+ /* @__PURE__ */ jsxs("label", { children: [
232
+ "Condition",
233
+ /* @__PURE__ */ jsxs("select", { name: "condition", defaultValue: filters.condition || "", children: [
234
+ /* @__PURE__ */ jsx("option", { value: "", children: "Any condition" }),
235
+ TOY_CONDITIONS.map((c) => /* @__PURE__ */ jsx("option", { value: c.key, children: c.label }, c.key))
236
+ ] })
237
+ ] }),
238
+ /* @__PURE__ */ jsxs("label", { children: [
239
+ "Type",
240
+ /* @__PURE__ */ jsxs("select", { name: "exchange_type", defaultValue: filters.exchange_type || "", children: [
241
+ /* @__PURE__ */ jsx("option", { value: "", children: "Free or swap" }),
242
+ /* @__PURE__ */ jsx("option", { value: "giveaway", children: "Free giveaways" }),
243
+ /* @__PURE__ */ jsx("option", { value: "swap", children: "Swaps" })
244
+ ] })
245
+ ] }),
246
+ /* @__PURE__ */ jsxs("label", { children: [
247
+ "Availability",
248
+ /* @__PURE__ */ jsxs("select", { name: "availability", defaultValue: filters.availability || "", children: [
249
+ /* @__PURE__ */ jsx("option", { value: "", children: "Include reserved" }),
250
+ /* @__PURE__ */ jsx("option", { value: "available", children: "Available now" })
251
+ ] })
252
+ ] }),
253
+ /* @__PURE__ */ jsxs("label", { children: [
254
+ "Search",
255
+ /* @__PURE__ */ jsx("input", { name: "q", maxLength: 80, defaultValue: filters.q || "", placeholder: "Train set, puzzle, Brio\u2026" })
256
+ ] }),
257
+ /* @__PURE__ */ jsx("button", { type: "submit", children: "Show toys" })
258
+ ] }),
259
+ locationCount === 0 && community && /* @__PURE__ */ jsxs("p", { className: "toy-note toy-location-warning", children: [
260
+ "No checked meeting places are listed for ",
261
+ community.name,
262
+ " yet, so exchanges can't be arranged there until one is added. You can still browse, list, and",
263
+ " ",
264
+ locationsUrl ? /* @__PURE__ */ jsx("a", { href: safeToyLink(locationsUrl), children: "suggest a public meeting place" }) : "suggest a public meeting place",
265
+ "."
266
+ ] })
267
+ ] }),
268
+ /* @__PURE__ */ jsxs("section", { className: "toy-section", "aria-labelledby": "toy-listings-title", children: [
269
+ /* @__PURE__ */ jsxs("div", { className: "toy-section-heading", children: [
270
+ /* @__PURE__ */ jsx("h2", { id: "toy-listings-title", children: community ? `Toys in ${community.name}` : "Toys across the network" }),
271
+ /* @__PURE__ */ jsx("p", { children: "Every listing is reviewed by a local editor before it appears." })
272
+ ] }),
273
+ listings.length ? /* @__PURE__ */ jsx("div", { className: "toy-grid", children: listings.map((listing) => /* @__PURE__ */ jsx(ToyListingCard, { listing, href: link(listing.id), mediaUrl }, listing.id)) }) : /* @__PURE__ */ jsxs("div", { className: "toy-board-invitation", children: [
274
+ /* @__PURE__ */ jsx(ToyRoundMark, { size: 56 }),
275
+ /* @__PURE__ */ jsxs("div", { children: [
276
+ /* @__PURE__ */ jsxs("h3", { children: [
277
+ "Be the first to pass along the play in ",
278
+ location,
279
+ "."
280
+ ] }),
281
+ /* @__PURE__ */ jsx("p", { children: "No approved listings match yet. When neighbors list toys here, they'll appear after review." })
282
+ ] }),
283
+ submitUrl && /* @__PURE__ */ jsx("a", { className: "toy-text-link", href: safeToyLink(submitUrl), children: "List a toy" })
284
+ ] }),
285
+ nextUrl && /* @__PURE__ */ jsx("a", { className: "toy-button toy-button-secondary", href: safeToyLink(nextUrl), children: "More toys" })
286
+ ] }),
287
+ /* @__PURE__ */ jsx(ToyHowItWorks, {})
288
+ ] }),
289
+ /* @__PURE__ */ jsxs("footer", { className: "toy-footer", children: [
290
+ /* @__PURE__ */ jsxs("div", { children: [
291
+ /* @__PURE__ */ jsx(ToyWordmark, { size: 28, href: embedded ? TOY_BRAND.origin : "/" }),
292
+ /* @__PURE__ */ jsx("p", { children: TOY_BRAND.tagline })
293
+ ] }),
294
+ /* @__PURE__ */ jsxs("p", { children: [
295
+ embedded ? /* @__PURE__ */ jsxs(Fragment, { children: [
296
+ /* @__PURE__ */ jsx("a", { href: TOY_BRAND.origin, children: TOY_BRAND.poweredBy }),
297
+ /* @__PURE__ */ jsx("br", {})
298
+ ] }) : null,
299
+ "A community toy exchange by ",
300
+ /* @__PURE__ */ jsx("a", { href: TOY_BRAND.networkUrl, children: "Bay Area News Network" }),
301
+ "."
302
+ ] }),
303
+ /* @__PURE__ */ jsxs("p", { className: "toy-footer-links", children: [
304
+ rulesUrl && /* @__PURE__ */ jsx("a", { href: safeToyLink(rulesUrl), children: "Rules, prohibited items, privacy & safety" }),
305
+ locationsUrl && /* @__PURE__ */ jsx("a", { href: safeToyLink(locationsUrl), children: "Meeting places" })
306
+ ] })
307
+ ] })
308
+ ] });
309
+ }
310
+ function toyStatusLabel(status) {
311
+ return TOY_STATUS_LABELS[status] || status;
312
+ }
313
+
314
+ export { ToyBadges, ToyHowItWorks, ToyListingCard, ToyLocationCard, ToyPhoto, ToyRoundMark, ToyRulesContent, ToyWordmark, ToysSection, toyStatusLabel };
@@ -0,0 +1,174 @@
1
+ // src/toys.ts
2
+ var TOY_BRAND = {
3
+ name: "ToyRound",
4
+ tagline: "Pass along the play.",
5
+ attribution: "A community toy exchange by Bay Area News Network.",
6
+ poweredBy: "Powered by ToyRound",
7
+ publicationLabel: "Toy Swap",
8
+ origin: "https://toyround.com",
9
+ networkUrl: "https://bayareanewsnetwork.com"
10
+ };
11
+ var TOY_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
12
+ var TOY_SLUG = /^[a-z0-9][a-z0-9-]{0,190}$/;
13
+ var TOY_EXCHANGE_TYPES = [
14
+ { key: "giveaway", label: "Free giveaway" },
15
+ { key: "swap", label: "Direct swap" }
16
+ ];
17
+ var TOY_CATEGORIES = [
18
+ { key: "building", label: "Building & construction" },
19
+ { key: "puzzles", label: "Puzzles" },
20
+ { key: "games", label: "Board & card games" },
21
+ { key: "dolls_figures", label: "Dolls & action figures" },
22
+ { key: "vehicles", label: "Vehicles & trains" },
23
+ { key: "outdoor", label: "Outdoor & active play" },
24
+ { key: "arts_crafts", label: "Arts & crafts" },
25
+ { key: "pretend_play", label: "Pretend play & play sets" },
26
+ { key: "stem_learning", label: "STEM & learning" },
27
+ { key: "plush", label: "Plush & soft toys" },
28
+ { key: "books_media", label: "Books & media" },
29
+ { key: "baby_toddler", label: "Baby & toddler toys" },
30
+ { key: "musical", label: "Musical toys" },
31
+ { key: "other", label: "Other toys" }
32
+ ];
33
+ var TOY_AGE_RANGES = [
34
+ { key: "0-12m", label: "0\u201312 months" },
35
+ { key: "1-2", label: "1\u20132 years" },
36
+ { key: "3-5", label: "3\u20135 years" },
37
+ { key: "6-8", label: "6\u20138 years" },
38
+ { key: "9-12", label: "9\u201312 years" },
39
+ { key: "13+", label: "13 and up" },
40
+ { key: "unknown", label: "Not stated on the item" }
41
+ ];
42
+ var TOY_CONDITIONS = [
43
+ { key: "like_new", label: "Like new" },
44
+ { key: "good", label: "Good \u2014 normal wear" },
45
+ { key: "fair", label: "Fair \u2014 visible wear, works" }
46
+ ];
47
+ var TOY_EXCLUSIONS = [
48
+ { key: "car_seats", label: "Car seats and booster seats" },
49
+ { key: "cribs_sleep", label: "Cribs, bassinets and infant sleep equipment" },
50
+ { key: "helmets", label: "Helmets and protective gear" },
51
+ { key: "weapons", label: "Weapons, replica weapons and hard-tipped projectile toys" },
52
+ { key: "water_beads", label: "Water beads" },
53
+ { key: "magnets", label: "Loose high-powered magnets and magnet sets" },
54
+ { key: "recalled", label: "Anything subject to a CPSC recall" },
55
+ { key: "broken", label: "Visibly unsafe, broken or sharp-edged items" },
56
+ { key: "batteries", label: "Items with loose button or coin batteries" }
57
+ ];
58
+ var TOY_REPORT_REASONS = [
59
+ { key: "recalled_or_unsafe", label: "Recalled or unsafe item" },
60
+ { key: "child_safety", label: "Child safety concern" },
61
+ { key: "harassment", label: "Harassment or threats" },
62
+ { key: "scam_or_payment", label: "Asked for money, deposits or codes" },
63
+ { key: "prohibited_item", label: "Prohibited item" },
64
+ { key: "inappropriate_photo", label: "Inappropriate photo" },
65
+ { key: "no_show", label: "No-show" },
66
+ { key: "misleading_listing", label: "Misleading listing" },
67
+ { key: "spam", label: "Spam" },
68
+ { key: "other", label: "Something else" }
69
+ ];
70
+ var TOY_CPSC_RECALLS_URL = "https://www.cpsc.gov/Recalls";
71
+ var TOY_STATUS_LABELS = {
72
+ draft: "Draft",
73
+ pending_review: "Waiting for review",
74
+ available: "Available",
75
+ reserved: "Reserved",
76
+ completed: "Completed",
77
+ rejected: "Needs changes",
78
+ withdrawn: "Withdrawn",
79
+ expired: "Expired",
80
+ suspended: "Suspended for safety review"
81
+ };
82
+ var TOY_REQUEST_STATUS_LABELS = {
83
+ pending: "Waiting for the owner",
84
+ accepted: "Accepted \u2014 arrange a meeting",
85
+ declined: "Declined",
86
+ cancelled: "Cancelled",
87
+ completed: "Completed",
88
+ expired: "Expired"
89
+ };
90
+ var TOY_SAFETY = {
91
+ summary: "Public places and account verification reduce risk but do not guarantee safety. ToyRound is not supervised and no one is on call.",
92
+ verification: "\u201CPhone verified\u201D and \u201Cemail verified\u201D mean a working contact method was confirmed. They are not an identity check, a background check or a statement that someone is trustworthy.",
93
+ meeting: "Meet only at a listed public place during the day, keep arrangements in this thread, and bring someone along if you like. Never share your home address.",
94
+ money: "ToyRound never involves payments, deposits, shipping fees or verification codes. Anyone asking for them is breaking the rules \u2014 report them.",
95
+ recall: "A member's recall check is their own statement after searching the CPSC database. It is not a safety certification, and ToyRound never labels an item recall-free or certified.",
96
+ children: "Do not share children's names, photos, schools or schedules. Manufacturer age guidance is reported as printed; ToyRound never decides what is safe for a particular child."
97
+ };
98
+ var TOY_HOW_IT_WORKS = [
99
+ { title: "List a toy", detail: "Real photos, honest condition, a quick CPSC recall search. Editors review every listing before it appears." },
100
+ { title: "Agree on an exchange", detail: "Neighbors ask for the toy or propose a swap. You decide, and the toy is reserved for one person at a time." },
101
+ { title: "Meet in public", detail: "Pick a listed public place and a daytime slot that both of you confirm. No home or porch pickups." },
102
+ { title: "Pass along the play", detail: "Both of you mark the exchange complete. Private feedback helps keep the exchange friendly." }
103
+ ];
104
+ function toyOptionLabel(options, key) {
105
+ return options.find((o) => o.key === key)?.label || key;
106
+ }
107
+ function resolveToyCommunity(areas, selected, preference, publicationDefault) {
108
+ if (selected === "" || selected === void 0 && preference === "all") return void 0;
109
+ for (const candidate of [selected, preference, publicationDefault]) {
110
+ const found = areas.find((area) => area.id === candidate || area.slug === candidate);
111
+ if (found) return found;
112
+ }
113
+ return void 0;
114
+ }
115
+ function safeToyLink(raw) {
116
+ if (!raw) return void 0;
117
+ if (raw.startsWith("/") && !raw.startsWith("//") && !/[\\\r\n]/.test(raw)) return raw;
118
+ try {
119
+ const url = new URL(raw);
120
+ return url.protocol === "https:" && !url.username && !url.password ? url.href : void 0;
121
+ } catch {
122
+ return void 0;
123
+ }
124
+ }
125
+ function toyListingMetadata(listing, canonicalUrl, photoUrl) {
126
+ const canonical = safeToyLink(canonicalUrl);
127
+ if (!listing || !canonical?.startsWith("https://"))
128
+ return { title: "Listing unavailable", robots: { index: false, follow: false } };
129
+ const title = `${listing.content.title} \u2014 ${listing.exchange_type === "swap" ? "swap" : "free"} on ToyRound`;
130
+ const description = Array.from(listing.content.description).slice(0, 180).join("");
131
+ return {
132
+ title,
133
+ description,
134
+ alternates: { canonical },
135
+ openGraph: {
136
+ title,
137
+ description,
138
+ url: canonical,
139
+ ...photoUrl && safeToyLink(photoUrl) ? { images: [{ url: photoUrl, alt: listing.content.title }] } : {}
140
+ }
141
+ };
142
+ }
143
+ function formatLocalStart(localStart, timezone) {
144
+ const [date, time] = localStart.split("T");
145
+ if (!date || !time) return localStart;
146
+ try {
147
+ const day = (/* @__PURE__ */ new Date(date + "T12:00:00Z")).toLocaleDateString("en-US", {
148
+ weekday: "short",
149
+ month: "short",
150
+ day: "numeric",
151
+ timeZone: "UTC"
152
+ });
153
+ const [h, m] = time.split(":").map(Number);
154
+ const hour12 = (h + 11) % 12 + 1;
155
+ const zone = timezone.split("/").pop()?.replaceAll("_", " ") || timezone;
156
+ return `${day}, ${hour12}:${String(m).padStart(2, "0")} ${h >= 12 ? "PM" : "AM"} (${zone} time)`;
157
+ } catch {
158
+ return localStart;
159
+ }
160
+ }
161
+ var TOY_DAY_LABELS = {
162
+ mon: "Mon",
163
+ tue: "Tue",
164
+ wed: "Wed",
165
+ thu: "Thu",
166
+ fri: "Fri",
167
+ sat: "Sat",
168
+ sun: "Sun"
169
+ };
170
+ function hoursSummary(hours) {
171
+ return Object.entries(hours).map(([day, ranges]) => `${TOY_DAY_LABELS[day] || day} ${ranges.map(([o, c]) => `${o}\u2013${c}`).join(", ")}`).join(" \xB7 ");
172
+ }
173
+
174
+ export { TOY_AGE_RANGES, TOY_BRAND, TOY_CATEGORIES, TOY_CONDITIONS, TOY_CPSC_RECALLS_URL, TOY_DAY_LABELS, TOY_EXCHANGE_TYPES, TOY_EXCLUSIONS, TOY_HOW_IT_WORKS, TOY_REPORT_REASONS, TOY_REQUEST_STATUS_LABELS, TOY_SAFETY, TOY_SLUG, TOY_STATUS_LABELS, TOY_UUID, formatLocalStart, hoursSummary, resolveToyCommunity, safeToyLink, toyListingMetadata, toyOptionLabel };
@@ -1,4 +1,4 @@
1
- import { NETWORK_PARENT } from './chunk-6S5FARL3.js';
1
+ import { NETWORK_PARENT } from './chunk-XWXPERLK.js';
2
2
  import { jsxs, jsx } from 'react/jsx-runtime';
3
3
 
4
4
  function NetworkCopyrightNotice({
@@ -512,7 +512,13 @@ var ALLOWED_CARD_TYPES = /* @__PURE__ */ new Set([
512
512
  "ACTIVITY",
513
513
  "EVENT",
514
514
  "ORGANIZATION",
515
- "PRODUCT"
515
+ "PRODUCT",
516
+ "FRAMEWORK",
517
+ "STANDARD",
518
+ "SPECIFICATION",
519
+ "TOPIC",
520
+ "RESOURCE",
521
+ "REFERENCE"
516
522
  ]);
517
523
  function clip(val, maxChars) {
518
524
  if (typeof val !== "string") return void 0;
@@ -554,9 +560,18 @@ function parseRawCards(rawCards) {
554
560
  const id = clip(c.id, 64);
555
561
  const title = clip(c.title, 300);
556
562
  if (!id || !title) continue;
557
- const rawType = typeof c.card_type === "string" ? c.card_type : c.cardType;
558
- const cardType = ALLOWED_CARD_TYPES.has(rawType) ? rawType : "PLACE";
559
- const kicker = clip(c.kicker, 120) || (cardType === "PLACE" ? "LOCAL VENUE \xB7 VERIFIED DIRECTORY" : cardType === "EVENT" ? "COMMUNITY EVENT \xB7 VERIFIED FACTSHEET" : cardType === "ACTIVITY" ? "COMMUNITY ACTIVITY \xB7 VERIFIED FACTSHEET" : cardType === "ORGANIZATION" ? "COMMUNITY ORGANIZATION \xB7 DIRECTORY" : "VERIFIED FACTSHEET");
563
+ const rawKind = (typeof c.card_type === "string" ? c.card_type : typeof c.cardType === "string" ? c.cardType : "").trim().toUpperCase();
564
+ let cardType;
565
+ if (ALLOWED_CARD_TYPES.has(rawKind)) {
566
+ cardType = rawKind;
567
+ } else if (rawKind === "RESEARCH_FRAMEWORK") {
568
+ cardType = "FRAMEWORK";
569
+ } else if (c.address && c.hours) {
570
+ cardType = "PLACE";
571
+ } else {
572
+ cardType = "REFERENCE";
573
+ }
574
+ const kicker = clip(c.kicker, 120) || (cardType === "PLACE" ? "LOCAL VENUE \xB7 DIRECTORY" : cardType === "EVENT" ? "COMMUNITY EVENT \xB7 FACTSHEET" : cardType === "ACTIVITY" ? "COMMUNITY ACTIVITY \xB7 FACTSHEET" : cardType === "ORGANIZATION" ? "ORGANIZATION \xB7 DIRECTORY" : cardType === "PRODUCT" ? "PRODUCT \xB7 FACTSHEET" : cardType === "FRAMEWORK" ? "TECHNICAL FRAMEWORK" : cardType === "STANDARD" ? "TECHNICAL STANDARD" : cardType === "SPECIFICATION" ? "SPECIFICATION" : cardType === "TOPIC" ? "TOPIC REFERENCE" : cardType === "RESOURCE" ? "DIGITAL RESOURCE" : "FACTSHEET");
560
575
  const subtitle = clip(c.subtitle, 300);
561
576
  const summary = clip(c.summary, 1e3);
562
577
  const badge = clip(c.badge, 64);
@@ -577,16 +592,23 @@ function parseRawCards(rawCards) {
577
592
  } else {
578
593
  const timeframe = clip(c.timeframe, 200);
579
594
  if (timeframe) facts.push({ label: "Timeframe", value: timeframe });
595
+ const isPhysicalPlace = cardType === "PLACE" || cardType === "EVENT" || cardType === "ACTIVITY";
580
596
  const address = clip(c.address, 300);
581
597
  if (address) {
582
598
  facts.push({
583
- label: "Address",
599
+ label: isPhysicalPlace ? "Address" : "Location",
584
600
  value: address,
585
- href: `https://maps.google.com/?q=${encodeURIComponent(address)}`
601
+ href: isPhysicalPlace ? `https://maps.google.com/?q=${encodeURIComponent(address)}` : void 0
586
602
  });
587
603
  }
588
604
  const hours = clip(c.hours, 300);
589
- if (hours) facts.push({ label: "Hours", value: hours });
605
+ if (hours) {
606
+ facts.push({ label: isPhysicalPlace ? "Hours" : "Details", value: hours });
607
+ }
608
+ const website = clip(c.website || c.url, 500);
609
+ if (website && isSafeActionUrl(website)) {
610
+ facts.push({ label: "Website", value: website.replace(/^https?:\/\//, ""), href: website });
611
+ }
590
612
  const phone = clip(c.phone, 80);
591
613
  if (phone) {
592
614
  facts.push({
@@ -634,8 +656,8 @@ function parseRawCards(rawCards) {
634
656
  };
635
657
  }
636
658
  }
637
- const verificationNote = clip(c.verification_note || c.verificationNote, 300) || "Verified by publication reporting staff";
638
- const verifiedAt = clip(c.verified_at || c.verifiedAt, 100) || "October 2026";
659
+ const verificationNote = clip(c.verification_note || c.verificationNote, 300);
660
+ const verifiedAt = clip(c.verified_at || c.verifiedAt, 100);
639
661
  let rating = void 0;
640
662
  if (typeof c.rating === "number" || typeof c.rating === "string") {
641
663
  rating = c.rating;
@@ -713,12 +735,12 @@ function VerifiedCardComponent({
713
735
  },
714
736
  i
715
737
  )) }),
716
- /* @__PURE__ */ jsxs("footer", { className: "article-verified-card__footer", children: [
717
- /* @__PURE__ */ jsxs("div", { className: "article-verified-card__seal", children: [
738
+ (card.verificationNote || card.verifiedAt) && /* @__PURE__ */ jsxs("footer", { className: "article-verified-card__footer", children: [
739
+ card.verificationNote && /* @__PURE__ */ jsxs("div", { className: "article-verified-card__seal", children: [
718
740
  /* @__PURE__ */ jsx("span", { className: "article-verified-card__seal-check", "aria-hidden": "true", children: "\u2713" }),
719
741
  /* @__PURE__ */ jsx("span", { children: card.verificationNote })
720
742
  ] }),
721
- /* @__PURE__ */ jsx("span", { className: "article-verified-card__date", children: card.verifiedAt })
743
+ card.verifiedAt && /* @__PURE__ */ jsx("span", { className: "article-verified-card__date", children: card.verifiedAt })
722
744
  ] })
723
745
  ]
724
746
  }
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { setupNetworkConsentDelegation, COOKIE_CONSENT_EVENT, listedPublications, decorateNetworkUrl } from './chunk-6S5FARL3.js';
2
+ import { setupNetworkConsentDelegation, COOKIE_CONSENT_EVENT, listedPublications, decorateNetworkUrl } from './chunk-XWXPERLK.js';
3
3
  import { useState, useId, useRef, useEffect } from 'react';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
5