PageSourceSearch

https://blackbusinessmonth.com/assets/_id_-BD9rv536.js

js blackbusinessmonth.com collected 2026-09-24 23:50:56 UTC 15,599 bytes, 275 lines download raw bytes

1import { av as useParams, aw as useLoaderData, r as reactExports, j as jsxRuntimeExports, L as Link, a8 as ArrowLeft, H as Helmet, ax as Tag, m as motion, ay as User, h as Clock, aj as Check, az as Share2 } from "./vendor-BnxyTOIt.js";
2import { a as story } from "./main-DpFm2Mq5.js";
3import "./preload-VwzZcMtp.js";
4/* empty css                 */
5function formatDate(iso) {
6  return new Date(iso).toLocaleDateString("en-US", {
7    weekday: "long",
8    year: "numeric",
9    month: "long",
10    day: "numeric"
11  });
12}
13function StoryBody({
14  content
15}) {
16  const hasHTML = /<(p|br|div|h[1-6]|ul|ol|li|strong|em|b|i|blockquote|a)\b/i.test(content);
17  if (hasHTML) {
18    const BLOCK_START = /^\s*<(ul|ol|li|div|h[1-6]|blockquote|p)\b/i;
19    const html = content.split("\n\n").map((chunk) => chunk.trim()).filter(Boolean).map((chunk) => {
20      if (BLOCK_START.test(chunk)) return chunk;
21      return `<p>${chunk.replace(/\n/g, "<br />")}</p>`;
22    }).join("");
23    return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
24      /* @__PURE__ */ jsxRuntimeExports.jsx("style", { children: `
25          .story-body p { margin-bottom: 1.25rem; line-height: 1.75; }
26          .story-body ul, .story-body ol { margin-bottom: 1.25rem; padding-left: 1.5rem; }
27          .story-body li { margin-bottom: 0.4rem; line-height: 1.75; }
28          .story-body ul { list-style-type: disc; }
29          .story-body ol { list-style-type: decimal; }
30          .story-body h1,.story-body h2,.story-body h3,.story-body h4 { margin-top: 1.5rem; margin-bottom: 0.75rem; font-weight: 700; }
31          .story-body strong, .story-body b { font-weight: 700; }
32          .story-body em, .story-body i { font-style: italic; }
33          .story-body blockquote { border-left: 4px solid hsl(var(--accent)); padding-left: 1rem; margin: 1.25rem 0; font-style: italic; }
34          .story-body a { color: hsl(var(--primary)); text-decoration: underline; }
35        ` }),
36      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "story-body max-w-none", style: {
37        fontFamily: "var(--font-sans)",
38        color: "hsl(var(--foreground))"
39      }, dangerouslySetInnerHTML: {
40        __html: html
41      } })
42    ] });
43  }
44  let paragraphs = content.split(/\n{2,}/).map((p) => p.trim()).filter(Boolean);
45  if (paragraphs.length <= 1) {
46    paragraphs = content.split(/\n/).map((p) => p.trim()).filter(Boolean);
47  }
48  return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "story-body", children: paragraphs.map((p, i) => /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mb-5 leading-relaxed text-base", style: {
49    fontFamily: "var(--font-sans)",
50    color: "hsl(var(--foreground))"
51  }, children: p }, i)) });
52}
53function StoryPage() {
54  const {
55    id
56  } = useParams();
57  const loaderData = useLoaderData();
58  const loaderStory = (loaderData == null ? void 0 : loaderData.story) ?? null;
59  const [story$1, setStory] = reactExports.useState(loaderStory);
60  const [loading, setLoading] = reactExports.useState(!loaderStory);
61  const [notFound, setNotFound] = reactExports.useState(false);
62  const [copied, setCopied] = reactExports.useState(false);
63  const site = "https://blackbusinessmonth.com";
64  const defaultOgImage = `${site}/airo-assets/uploads/og-default.png`;
65  reactExports.useEffect(() => {
66    if (story$1) return;
67    if (!id) return;
68    setLoading(true);
69    fetch(`/api/stories/${id}`).then((r) => {
70      if (r.status === 404) {
71        setNotFound(true);
72        return null;
73      }
74      return r.json();
75    }).then((data) => {
76      if (data) setStory(data);
77    }).catch(() => setNotFound(true)).finally(() => setLoading(false));
78  }, [id]);
79  const handleShare = () => {
80    navigator.clipboard.writeText(window.location.href);
81    setCopied(true);
82    setTimeout(() => setCopied(false), 2e3);
83  };
84  if (loading) {
85    return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "container mx-auto px-4 py-20 flex justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-4", children: [
86      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-8 h-8 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
87      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground text-sm", style: {
88        whiteSpace: "pre-line",
89        fontFamily: "var(--font-sans)"
90      }, children: story.loadingText })
91    ] }) });
92  }
93  if (notFound || !story$1) {
94    return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "container mx-auto px-4 py-20 text-center", children: [
95      /* @__PURE__ */ jsxRuntimeExports.jsx("h1", { className: "text-2xl font-bold mb-4", style: {
96        whiteSpace: "pre-line",
97        fontFamily: "var(--font-heading)"
98      }, children: story.notFoundHeading }),
99      /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground mb-8", style: {
100        whiteSpace: "pre-line",
101        fontFamily: "var(--font-sans)"
102      }, children: story.notFoundBody }),
103      /* @__PURE__ */ jsxRuntimeExports.jsxs(Link, { to: "/", className: "inline-flex items-center gap-2 font-semibold text-sm", style: {
104        color: "hsl(var(--primary))"
105      }, children: [
106        /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 15 }),
107        " ",
108        story.backToHome
109      ] })
110    ] });
111  }
112  const storyUrl = `${site}/stories/${story$1.id}`;
113  const ogImage = story$1.imageUrl ? story$1.imageUrl.startsWith("http") ? story$1.imageUrl : `${site}${story$1.imageUrl}` : defaultOgImage;
114  const pageTitle = story$1.seoTitle || `${story$1.headline} — Black Money Worldwide`;
115  const ogDescription = story$1.seoDescription || story$1.summary || story$1.headline;
116  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
117    /* @__PURE__ */ jsxRuntimeExports.jsxs(Helmet, { children: [
118      /* @__PURE__ */ jsxRuntimeExports.jsx("title", { children: pageTitle }),
119      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "description", content: ogDescription }),
120      story$1.seoKeywords && /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "keywords", content: story$1.seoKeywords }),
121      /* @__PURE__ */ jsxRuntimeExports.jsx("link", { rel: "canonical", href: storyUrl }),
122      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:type", content: "article" }),
123      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:site_name", content: "Black Money Worldwide" }),
124      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:url", content: storyUrl }),
125      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:title", content: pageTitle }),
126      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:description", content: ogDescription }),
127      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:image", content: ogImage }),
128      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:image:url", content: ogImage }),
129      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:image:secure_url", content: ogImage }),
130      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:image:width", content: "1200" }),
131      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:image:height", content: "630" }),
132      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "og:image:alt", content: story$1.headline }),
133      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "twitter:card", content: "summary_large_image" }),
134      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "twitter:title", content: pageTitle }),
135      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "twitter:description", content: ogDescription }),
136      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "twitter:image", content: ogImage }),
137      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { name: "twitter:image:alt", content: story$1.headline }),
138      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "article:published_time", content: story$1.publishedAt }),
139      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "article:author", content: story$1.author }),
140      /* @__PURE__ */ jsxRuntimeExports.jsx("meta", { property: "article:section", content: story$1.category })
141    ] }),
142    story$1.imageUrl && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-black flex items-center justify-center", style: {
143      maxHeight: "480px"
144    }, children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: story$1.imageUrl, alt: story$1.headline, className: "w-full object-contain", style: {
145      maxHeight: "480px"
146    } }) }),
147    /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "container mx-auto px-4 py-10", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "max-w-3xl mx-auto", children: [
148      /* @__PURE__ */ jsxRuntimeExports.jsxs(Link, { to: "/", className: "inline-flex items-center gap-1.5 text-xs font-semibold uppercase tracking-wider mb-6 hover:opacity-70 transition-opacity", style: {
149        color: "hsl(var(--primary))",
150        fontFamily: "var(--font-sans)"
151      }, children: [
152        /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 13 }),
153        " ",
154        story.backLabel
155      ] }),
156      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mb-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1.5 text-xs font-bold uppercase tracking-widest px-3 py-1", style: {
157        background: "hsl(var(--primary))",
158        color: "hsl(var(--accent))",
159        fontFamily: "var(--font-sans)"
160      }, children: [
161        /* @__PURE__ */ jsxRuntimeExports.jsx(Tag, { size: 10 }),
162        " ",
163        story$1.category
164      ] }) }),
165      /* @__PURE__ */ jsxRuntimeExports.jsx(motion.h1, { className: "text-3xl md:text-4xl font-bold leading-tight mb-5", style: {
166        fontFamily: "var(--font-heading)",
167        color: "hsl(var(--foreground))"
168      }, initial: {
169        opacity: 0,
170        y: 16
171      }, animate: {
172        opacity: 1,
173        y: 0,
174        transition: {
175          duration: 0.4,
176          ease: "easeOut"
177        }
178      }, children: story$1.headline }),
179      story$1.summary && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-lg text-muted-foreground leading-relaxed mb-6 border-l-4 pl-4", style: {
180        fontFamily: "var(--font-sans)",
181        borderColor: "hsl(var(--accent))"
182      }, children: story$1.summary }),
183      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center justify-between gap-4 py-4 border-t border-b border-border mb-8", style: {
184        fontFamily: "var(--font-sans)"
185      }, children: [
186        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-4 text-sm text-muted-foreground", children: [
187          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 font-semibold", style: {
188            color: "hsl(var(--primary))"
189          }, children: [
190            /* @__PURE__ */ jsxRuntimeExports.jsx(User, { size: 13 }),
191            " ",
192            story$1.author
193          ] }),
194          /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [
195            /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 13 }),
196            " ",
197            formatDate(story$1.publishedAt)
198          ] })
199        ] }),
200        /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleShare, className: "flex items-center gap-1.5 text-xs font-semibold px-3 py-1.5 border border-border hover:border-primary transition-colors", style: {
201          fontFamily: "var(--font-sans)"
202        }, children: copied ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
203          /* @__PURE__ */ jsxRuntimeExports.jsx(Check, { size: 12 }),
204          " Copied!"
205        ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
206          /* @__PURE__ */ jsxRuntimeExports.jsx(Share2, { size: 12 }),
207          " Share"
208        ] }) })
209      ] }),
210      story$1.content ? /* @__PURE__ */ jsxRuntimeExports.jsx(motion.div, { initial: {
211        opacity: 0
212      }, animate: {
213        opacity: 1,
214        transition: {
215          duration: 0.5,
216          delay: 0.1
217        }
218      }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(StoryBody, { content: story$1.content }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-muted-foreground italic", style: {
219        fontFamily: "var(--font-sans)"
220      }, children: "Full story content coming soon." }),
221      story$1.gallery && (() => {
222        try {
223          const galleryUrls = typeof story$1.gallery === "string" ? JSON.parse(story$1.gallery) : story$1.gallery;
224          if (Array.isArray(galleryUrls) && galleryUrls.length > 0) {
225            return /* @__PURE__ */ jsxRuntimeExports.jsxs(motion.div, { className: "mt-10", initial: {
226              opacity: 0
227            }, animate: {
228              opacity: 1,
229              transition: {
230                duration: 0.5,
231                delay: 0.2
232              }
233            }, children: [
234              /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-xl font-bold mb-4", style: {
235                whiteSpace: "pre-line",
236                fontFamily: "var(--font-heading)",
237                color: "hsl(var(--foreground))"
238              }, children: story.photoGalleryHeading }),
239              /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4", children: galleryUrls.map((url, idx) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-hidden border border-border", children: /* @__PURE__ */ jsxRuntimeExports.jsx("img", { src: url, alt: `${story$1.headline} - Photo ${idx + 1}`, className: "w-full h-auto object-cover" }) }, idx)) })
240            ] });
241          }
242        } catch (e) {
243          console.error("Failed to parse gallery:", e);
244        }
245        return null;
246      })(),
247      /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-12 pt-6 border-t border-border flex items-center gap-4", style: {
248        fontFamily: "var(--font-sans)"
249      }, children: [
250        /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-12 h-12 flex-shrink-0 flex items-center justify-center font-bold text-lg", style: {
251          background: "hsl(var(--primary))",
252          color: "hsl(var(--accent))"
253        }, children: story.authorInitials }),
254        /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
255          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "font-bold text-sm", style: {
256            color: "hsl(var(--foreground))"
257          }, children: story$1.author }),
258          /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", style: {
259            whiteSpace: "pre-line"
260          }, children: story.authorByline })
261        ] })
262      ] }),
263      /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-10 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Link, { to: "/", className: "inline-flex items-center gap-2 px-6 py-3 text-sm font-bold text-white transition-opacity hover:opacity-90", style: {
264        background: "hsl(var(--primary))"
265      }, children: [
266        /* @__PURE__ */ jsxRuntimeExports.jsx(ArrowLeft, { size: 14 }),
267        " ",
268        story.backToSiteLabel
269      ] }) })
270    ] }) })
271  ] });
272}
273export {
274  StoryPage as default
275};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.