@canvas-digital/blog-sdk 2.0.4 → 2.0.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.
Files changed (52) hide show
  1. package/dist/components/admin/AdminPostDetail.js +5 -5
  2. package/dist/components/admin/BrandSettings.js +5 -5
  3. package/dist/components/admin/BrandSwitcher.js +1 -1
  4. package/dist/components/admin/Chips.js +5 -5
  5. package/dist/components/admin/CommentsManager.js +6 -6
  6. package/dist/components/admin/Dashboard.js +1 -1
  7. package/dist/components/admin/MediaLibrary.js +5 -5
  8. package/dist/components/admin/MediaPicker.js +4 -4
  9. package/dist/components/admin/PostList.js +3 -3
  10. package/dist/components/admin/PostsTable.d.ts.map +1 -1
  11. package/dist/components/admin/PostsTable.js +10 -10
  12. package/dist/components/admin/Shell.js +3 -3
  13. package/dist/components/admin/TermManager.js +4 -4
  14. package/dist/components/admin/UsersManager.js +3 -3
  15. package/dist/components/admin/charts.js +7 -7
  16. package/dist/components/admin/editor/PostEditor.js +16 -16
  17. package/dist/components/admin/editor/RichTextEditor.js +8 -8
  18. package/dist/components/admin/editor/YoastCollapsible.js +2 -2
  19. package/dist/components/admin/editor/YoastInsightsPanel.js +1 -1
  20. package/dist/components/admin/editor/YoastInternalLinksPanel.js +1 -1
  21. package/dist/components/admin/editor/YoastSeoAnalysisPanel.js +6 -6
  22. package/dist/components/admin/editor/YoastSeoMetabox.js +8 -8
  23. package/dist/components/admin/editor/YoastSnippetField.js +2 -2
  24. package/dist/components/admin/internal/States.js +3 -3
  25. package/dist/components/admin/seo/Ga4Settings.js +6 -6
  26. package/dist/components/admin/seo/RedirectAnalyticsDashboard.js +1 -1
  27. package/dist/components/admin/seo/RedirectDetail.js +6 -6
  28. package/dist/components/admin/seo/RedirectForm.js +1 -1
  29. package/dist/components/admin/seo/RedirectList.js +4 -4
  30. package/dist/components/admin/seo/RobotsEditor.js +1 -1
  31. package/dist/components/admin/seo/shared.js +2 -2
  32. package/dist/components/admin/tools/ToolsHub.js +4 -4
  33. package/dist/components/user/BlogCard.js +3 -3
  34. package/dist/components/user/BlogCategories.js +1 -1
  35. package/dist/components/user/BlogDetail.js +1 -1
  36. package/dist/components/user/BlogList.js +1 -1
  37. package/dist/components/user/BlogSearch.js +2 -2
  38. package/dist/components/user/BlogTags.js +1 -1
  39. package/dist/components/user/FeaturedBlogs.js +1 -1
  40. package/dist/components/user/RelatedBlogs.js +1 -1
  41. package/dist/components/user/SiteMediaHero.js +1 -1
  42. package/dist/components/user/detail/ArticleDetailHero.js +5 -5
  43. package/dist/components/user/detail/ArticleRailDetails.js +2 -2
  44. package/dist/components/user/detail/CommentSection.js +2 -2
  45. package/dist/components/user/detail/HeroFadeSlide.js +1 -1
  46. package/dist/components/user/detail/ReadingProgress.js +1 -1
  47. package/dist/components/user/detail/ShareRow.js +1 -1
  48. package/dist/components/user/internal/States.js +4 -4
  49. package/dist/lib/lexical-doc.js +1 -1
  50. package/dist/pages/admin/BlogAdmin.js +7 -7
  51. package/dist/style.css +1018 -1018
  52. package/package.json +2 -1
@@ -104,21 +104,21 @@ export function AdminPostDetail({ postId, onBack, onEdit: _onEdit, onViewRelated
104
104
  const contentHtml = useMemo(() => injectHeadingIds(sanitized, headings), [sanitized, headings]);
105
105
  const readingMinutes = post?.readingMinutes ?? (post ? estimateReadingMinutes(sanitized) : 0);
106
106
  if (!post) {
107
- return (_jsx("div", { className: "panel", children: _jsxs("div", { className: "panel-body", children: [_jsx("p", { className: "note", children: "Post not found." }), _jsx("button", { type: "button", className: "btn", onClick: onBack, children: "\u2190 Back to posts" })] }) }));
107
+ return (_jsx("div", { className: "blog_panel", children: _jsxs("div", { className: "blog_panel-body", children: [_jsx("p", { className: "blog_note", children: "Post not found." }), _jsx("button", { type: "button", className: "blog_btn", onClick: onBack, children: "\u2190 Back to posts" })] }) }));
108
108
  }
109
109
  const primaryCategory = categories[0] ?? null;
110
110
  const origin = typeof window !== "undefined" ? window.location.origin : "https://example.com";
111
- return (_jsxs("div", { className: "bp-site-article admin-post-detail", children: [_jsx(ReadingProgress, {}), _jsx(ArticleDetailHero, { homeHref: "#", homeLabel: "Blogs", category: primaryCategory ? { slug: primaryCategory.slug, name: primaryCategory.name } : null, title: post.title, excerpt: post.excerpt, publishedAt: post.publishedAt, readingMinutes: readingMinutes, authors: authors,
111
+ return (_jsxs("div", { className: "blog_bp-site-article blog_admin-post-detail", children: [_jsx(ReadingProgress, {}), _jsx(ArticleDetailHero, { homeHref: "#", homeLabel: "Blogs", category: primaryCategory ? { slug: primaryCategory.slug, name: primaryCategory.name } : null, title: post.title, excerpt: post.excerpt, publishedAt: post.publishedAt, readingMinutes: readingMinutes, authors: authors,
112
112
  /* Match /blog/[slug] post-details: blue animated hero, no media strip */
113
- mediaUrl: null, onBack: onBack, onHome: onBack }), _jsxs("main", { className: "wrap article-shell", children: [_jsx(ArticleRailDetails, { className: "rail-details-mobile", owners: authors, related: related, hrefFor: (slug) => `#/blog/${slug}`, onSelect: (slug) => {
113
+ mediaUrl: null, onBack: onBack, onHome: onBack }), _jsxs("main", { className: "blog_wrap blog_article-shell", children: [_jsx(ArticleRailDetails, { className: "blog_rail-details-mobile", owners: authors, related: related, hrefFor: (slug) => `#/blog/${slug}`, onSelect: (slug) => {
114
114
  const hit = store.filterPosts({ state: "all", brandId: post.brandId }).find((p) => p.slug === slug);
115
115
  if (hit && onViewRelated)
116
116
  onViewRelated(hit.id);
117
- } }), _jsxs("article", { className: "article", children: [media ? (_jsx("figure", { className: "article-hero-media", style: { marginBottom: 28, maxWidth: "100%" }, children: _jsx("img", { className: "article-hero-visual", src: media.url, alt: media.alt || post.title }) })) : null, _jsx("div", { className: "prose", dangerouslySetInnerHTML: { __html: contentHtml } }), categories.length > 0 || tags.length > 0 ? (_jsxs("div", { className: "tag-row", children: [categories.map((c) => (_jsx("span", { className: "tag-pill", children: c.name }, c.id))), tags.map((t) => (_jsxs("span", { className: "tag-pill", children: ["#", t.name] }, t.id)))] })) : null, _jsx("div", { className: "share-foot", children: _jsx(ShareRow, { title: post.title, slug: post.slug, origin: origin, path: `/blogs/${post.slug}` }) }), authors.map((a) => (_jsx("div", { className: "author-card", children: _jsxs("div", { children: [_jsxs("p", { className: "author-name", children: [a.name, a.jobTitle ? _jsxs("span", { children: [" \u2014 ", a.jobTitle] }) : null] }), a.bio ? _jsx("p", { className: "author-bio", children: a.bio }) : null] }) }, a.id))), _jsx(CommentSection, { postId: post.id, allowComments: post.allowComments && post.status === "published", initialComments: comments })] }), _jsxs("aside", { className: "rail", children: [_jsx(ArticleRailDetails, { className: "rail-details-desktop", owners: authors, related: related, hrefFor: (slug) => `#/blog/${slug}`, onSelect: (slug) => {
117
+ } }), _jsxs("article", { className: "blog_article", children: [media ? (_jsx("figure", { className: "blog_article-hero-media", style: { marginBottom: 28, maxWidth: "100%" }, children: _jsx("img", { className: "blog_article-hero-visual", src: media.url, alt: media.alt || post.title }) })) : null, _jsx("div", { className: "blog_prose", dangerouslySetInnerHTML: { __html: contentHtml } }), categories.length > 0 || tags.length > 0 ? (_jsxs("div", { className: "blog_tag-row", children: [categories.map((c) => (_jsx("span", { className: "blog_tag-pill", children: c.name }, c.id))), tags.map((t) => (_jsxs("span", { className: "blog_tag-pill", children: ["#", t.name] }, t.id)))] })) : null, _jsx("div", { className: "blog_share-foot", children: _jsx(ShareRow, { title: post.title, slug: post.slug, origin: origin, path: `/blogs/${post.slug}` }) }), authors.map((a) => (_jsx("div", { className: "blog_author-card", children: _jsxs("div", { children: [_jsxs("p", { className: "blog_author-name", children: [a.name, a.jobTitle ? _jsxs("span", { children: [" \u2014 ", a.jobTitle] }) : null] }), a.bio ? _jsx("p", { className: "blog_author-bio", children: a.bio }) : null] }) }, a.id))), _jsx(CommentSection, { postId: post.id, allowComments: post.allowComments && post.status === "published", initialComments: comments })] }), _jsxs("aside", { className: "blog_rail", children: [_jsx(ArticleRailDetails, { className: "blog_rail-details-desktop", owners: authors, related: related, hrefFor: (slug) => `#/blog/${slug}`, onSelect: (slug) => {
118
118
  const hit = store
119
119
  .filterPosts({ state: "all", brandId: post.brandId })
120
120
  .find((p) => p.slug === slug);
121
121
  if (hit && onViewRelated)
122
122
  onViewRelated(hit.id);
123
- } }), headings.length > 1 ? (_jsxs("nav", { className: "toc", "aria-label": "On this page", children: [_jsx("p", { className: "rail-title", children: "On this page" }), _jsx("ol", { children: headings.map((h) => (_jsx("li", { className: h.level === 3 ? "sub" : undefined, children: _jsx("a", { href: `#${h.id}`, children: h.text }) }, h.id))) })] })) : null] })] })] }));
123
+ } }), headings.length > 1 ? (_jsxs("nav", { className: "blog_toc", "aria-label": "On this page", children: [_jsx("p", { className: "blog_rail-title", children: "On this page" }), _jsx("ol", { children: headings.map((h) => (_jsx("li", { className: h.level === 3 ? "blog_sub" : undefined, children: _jsx("a", { href: `#${h.id}`, children: h.text }) }, h.id))) })] })) : null] })] })] }));
124
124
  }
@@ -31,7 +31,7 @@ export function BrandSettings({ brandId, canEdit = true }) {
31
31
  setFlash("Settings saved.");
32
32
  });
33
33
  };
34
- return (_jsxs("fieldset", { className: "settings", disabled: !canEdit, children: [!canEdit ? (_jsx("p", { className: "explain", children: "These are read-only for your account \u2014 changing a brand\u2019s domains changes where its content publishes, so it is a platform-admin job." })) : null, error ? (_jsx("p", { className: "form-error", role: "alert", children: error })) : null, flash ? (_jsx("p", { className: "form-ok", role: "status", children: flash })) : null, _jsxs("div", { className: "grid grid-2", children: [_jsxs("section", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Identity" }) }), _jsxs("div", { className: "panel-body stack", children: [_jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Brand name" }), _jsx("input", { className: "fld", value: form.name, onChange: (e) => set("name", e.target.value) })] }), _jsxs("label", { className: "fld-row", children: [_jsxs("span", { className: "fld-lbl", children: ["Internal slug ", _jsx("em", { children: "used in cache tags and preview URLs" })] }), _jsx("input", { className: "fld mono", value: form.slug, disabled: true, readOnly: true })] }), _jsxs("label", { className: "fld-row", children: [_jsxs("span", { className: "fld-lbl", children: ["Primary domain ", _jsx("em", { children: "canonical URLs are built from this" })] }), _jsx("input", { className: "fld mono", value: form.primaryDomain, onChange: (e) => set("primaryDomain", e.target.value) })] }), _jsxs("div", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Hostnames that resolve to this brand" }), _jsxs("div", { className: "chips", children: [form.domains.map((host) => (_jsxs("span", { className: "token", children: [host, _jsx("button", { type: "button", "aria-label": `Remove ${host}`, onClick: () => set("domains", form.domains.filter((h) => h !== host)), children: "\u2715" })] }, host))), form.domains.length === 0 ? _jsx("span", { className: "note", children: "None yet." }) : null] }), _jsxs("div", { className: "btn-row", children: [_jsx("input", { className: "fld mono", placeholder: "staging.brand.com or localhost:3001", value: hostDraft, onChange: (e) => setHostDraft(e.target.value), onKeyDown: (e) => {
34
+ return (_jsxs("fieldset", { className: "blog_settings", disabled: !canEdit, children: [!canEdit ? (_jsx("p", { className: "blog_explain", children: "These are read-only for your account \u2014 changing a brand\u2019s domains changes where its content publishes, so it is a platform-admin job." })) : null, error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, flash ? (_jsx("p", { className: "blog_form-ok", role: "status", children: flash })) : null, _jsxs("div", { className: "blog_grid blog_grid-2", children: [_jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Identity" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Brand name" }), _jsx("input", { className: "blog_fld", value: form.name, onChange: (e) => set("name", e.target.value) })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Internal slug ", _jsx("em", { children: "used in cache tags and preview URLs" })] }), _jsx("input", { className: "blog_fld blog_mono", value: form.slug, disabled: true, readOnly: true })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Primary domain ", _jsx("em", { children: "canonical URLs are built from this" })] }), _jsx("input", { className: "blog_fld blog_mono", value: form.primaryDomain, onChange: (e) => set("primaryDomain", e.target.value) })] }), _jsxs("div", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Hostnames that resolve to this brand" }), _jsxs("div", { className: "blog_chips", children: [form.domains.map((host) => (_jsxs("span", { className: "blog_token", children: [host, _jsx("button", { type: "button", "aria-label": `Remove ${host}`, onClick: () => set("domains", form.domains.filter((h) => h !== host)), children: "\u2715" })] }, host))), form.domains.length === 0 ? _jsx("span", { className: "blog_note", children: "None yet." }) : null] }), _jsxs("div", { className: "blog_btn-row", children: [_jsx("input", { className: "blog_fld blog_mono", placeholder: "staging.brand.com or localhost:3001", value: hostDraft, onChange: (e) => setHostDraft(e.target.value), onKeyDown: (e) => {
35
35
  if (e.key === "Enter") {
36
36
  e.preventDefault();
37
37
  if (hostDraft.trim()) {
@@ -39,12 +39,12 @@ export function BrandSettings({ brandId, canEdit = true }) {
39
39
  setHostDraft("");
40
40
  }
41
41
  }
42
- } }), _jsx("button", { type: "button", className: "btn", onClick: () => {
42
+ } }), _jsx("button", { type: "button", className: "blog_btn", onClick: () => {
43
43
  if (!hostDraft.trim())
44
44
  return;
45
45
  set("domains", [...form.domains, hostDraft.trim().toLowerCase()]);
46
46
  setHostDraft("");
47
- }, children: "Add" })] })] })] })] }), _jsxs("section", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Presentation" }) }), _jsxs("div", { className: "panel-body stack", children: [_jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Accent colour" }), _jsxs("span", { className: "colour-row", children: [_jsx("input", { type: "color", className: "colour", value: /^#[0-9a-f]{6}$/i.test(form.accent) ? form.accent : "#2e3a8c", onChange: (e) => set("accent", e.target.value), "aria-label": "Accent colour" }), _jsx("input", { className: "fld mono", value: form.accent, onChange: (e) => set("accent", e.target.value) })] })] }), _jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Body typeface" }), _jsxs("select", { className: "fld", value: form.font, onChange: (e) => set("font", e.target.value), children: [_jsx("option", { value: "serif", children: "Serif" }), _jsx("option", { value: "sans", children: "Sans-serif" })] })] }), _jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Blog index heading" }), _jsx("input", { className: "fld", value: form.blogTitle, onChange: (e) => set("blogTitle", e.target.value) })] }), _jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Blog index description" }), _jsx("textarea", { className: "fld", rows: 2, value: form.blogDescription, onChange: (e) => set("blogDescription", e.target.value) })] })] })] }), _jsxs("section", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Search defaults" }) }), _jsxs("div", { className: "panel-body stack", children: [_jsxs("label", { className: "fld-row", children: [_jsxs("span", { className: "fld-lbl", children: ["Site name ", _jsx("em", { children: "used in Open Graph and Organization schema" })] }), _jsx("input", { className: "fld", value: form.siteName, onChange: (e) => set("siteName", e.target.value) })] }), _jsxs("label", { className: "fld-row", children: [_jsxs("span", { className: "fld-lbl", children: ["Title template ", _jsx("em", { children: "%s is the page title, %site% the site name" })] }), _jsx("input", { className: "fld mono", value: form.titleTemplate, onChange: (e) => set("titleTemplate", e.target.value) })] })] })] }), _jsxs("section", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Measurement" }) }), _jsxs("div", { className: "panel-body stack", children: [_jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "GA4 measurement id" }), _jsx("input", { className: "fld mono", placeholder: "G-XXXXXXXXXX", value: form.ga4MeasurementId, onChange: (e) => set("ga4MeasurementId", e.target.value) })] }), _jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Search Console verification" }), _jsx("input", { className: "fld mono", value: form.gscVerification, onChange: (e) => set("gscVerification", e.target.value) })] })] })] })] }), canEdit ? (_jsxs("div", { className: "save-bar", children: [_jsx("span", { className: "note", children: "Mock save \u2014 changes stay in this session only." }), _jsx("button", { type: "button", className: "btn btn-primary", onClick: submit, disabled: pending, children: pending ? "Saving…" : "Save settings" })] })) : null] }));
47
+ }, children: "Add" })] })] })] })] }), _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Presentation" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Accent colour" }), _jsxs("span", { className: "blog_colour-row", children: [_jsx("input", { type: "color", className: "blog_colour", value: /^#[0-9a-f]{6}$/i.test(form.accent) ? form.accent : "#2e3a8c", onChange: (e) => set("accent", e.target.value), "aria-label": "Accent colour" }), _jsx("input", { className: "blog_fld blog_mono", value: form.accent, onChange: (e) => set("accent", e.target.value) })] })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Body typeface" }), _jsxs("select", { className: "blog_fld", value: form.font, onChange: (e) => set("font", e.target.value), children: [_jsx("option", { value: "serif", children: "Serif" }), _jsx("option", { value: "sans", children: "Sans-serif" })] })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Blog index heading" }), _jsx("input", { className: "blog_fld", value: form.blogTitle, onChange: (e) => set("blogTitle", e.target.value) })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Blog index description" }), _jsx("textarea", { className: "blog_fld", rows: 2, value: form.blogDescription, onChange: (e) => set("blogDescription", e.target.value) })] })] })] }), _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Search defaults" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Site name ", _jsx("em", { children: "used in Open Graph and Organization schema" })] }), _jsx("input", { className: "blog_fld", value: form.siteName, onChange: (e) => set("siteName", e.target.value) })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Title template ", _jsx("em", { children: "%s is the page title, %site% the site name" })] }), _jsx("input", { className: "blog_fld blog_mono", value: form.titleTemplate, onChange: (e) => set("titleTemplate", e.target.value) })] })] })] }), _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Measurement" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "GA4 measurement id" }), _jsx("input", { className: "blog_fld blog_mono", placeholder: "G-XXXXXXXXXX", value: form.ga4MeasurementId, onChange: (e) => set("ga4MeasurementId", e.target.value) })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Search Console verification" }), _jsx("input", { className: "blog_fld blog_mono", value: form.gscVerification, onChange: (e) => set("gscVerification", e.target.value) })] })] })] })] }), canEdit ? (_jsxs("div", { className: "blog_save-bar", children: [_jsx("span", { className: "blog_note", children: "Mock save \u2014 changes stay in this session only." }), _jsx("button", { type: "button", className: "blog_btn blog_btn-primary", onClick: submit, disabled: pending, children: pending ? "Saving…" : "Save settings" })] })) : null] }));
48
48
  }
49
49
  export function BrandsList({ onOpenSettings }) {
50
50
  const store = useAdminMock();
@@ -57,7 +57,7 @@ export function BrandsList({ onOpenSettings }) {
57
57
  .reduce((sum, p) => sum + (p.views ?? 0), 0);
58
58
  return { tenant: t, live, drafts, last: latest?.publishedAt ?? null, views };
59
59
  });
60
- return (_jsxs(_Fragment, { children: [_jsxs("p", { className: "explain", children: ["Onboarding a brand is ", _jsx("b", { children: "a row here plus a hostname" }), ", not a code fork. The renderer matches the incoming ", _jsx("span", { className: "mono", children: "Host" }), " header against the hostname list."] }), _jsxs("section", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "All brands" }), _jsx("span", { className: "hint", children: "views over 30d" })] }), _jsx("div", { className: "tw", children: _jsxs("table", { className: "tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Brand" }), _jsx("th", { className: "num", children: "Live" }), _jsx("th", { className: "num", children: "Drafts" }), _jsx("th", { children: "Last published" }), _jsx("th", { className: "num", children: "Views" })] }) }), _jsx("tbody", { children: rows.map(({ tenant, live, drafts, last, views }) => (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("button", { type: "button", className: "row-title", onClick: () => onOpenSettings?.(tenant.id), children: tenant.name }), _jsx("span", { className: "cell-sub mono", children: tenant.primaryDomain }), _jsx("div", { className: "row-actions", children: _jsx("button", { type: "button", onClick: () => onOpenSettings?.(tenant.id), children: "Settings" }) })] }), _jsx("td", { className: "num", children: live }), _jsx("td", { className: "num", children: drafts }), _jsx("td", { className: "muted", children: last ? relativeTime(last) : "—" }), _jsx("td", { className: "num", children: views })] }, tenant.id))) })] }) })] })] }));
60
+ return (_jsxs(_Fragment, { children: [_jsxs("p", { className: "blog_explain", children: ["Onboarding a brand is ", _jsx("b", { children: "a row here plus a hostname" }), ", not a code fork. The renderer matches the incoming ", _jsx("span", { className: "blog_mono", children: "Host" }), " header against the hostname list."] }), _jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "All brands" }), _jsx("span", { className: "blog_hint", children: "views over 30d" })] }), _jsx("div", { className: "blog_tw", children: _jsxs("table", { className: "blog_tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Brand" }), _jsx("th", { className: "blog_num", children: "Live" }), _jsx("th", { className: "blog_num", children: "Drafts" }), _jsx("th", { children: "Last published" }), _jsx("th", { className: "blog_num", children: "Views" })] }) }), _jsx("tbody", { children: rows.map(({ tenant, live, drafts, last, views }) => (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("button", { type: "button", className: "blog_row-title", onClick: () => onOpenSettings?.(tenant.id), children: tenant.name }), _jsx("span", { className: "blog_cell-sub blog_mono", children: tenant.primaryDomain }), _jsx("div", { className: "blog_row-actions", children: _jsx("button", { type: "button", onClick: () => onOpenSettings?.(tenant.id), children: "Settings" }) })] }), _jsx("td", { className: "blog_num", children: live }), _jsx("td", { className: "blog_num", children: drafts }), _jsx("td", { className: "blog_muted", children: last ? relativeTime(last) : "—" }), _jsx("td", { className: "blog_num", children: views })] }, tenant.id))) })] }) })] })] }));
61
61
  }
62
62
  export function ProfilePanel() {
63
63
  const store = useAdminMock();
@@ -67,5 +67,5 @@ export function ProfilePanel() {
67
67
  .split("-")
68
68
  .map((w) => w[0].toUpperCase() + w.slice(1))
69
69
  .join(" ");
70
- return (_jsxs("section", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Account" }) }), _jsxs("div", { className: "panel-body profile-panel", children: [_jsxs("div", { className: "profile-hero", children: [_jsx("span", { className: "profile-avatar", "aria-hidden": "true", children: (me.name ?? me.email).slice(0, 1).toUpperCase() }), _jsxs("div", { children: [_jsx("p", { className: "profile-name", children: me.name }), _jsx("p", { className: "profile-email mono", children: me.email })] })] }), _jsxs("dl", { className: "facts profile-facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "Platform role" }), _jsx("dd", { children: me.globalRole === "platform-admin" ? "Platform admin" : roleLabel(me.globalRole || "none") })] }), _jsxs("div", { children: [_jsx("dt", { children: "Brands" }), _jsx("dd", { children: store.brands.length })] })] }), self && self.roles.length > 0 ? (_jsxs("div", { className: "profile-roles", children: [_jsx("h3", { children: "Brand access" }), _jsx("ul", { className: "profile-role-list", children: self.roles.map((row) => (_jsxs("li", { children: [_jsx("span", { className: "profile-role-brand", children: row.tenantName }), _jsx("span", { className: "profile-role-level", children: roleLabel(String(row.role)) })] }, `${row.tenant}-${row.role}`))) })] })) : null] })] }));
70
+ return (_jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Account" }) }), _jsxs("div", { className: "blog_panel-body blog_profile-panel", children: [_jsxs("div", { className: "blog_profile-hero", children: [_jsx("span", { className: "blog_profile-avatar", "aria-hidden": "true", children: (me.name ?? me.email).slice(0, 1).toUpperCase() }), _jsxs("div", { children: [_jsx("p", { className: "blog_profile-name", children: me.name }), _jsx("p", { className: "blog_profile-email blog_mono", children: me.email })] })] }), _jsxs("dl", { className: "blog_facts blog_profile-facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "Platform role" }), _jsx("dd", { children: me.globalRole === "platform-admin" ? "Platform admin" : roleLabel(me.globalRole || "none") })] }), _jsxs("div", { children: [_jsx("dt", { children: "Brands" }), _jsx("dd", { children: store.brands.length })] })] }), self && self.roles.length > 0 ? (_jsxs("div", { className: "blog_profile-roles", children: [_jsx("h3", { children: "Brand access" }), _jsx("ul", { className: "blog_profile-role-list", children: self.roles.map((row) => (_jsxs("li", { children: [_jsx("span", { className: "blog_profile-role-brand", children: row.tenantName }), _jsx("span", { className: "blog_profile-role-level", children: roleLabel(String(row.role)) })] }, `${row.tenant}-${row.role}`))) })] })) : null] })] }));
71
71
  }
@@ -8,5 +8,5 @@ export function BrandSwitcher() {
8
8
  return null;
9
9
  const active = store.activeBrand;
10
10
  const label = active?.name ?? "All brands";
11
- return (_jsxs("details", { className: "menu", children: [_jsxs("summary", { className: "btn", children: [_jsx("span", { className: "dot", style: { background: active?.accent || "var(--viz-1)" }, "aria-hidden": "true" }), label, _jsx("span", { className: "caret", "aria-hidden": "true", children: "\u25BE" })] }), _jsxs("div", { className: "menu-panel", children: [_jsx("button", { type: "button", "aria-current": !active ? "true" : undefined, onClick: () => store.setActiveBrandId(null), children: "All brands" }), brands.map((t) => (_jsxs("button", { type: "button", "aria-current": active?.id === t.id ? "true" : undefined, onClick: () => store.setActiveBrandId(t.id), children: [_jsx("span", { className: "dot", style: { background: t.accent || "var(--viz-2)" }, "aria-hidden": "true" }), t.name] }, t.id)))] })] }));
11
+ return (_jsxs("details", { className: "blog_menu", children: [_jsxs("summary", { className: "blog_btn", children: [_jsx("span", { className: "blog_dot", style: { background: active?.accent || "var(--viz-1)" }, "aria-hidden": "true" }), label, _jsx("span", { className: "blog_caret", "aria-hidden": "true", children: "\u25BE" })] }), _jsxs("div", { className: "blog_menu-panel", children: [_jsx("button", { type: "button", "aria-current": !active ? "true" : undefined, onClick: () => store.setActiveBrandId(null), children: "All brands" }), brands.map((t) => (_jsxs("button", { type: "button", "aria-current": active?.id === t.id ? "true" : undefined, onClick: () => store.setActiveBrandId(t.id), children: [_jsx("span", { className: "blog_dot", style: { background: t.accent || "var(--viz-2)" }, "aria-hidden": "true" }), t.name] }, t.id)))] })] }));
12
12
  }
@@ -6,10 +6,10 @@ import { REVIEW_LABELS } from "./lib/publishing";
6
6
  */
7
7
  export const StateChip = ({ status, reviewState, }) => {
8
8
  if (status === "published")
9
- return _jsx("span", { className: "chip chip-live", children: "Live" });
9
+ return _jsx("span", { className: "blog_chip blog_chip-live", children: "Live" });
10
10
  const rs = (reviewState ?? "writing");
11
- const cls = rs === "in-review" ? "chip-review" : rs === "approved" ? "chip-approved" : "chip-writing";
12
- return _jsx("span", { className: `chip ${cls}`, children: REVIEW_LABELS[rs] ?? rs });
11
+ const cls = rs === "in-review" ? "blog_chip-review" : rs === "approved" ? "blog_chip-approved" : "blog_chip-writing";
12
+ return _jsx("span", { className: `blog_chip ${cls}`, children: REVIEW_LABELS[rs] ?? rs });
13
13
  };
14
- export const BrandChip = ({ name }) => (_jsx("span", { className: "chip chip-brand", children: name }));
15
- export const BlockedChip = ({ count }) => (_jsxs("span", { className: "chip chip-blocked", children: [count, " blocker", count === 1 ? "" : "s"] }));
14
+ export const BrandChip = ({ name }) => (_jsx("span", { className: "blog_chip blog_chip-brand", children: name }));
15
+ export const BlockedChip = ({ count }) => (_jsxs("span", { className: "blog_chip blog_chip-blocked", children: [count, " blocker", count === 1 ? "" : "s"] }));
@@ -15,16 +15,16 @@ export function CommentsManager({ onOpenPost }) {
15
15
  alert(res.error);
16
16
  });
17
17
  };
18
- return (_jsxs("section", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "All comments" }), _jsx("span", { className: "hint", children: rows.length })] }), rows.length === 0 ? (_jsx("p", { className: "d-empty", children: "No comments yet." })) : (_jsx("div", { className: "tw", children: _jsxs("table", { className: "tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Comment" }), _jsx("th", { children: "Post" }), _jsx("th", { children: "Status" }), showBrand ? _jsx("th", { children: "Brand" }) : null, _jsx("th", { children: "Date" })] }) }), _jsx("tbody", { children: rows.map((row) => {
18
+ return (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "All comments" }), _jsx("span", { className: "blog_hint", children: rows.length })] }), rows.length === 0 ? (_jsx("p", { className: "blog_d-empty", children: "No comments yet." })) : (_jsx("div", { className: "blog_tw", children: _jsxs("table", { className: "blog_tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Comment" }), _jsx("th", { children: "Post" }), _jsx("th", { children: "Status" }), showBrand ? _jsx("th", { children: "Brand" }) : null, _jsx("th", { children: "Date" })] }) }), _jsx("tbody", { children: rows.map((row) => {
19
19
  const canModerate = canModerateAll || (row.postOwnerId != null && row.postOwnerId === currentUserId);
20
- return (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("span", { className: "row-title", children: row.authorName }), row.authorEmail ? _jsx("span", { className: "cell-sub", children: row.authorEmail }) : null, _jsx("span", { className: "cell-sub", style: { whiteSpace: "pre-wrap" }, children: row.body.length > 180 ? `${row.body.slice(0, 180)}…` : row.body }), canModerate ? (_jsxs("div", { className: "row-actions", children: [row.status !== "approved" ? (_jsx("button", { type: "button", disabled: pending, onClick: () => run(() => store.setCommentStatus(row.id, "approved")), children: "Approve" })) : null, row.status !== "rejected" ? (_jsx("button", { type: "button", disabled: pending, onClick: () => run(() => store.setCommentStatus(row.id, "rejected")), children: "Reject" })) : null, canModerateAll ? (_jsx("button", { type: "button", className: "danger", disabled: pending, onClick: () => {
20
+ return (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("span", { className: "blog_row-title", children: row.authorName }), row.authorEmail ? _jsx("span", { className: "blog_cell-sub", children: row.authorEmail }) : null, _jsx("span", { className: "blog_cell-sub", style: { whiteSpace: "pre-wrap" }, children: row.body.length > 180 ? `${row.body.slice(0, 180)}…` : row.body }), canModerate ? (_jsxs("div", { className: "blog_row-actions", children: [row.status !== "approved" ? (_jsx("button", { type: "button", disabled: pending, onClick: () => run(() => store.setCommentStatus(row.id, "approved")), children: "Approve" })) : null, row.status !== "rejected" ? (_jsx("button", { type: "button", disabled: pending, onClick: () => run(() => store.setCommentStatus(row.id, "rejected")), children: "Reject" })) : null, canModerateAll ? (_jsx("button", { type: "button", className: "blog_danger", disabled: pending, onClick: () => {
21
21
  if (confirm("Delete this comment permanently?")) {
22
22
  run(() => store.deleteComment(row.id));
23
23
  }
24
- }, children: "Delete" })) : null] })) : null] }), _jsx("td", { children: row.postId ? (_jsx("button", { type: "button", className: "btn btn-ghost btn-sm", onClick: () => onOpenPost?.(row.postId), children: row.postTitle || "Post" })) : ("—") }), _jsx("td", { children: _jsx("span", { className: `chip ${row.status === "approved"
25
- ? "chip-approved"
24
+ }, children: "Delete" })) : null] })) : null] }), _jsx("td", { children: row.postId ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-ghost blog_btn-sm", onClick: () => onOpenPost?.(row.postId), children: row.postTitle || "Post" })) : ("—") }), _jsx("td", { children: _jsx("span", { className: `blog_chip ${row.status === "approved"
25
+ ? "blog_chip-approved"
26
26
  : row.status === "pending"
27
- ? "chip-writing"
28
- : "chip-writing"}`, children: row.status }) }), showBrand ? _jsx("td", { children: row.brandName || "—" }) : null, _jsx("td", { className: "mono", children: new Date(row.createdAt).toLocaleString() })] }, row.id));
27
+ ? "blog_chip-writing"
28
+ : "blog_chip-writing"}`, children: row.status }) }), showBrand ? _jsx("td", { children: row.brandName || "—" }) : null, _jsx("td", { className: "blog_mono", children: new Date(row.createdAt).toLocaleString() })] }, row.id));
29
29
  }) })] }) }))] }));
30
30
  }
@@ -30,5 +30,5 @@ export function Dashboard() {
30
30
  { label: "Tech review", value: 0, tone: 3 },
31
31
  { label: "Approved", value: 1, tone: 4 }
32
32
  ];
33
- return (_jsxs(_Fragment, { children: [_jsxs("section", { className: "kpis", children: [_jsxs("div", { className: "kpi", children: [_jsxs("span", { className: "kpi-l", children: ["Views \u00B7 ", range, "d"] }), _jsxs("div", { className: "kpi-row", children: [_jsx("span", { className: "kpi-n", children: totalViews }), _jsx(Sparkline, { data: series.map((d) => d.views) })] }), _jsxs("div", { className: "kpi-delta", children: [_jsx("span", { className: "up", children: "\u2191 366.7%" }), " vs previous 30d"] })] }), _jsxs("div", { className: "kpi", children: [_jsx("span", { className: "kpi-l", children: "Unique readers" }), _jsx("div", { className: "kpi-row", children: _jsx("span", { className: "kpi-n", children: "14" }) }), _jsx("span", { className: "kpi-sub", children: "1.00 views per reader" })] }), _jsxs("div", { className: "kpi", children: [_jsx("span", { className: "kpi-l", children: "Needs attention" }), _jsx("div", { className: "kpi-row", children: _jsx("span", { className: "kpi-n", children: "0" }) }), _jsx("span", { className: "kpi-sub", children: "in review, or approved but blocked" })] }), _jsxs("div", { className: "kpi", children: [_jsx("span", { className: "kpi-l", children: "Published" }), _jsx("div", { className: "kpi-row", children: _jsx("span", { className: "kpi-n", children: "8" }) }), _jsx("span", { className: "kpi-sub", children: "0 scheduled next" })] })] }), _jsxs("section", { className: "grid grid-2", children: [_jsxs("div", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "Views per day" }), _jsx("span", { className: "hint", children: "hover for a day" })] }), _jsx("div", { className: "panel-body flush", children: _jsx(TrendArea, { data: series }) })] }), _jsxs("div", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "Editorial pipeline" }), _jsx("span", { className: "hint", children: "4 posts in progress" })] }), _jsx("div", { className: "panel-body", children: _jsx(Funnel, { stages: funnelStages }) })] })] }), _jsxs("section", { className: "grid grid-3", children: [_jsxs("div", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "Most read" }), _jsxs("span", { className: "hint", children: [range, "d"] })] }), _jsx("div", { className: "panel-body", children: _jsx(BarList, { items: top, colorVar: "var(--viz-1)" }) })] }), _jsxs("div", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Published by category" }) }), _jsx("div", { className: "panel-body", children: _jsx(BarList, { items: categories, colorVar: "var(--viz-3)" }) })] }), _jsxs("div", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "Scheduled" }), _jsx("span", { className: "hint", children: "0" })] }), _jsx("div", { className: "panel-body", children: _jsx("p", { className: "d-empty", children: "Nothing scheduled." }) })] })] }), _jsxs("section", { className: "grid grid-2", children: [_jsxs("div", { className: "panel", children: [_jsxs("div", { className: "panel-head", children: [_jsx("h2", { children: "By brand" }), _jsxs("span", { className: "hint", children: ["views over ", range, "d"] })] }), _jsx("div", { className: "panel-body flush", children: _jsx("div", { className: "tw", children: _jsxs("table", { className: "tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Brand" }), _jsx("th", { children: "Views" }), _jsx("th", { className: "num", children: "Live" }), _jsx("th", { className: "num", children: "Drafts" }), _jsx("th", { className: "num", children: "Last published" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: _jsx("a", { href: "/admin?brand=halcyon", children: "Halcyon Health" }) }), _jsx("td", { children: _jsxs("div", { className: "bar-cell", children: [_jsx("span", { className: "bar-cell-n", children: "9" }), _jsx("span", { className: "mini-track", children: _jsx("span", { className: "mini-fill", style: { width: '100%' } }) })] }) }), _jsx("td", { className: "num", children: "6" }), _jsx("td", { className: "num", children: "1" }), _jsx("td", { className: "num", children: "2d ago" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("a", { href: "/admin?brand=northbeam", children: "Northbeam" }) }), _jsx("td", { children: _jsxs("div", { className: "bar-cell", children: [_jsx("span", { className: "bar-cell-n", children: "5" }), _jsx("span", { className: "mini-track", children: _jsx("span", { className: "mini-fill", style: { width: '55%' } }) })] }) }), _jsx("td", { className: "num", children: "2" }), _jsx("td", { className: "num", children: "0" }), _jsx("td", { className: "num", children: "1mo ago" })] })] })] }) }) })] }), _jsxs("div", { className: "panel", children: [_jsx("div", { className: "panel-head", children: _jsx("h2", { children: "Recently published" }) }), _jsxs("div", { className: "panel-body flush", children: [_jsxs("div", { className: "row", children: [_jsxs("div", { className: "row-main", children: [_jsx("a", { href: "#", className: "t", children: "How to choose the best app development company in the middle east?" }), _jsxs("div", { className: "row-sub", children: [_jsx("span", { children: "2d ago" }), _jsx("a", { href: "#", children: "View \u2192" })] })] }), _jsx("div", { className: "row-right", children: _jsx("span", { className: "chip chip-brand", children: "Halcyon Health" }) })] }), _jsxs("div", { className: "row", children: [_jsxs("div", { className: "row-main", children: [_jsx("a", { href: "#", className: "t", children: "Hello this is jason speaking how may i help you" }), _jsxs("div", { className: "row-sub", children: [_jsx("span", { children: "16d ago" }), _jsx("a", { href: "#", children: "View \u2192" })] })] }), _jsx("div", { className: "row-right", children: _jsx("span", { className: "chip chip-brand", children: "Halcyon Health" }) })] })] })] })] }), _jsx("p", { className: "note", children: "Showing 2 brands \u2014 the ones your account has access to. Numbers come from the tracking beacon on published articles." })] }));
33
+ return (_jsxs(_Fragment, { children: [_jsxs("section", { className: "blog_kpis", children: [_jsxs("div", { className: "blog_kpi", children: [_jsxs("span", { className: "blog_kpi-l", children: ["Views \u00B7 ", range, "d"] }), _jsxs("div", { className: "blog_kpi-row", children: [_jsx("span", { className: "blog_kpi-n", children: totalViews }), _jsx(Sparkline, { data: series.map((d) => d.views) })] }), _jsxs("div", { className: "blog_kpi-delta", children: [_jsx("span", { className: "blog_up", children: "\u2191 366.7%" }), " vs previous 30d"] })] }), _jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "Unique readers" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: "14" }) }), _jsx("span", { className: "blog_kpi-sub", children: "1.00 views per reader" })] }), _jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "Needs attention" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: "0" }) }), _jsx("span", { className: "blog_kpi-sub", children: "in review, or approved but blocked" })] }), _jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "Published" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: "8" }) }), _jsx("span", { className: "blog_kpi-sub", children: "0 scheduled next" })] })] }), _jsxs("section", { className: "blog_grid blog_grid-2", children: [_jsxs("div", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Views per day" }), _jsx("span", { className: "blog_hint", children: "hover for a day" })] }), _jsx("div", { className: "blog_panel-body blog_flush", children: _jsx(TrendArea, { data: series }) })] }), _jsxs("div", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Editorial pipeline" }), _jsx("span", { className: "blog_hint", children: "4 posts in progress" })] }), _jsx("div", { className: "blog_panel-body", children: _jsx(Funnel, { stages: funnelStages }) })] })] }), _jsxs("section", { className: "blog_grid blog_grid-3", children: [_jsxs("div", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Most read" }), _jsxs("span", { className: "blog_hint", children: [range, "d"] })] }), _jsx("div", { className: "blog_panel-body", children: _jsx(BarList, { items: top, colorVar: "var(--viz-1)" }) })] }), _jsxs("div", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Published by category" }) }), _jsx("div", { className: "blog_panel-body", children: _jsx(BarList, { items: categories, colorVar: "var(--viz-3)" }) })] }), _jsxs("div", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Scheduled" }), _jsx("span", { className: "blog_hint", children: "0" })] }), _jsx("div", { className: "blog_panel-body", children: _jsx("p", { className: "blog_d-empty", children: "Nothing scheduled." }) })] })] }), _jsxs("section", { className: "blog_grid blog_grid-2", children: [_jsxs("div", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "By brand" }), _jsxs("span", { className: "blog_hint", children: ["views over ", range, "d"] })] }), _jsx("div", { className: "blog_panel-body blog_flush", children: _jsx("div", { className: "blog_tw", children: _jsxs("table", { className: "blog_tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Brand" }), _jsx("th", { children: "Views" }), _jsx("th", { className: "blog_num", children: "Live" }), _jsx("th", { className: "blog_num", children: "Drafts" }), _jsx("th", { className: "blog_num", children: "Last published" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: _jsx("a", { href: "/admin?brand=halcyon", children: "Halcyon Health" }) }), _jsx("td", { children: _jsxs("div", { className: "blog_bar-cell", children: [_jsx("span", { className: "blog_bar-cell-n", children: "9" }), _jsx("span", { className: "blog_mini-track", children: _jsx("span", { className: "blog_mini-fill", style: { width: '100%' } }) })] }) }), _jsx("td", { className: "blog_num", children: "6" }), _jsx("td", { className: "blog_num", children: "1" }), _jsx("td", { className: "blog_num", children: "2d ago" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("a", { href: "/admin?brand=northbeam", children: "Northbeam" }) }), _jsx("td", { children: _jsxs("div", { className: "blog_bar-cell", children: [_jsx("span", { className: "blog_bar-cell-n", children: "5" }), _jsx("span", { className: "blog_mini-track", children: _jsx("span", { className: "blog_mini-fill", style: { width: '55%' } }) })] }) }), _jsx("td", { className: "blog_num", children: "2" }), _jsx("td", { className: "blog_num", children: "0" }), _jsx("td", { className: "blog_num", children: "1mo ago" })] })] })] }) }) })] }), _jsxs("div", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Recently published" }) }), _jsxs("div", { className: "blog_panel-body blog_flush", children: [_jsxs("div", { className: "blog_row", children: [_jsxs("div", { className: "blog_row-main", children: [_jsx("a", { href: "#", className: "blog_t", children: "How to choose the best app development company in the middle east?" }), _jsxs("div", { className: "blog_row-sub", children: [_jsx("span", { children: "2d ago" }), _jsx("a", { href: "#", children: "View \u2192" })] })] }), _jsx("div", { className: "blog_row-right", children: _jsx("span", { className: "blog_chip blog_chip-brand", children: "Halcyon Health" }) })] }), _jsxs("div", { className: "blog_row", children: [_jsxs("div", { className: "blog_row-main", children: [_jsx("a", { href: "#", className: "blog_t", children: "Hello this is jason speaking how may i help you" }), _jsxs("div", { className: "blog_row-sub", children: [_jsx("span", { children: "16d ago" }), _jsx("a", { href: "#", children: "View \u2192" })] })] }), _jsx("div", { className: "blog_row-right", children: _jsx("span", { className: "blog_chip blog_chip-brand", children: "Halcyon Health" }) })] })] })] })] }), _jsx("p", { className: "blog_note", children: "Showing 2 brands \u2014 the ones your account has access to. Numbers come from the tracking beacon on published articles." })] }));
34
34
  }
@@ -109,11 +109,11 @@ export function MediaLibrary() {
109
109
  });
110
110
  });
111
111
  };
112
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "filterbar", children: [_jsx("input", { className: "fld", type: "search", value: query, placeholder: "Search alt text or filename\u2026", "aria-label": "Search images", onChange: (e) => setQuery(e.target.value) }), _jsx("button", { type: "button", className: "btn btn-primary", onClick: () => fileRef.current?.click(), disabled: !!uploading, children: uploading ? `Uploading ${uploading.done}/${uploading.total}…` : "+ Upload images" }), _jsxs("span", { className: "note", children: [count, " image", count === 1 ? "" : "s", " \u00B7 ", tenant ? tenantName : "all brands"] })] }), _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp,image/avif,image/gif", multiple: true, hidden: true, onChange: (e) => {
112
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "blog_filterbar", children: [_jsx("input", { className: "blog_fld", type: "search", value: query, placeholder: "Search alt text or filename\u2026", "aria-label": "Search images", onChange: (e) => setQuery(e.target.value) }), _jsx("button", { type: "button", className: "blog_btn blog_btn-primary", onClick: () => fileRef.current?.click(), disabled: !!uploading, children: uploading ? `Uploading ${uploading.done}/${uploading.total}…` : "+ Upload images" }), _jsxs("span", { className: "blog_note", children: [count, " image", count === 1 ? "" : "s", " \u00B7 ", tenant ? tenantName : "all brands"] })] }), _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp,image/avif,image/gif", multiple: true, hidden: true, onChange: (e) => {
113
113
  if (e.target.files?.length)
114
114
  void upload(e.target.files);
115
115
  e.target.value = "";
116
- } }), error ? (_jsx("p", { className: "form-error", role: "alert", children: error })) : null, flash ? (_jsx("p", { className: "form-ok", role: "status", children: flash })) : null, _jsx("p", { className: "explain", children: "Uploaded images are stored on the Blog Platform API and shown here for every brand." }), _jsxs("section", { className: `panel dropzone${dragging ? " is-dragging" : ""}`, onDragOver: (e) => {
116
+ } }), error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, flash ? (_jsx("p", { className: "blog_form-ok", role: "status", children: flash })) : null, _jsx("p", { className: "blog_explain", children: "Uploaded images are stored on the Blog Platform API and shown here for every brand." }), _jsxs("section", { className: `blog_panel blog_dropzone${dragging ? " blog_is-dragging" : ""}`, onDragOver: (e) => {
117
117
  e.preventDefault();
118
118
  setDragging(true);
119
119
  }, onDragLeave: () => setDragging(false), onDrop: (e) => {
@@ -121,14 +121,14 @@ export function MediaLibrary() {
121
121
  setDragging(false);
122
122
  if (e.dataTransfer.files?.length)
123
123
  void upload(e.dataTransfer.files);
124
- }, children: [items.length === 0 && !loading ? (_jsx("p", { className: "d-empty", children: "Nothing here yet \u2014 drop images anywhere on this panel to upload." })) : (_jsx("div", { className: "media-grid", children: items.map((item) => (_jsxs("button", { type: "button", className: "media-card", onClick: () => openDetail(item), children: [item.thumbUrl || item.url ? (_jsx("img", { src: item.thumbUrl || item.url, alt: "", loading: "lazy" })) : (_jsx("span", { className: "pick-blank" })), _jsxs("span", { className: "media-meta", children: [_jsx("span", { className: "media-alt", children: item.alt || item.filename || "Image" }), _jsxs("span", { className: "media-sub", children: [item.width && item.height ? `${item.width}×${item.height}` : "—", " \u00B7 ", kb(item.filesize)] })] })] }, item.id))) })), hasMore ? (_jsx("div", { className: "modal-more", children: _jsx("button", { type: "button", className: "btn", disabled: loading, onClick: () => {
124
+ }, children: [items.length === 0 && !loading ? (_jsx("p", { className: "blog_d-empty", children: "Nothing here yet \u2014 drop images anywhere on this panel to upload." })) : (_jsx("div", { className: "blog_media-grid", children: items.map((item) => (_jsxs("button", { type: "button", className: "blog_media-card", onClick: () => openDetail(item), children: [item.thumbUrl || item.url ? (_jsx("img", { src: item.thumbUrl || item.url, alt: "", loading: "lazy" })) : (_jsx("span", { className: "blog_pick-blank" })), _jsxs("span", { className: "blog_media-meta", children: [_jsx("span", { className: "blog_media-alt", children: item.alt || item.filename || "Image" }), _jsxs("span", { className: "blog_media-sub", children: [item.width && item.height ? `${item.width}×${item.height}` : "—", " \u00B7 ", kb(item.filesize)] })] })] }, item.id))) })), hasMore ? (_jsx("div", { className: "blog_modal-more", children: _jsx("button", { type: "button", className: "blog_btn", disabled: loading, onClick: () => {
125
125
  const next = page + 1;
126
126
  setPage(next);
127
127
  load(next, query, true);
128
- }, children: loading ? "Loading…" : "Load more" }) })) : null] }), open ? (_jsx("div", { className: "modal-backdrop", onMouseDown: () => setOpen(null), children: _jsxs("div", { className: "modal", role: "dialog", "aria-modal": "true", "aria-label": "Image details", onMouseDown: (e) => e.stopPropagation(), children: [_jsxs("header", { className: "modal-head", children: [_jsx("h2", { children: "Image details" }), _jsx("button", { type: "button", className: "icon-btn", onClick: () => setOpen(null), "aria-label": "Close", children: "\u2715" })] }), _jsxs("div", { className: "modal-body detail", children: [_jsx("img", { className: "detail-img", src: open.url || open.thumbUrl, alt: open.alt }), _jsxs("div", { className: "stack", children: [_jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Alt text \u2014 what a screen reader reads out" }), _jsx("textarea", { className: "fld", rows: 2, value: meta.alt, onChange: (e) => {
128
+ }, children: loading ? "Loading…" : "Load more" }) })) : null] }), open ? (_jsx("div", { className: "blog_modal-backdrop", onMouseDown: () => setOpen(null), children: _jsxs("div", { className: "blog_modal", role: "dialog", "aria-modal": "true", "aria-label": "Image details", onMouseDown: (e) => e.stopPropagation(), children: [_jsxs("header", { className: "blog_modal-head", children: [_jsx("h2", { children: "Image details" }), _jsx("button", { type: "button", className: "blog_icon-btn", onClick: () => setOpen(null), "aria-label": "Close", children: "\u2715" })] }), _jsxs("div", { className: "blog_modal-body blog_detail", children: [_jsx("img", { className: "blog_detail-img", src: open.url || open.thumbUrl, alt: open.alt }), _jsxs("div", { className: "blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Alt text \u2014 what a screen reader reads out" }), _jsx("textarea", { className: "blog_fld", rows: 2, value: meta.alt, onChange: (e) => {
129
129
  setMeta((m) => ({ ...m, alt: e.target.value }));
130
130
  setSaved(false);
131
- } })] }), _jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Caption" }), _jsx("input", { className: "fld", value: meta.caption, onChange: (e) => setMeta((m) => ({ ...m, caption: e.target.value })) })] }), _jsxs("label", { className: "fld-row", children: [_jsx("span", { className: "fld-lbl", children: "Credit" }), _jsx("input", { className: "fld", value: meta.credit, onChange: (e) => setMeta((m) => ({ ...m, credit: e.target.value })) })] }), _jsxs("dl", { className: "facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "Dimensions" }), _jsx("dd", { children: open.width && open.height ? `${open.width}×${open.height}` : "—" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Size" }), _jsx("dd", { children: kb(open.filesize) })] }), _jsxs("div", { children: [_jsx("dt", { children: "File" }), _jsx("dd", { className: "mono trunc", children: open.filename || open.url })] })] })] })] }), _jsxs("footer", { className: "modal-foot", children: [_jsx("button", { type: "button", className: "btn-danger-link", onClick: removeImage, disabled: saving, children: "Delete image" }), _jsxs("div", { className: "modal-foot-actions", children: [saved ? _jsx("span", { className: "form-ok inline", children: "Saved" }) : null, _jsx("button", { type: "button", className: "btn", onClick: () => setOpen(null), children: "Close" }), _jsx("button", { type: "button", className: "btn btn-primary", onClick: saveMeta, disabled: saving || !meta.alt.trim(), children: saving ? "Saving…" : "Save details" })] })] })] }) })) : null] }));
131
+ } })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Caption" }), _jsx("input", { className: "blog_fld", value: meta.caption, onChange: (e) => setMeta((m) => ({ ...m, caption: e.target.value })) })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Credit" }), _jsx("input", { className: "blog_fld", value: meta.credit, onChange: (e) => setMeta((m) => ({ ...m, credit: e.target.value })) })] }), _jsxs("dl", { className: "blog_facts", children: [_jsxs("div", { children: [_jsx("dt", { children: "Dimensions" }), _jsx("dd", { children: open.width && open.height ? `${open.width}×${open.height}` : "—" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Size" }), _jsx("dd", { children: kb(open.filesize) })] }), _jsxs("div", { children: [_jsx("dt", { children: "File" }), _jsx("dd", { className: "blog_mono blog_trunc", children: open.filename || open.url })] })] })] })] }), _jsxs("footer", { className: "blog_modal-foot", children: [_jsx("button", { type: "button", className: "blog_btn-danger-link", onClick: removeImage, disabled: saving, children: "Delete image" }), _jsxs("div", { className: "blog_modal-foot-actions", children: [saved ? _jsx("span", { className: "blog_form-ok blog_inline", children: "Saved" }) : null, _jsx("button", { type: "button", className: "blog_btn", onClick: () => setOpen(null), children: "Close" }), _jsx("button", { type: "button", className: "blog_btn blog_btn-primary", onClick: saveMeta, disabled: saving || !meta.alt.trim(), children: saving ? "Saving…" : "Save details" })] })] })] }) })) : null] }));
132
132
  }
133
133
  /** @deprecated Prefer MediaLibrary — kept for export compatibility. */
134
134
  export function MediaManager() {
@@ -72,11 +72,11 @@ export function MediaPicker({ open, brandId, onClose, onSelect, title = "Choose
72
72
  };
73
73
  if (!open)
74
74
  return null;
75
- return (_jsx("div", { className: "modal-backdrop", onMouseDown: onClose, children: _jsxs("div", { className: "modal modal-wide", role: "dialog", "aria-modal": "true", "aria-label": title, onMouseDown: (e) => e.stopPropagation(), children: [_jsxs("header", { className: "modal-head", children: [_jsx("h2", { children: title }), _jsxs("div", { className: "modal-head-actions", children: [_jsx("input", { className: "fld", type: "search", placeholder: "Search alt text or filename\u2026", value: query, onChange: (e) => setQuery(e.target.value) }), _jsx("button", { type: "button", className: "btn", onClick: () => fileRef.current?.click(), disabled: uploading, children: uploading ? "Uploading…" : "Upload" }), _jsx("button", { type: "button", className: "icon-btn", onClick: onClose, "aria-label": "Close", children: "\u2715" })] })] }), _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp,image/avif,image/gif", multiple: true, hidden: true, onChange: (e) => {
75
+ return (_jsx("div", { className: "blog_modal-backdrop", onMouseDown: onClose, children: _jsxs("div", { className: "blog_modal blog_modal-wide", role: "dialog", "aria-modal": "true", "aria-label": title, onMouseDown: (e) => e.stopPropagation(), children: [_jsxs("header", { className: "blog_modal-head", children: [_jsx("h2", { children: title }), _jsxs("div", { className: "blog_modal-head-actions", children: [_jsx("input", { className: "blog_fld", type: "search", placeholder: "Search alt text or filename\u2026", value: query, onChange: (e) => setQuery(e.target.value) }), _jsx("button", { type: "button", className: "blog_btn", onClick: () => fileRef.current?.click(), disabled: uploading, children: uploading ? "Uploading…" : "Upload" }), _jsx("button", { type: "button", className: "blog_icon-btn", onClick: onClose, "aria-label": "Close", children: "\u2715" })] })] }), _jsx("input", { ref: fileRef, type: "file", accept: "image/jpeg,image/png,image/webp,image/avif,image/gif", multiple: true, hidden: true, onChange: (e) => {
76
76
  if (e.target.files?.length)
77
77
  void upload(e.target.files);
78
78
  e.target.value = "";
79
- } }), error ? (_jsx("p", { className: "form-error", role: "alert", children: error })) : null, _jsxs("div", { className: `modal-body dropzone${dragging ? " is-dragging" : ""}`, onDragOver: (e) => {
79
+ } }), error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, _jsxs("div", { className: `blog_modal-body blog_dropzone${dragging ? " blog_is-dragging" : ""}`, onDragOver: (e) => {
80
80
  e.preventDefault();
81
81
  setDragging(true);
82
82
  }, onDragLeave: () => setDragging(false), onDrop: (e) => {
@@ -84,9 +84,9 @@ export function MediaPicker({ open, brandId, onClose, onSelect, title = "Choose
84
84
  setDragging(false);
85
85
  if (e.dataTransfer.files?.length)
86
86
  void upload(e.dataTransfer.files);
87
- }, children: [items.length === 0 && !loading ? (_jsx("p", { className: "d-empty", children: "Nothing in the library yet. Drop an image here, or press Upload." })) : (_jsx("div", { className: "pick-grid", children: items.map((item) => (_jsxs("button", { type: "button", className: `pick${selected?.id === item.id ? " is-picked" : ""}`, onClick: () => setSelected(item), onDoubleClick: () => onSelect(item), children: [item.thumbUrl || item.url ? (_jsx("img", { src: item.thumbUrl || item.url, alt: "", loading: "lazy" })) : (_jsx("span", { className: "pick-blank" })), _jsxs("span", { className: "pick-meta", children: [_jsx("span", { className: `pick-alt${item.alt ? "" : " is-missing"}`, children: item.alt || "Image" }), _jsxs("span", { className: "pick-sub", children: [item.width && item.height ? `${item.width}×${item.height}` : "—", " \u00B7", " ", kb(item.filesize)] })] })] }, item.id))) })), hasMore ? (_jsx("div", { className: "modal-more", children: _jsx("button", { type: "button", className: "btn", disabled: loading, onClick: () => {
87
+ }, children: [items.length === 0 && !loading ? (_jsx("p", { className: "blog_d-empty", children: "Nothing in the library yet. Drop an image here, or press Upload." })) : (_jsx("div", { className: "blog_pick-grid", children: items.map((item) => (_jsxs("button", { type: "button", className: `blog_pick${selected?.id === item.id ? " blog_is-picked" : ""}`, onClick: () => setSelected(item), onDoubleClick: () => onSelect(item), children: [item.thumbUrl || item.url ? (_jsx("img", { src: item.thumbUrl || item.url, alt: "", loading: "lazy" })) : (_jsx("span", { className: "blog_pick-blank" })), _jsxs("span", { className: "blog_pick-meta", children: [_jsx("span", { className: `blog_pick-alt${item.alt ? "" : " blog_is-missing"}`, children: item.alt || "Image" }), _jsxs("span", { className: "blog_pick-sub", children: [item.width && item.height ? `${item.width}×${item.height}` : "—", " \u00B7", " ", kb(item.filesize)] })] })] }, item.id))) })), hasMore ? (_jsx("div", { className: "blog_modal-more", children: _jsx("button", { type: "button", className: "blog_btn", disabled: loading, onClick: () => {
88
88
  const next = page + 1;
89
89
  setPage(next);
90
90
  load(next, query, true);
91
- }, children: loading ? "Loading…" : "Load more" }) })) : null] }), _jsxs("footer", { className: "modal-foot", children: [_jsxs("span", { className: "note", children: [total, " image", total === 1 ? "" : "s", " \u00B7 drag files anywhere in this window to upload"] }), _jsxs("div", { className: "modal-foot-actions", children: [_jsx("button", { type: "button", className: "btn", onClick: onClose, children: "Cancel" }), _jsx("button", { type: "button", className: "btn btn-primary", disabled: !selected, onClick: () => selected && onSelect(selected), children: "Use this image" })] })] })] }) }));
91
+ }, children: loading ? "Loading…" : "Load more" }) })) : null] }), _jsxs("footer", { className: "blog_modal-foot", children: [_jsxs("span", { className: "blog_note", children: [total, " image", total === 1 ? "" : "s", " \u00B7 drag files anywhere in this window to upload"] }), _jsxs("div", { className: "blog_modal-foot-actions", children: [_jsx("button", { type: "button", className: "blog_btn", onClick: onClose, children: "Cancel" }), _jsx("button", { type: "button", className: "blog_btn blog_btn-primary", disabled: !selected, onClick: () => selected && onSelect(selected), children: "Use this image" })] })] })] }) }));
92
92
  }
@@ -88,15 +88,15 @@ export function PostList({ filterState = "all", onEdit, onView, onMetaChange, })
88
88
  setCategoryId("");
89
89
  setPage(1);
90
90
  };
91
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "tabs", role: "navigation", "aria-label": "Filter posts by state", children: TABS.map((t) => (_jsxs("button", { type: "button", "aria-current": t.key === tab ? "true" : undefined, onClick: () => {
91
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "blog_tabs", role: "navigation", "aria-label": "Filter posts by state", children: TABS.map((t) => (_jsxs("button", { type: "button", "aria-current": t.key === tab ? "true" : undefined, onClick: () => {
92
92
  setTab(t.key);
93
93
  setPage(1);
94
94
  if (t.key === "live") {
95
95
  setSort("published");
96
96
  setSortDraft("published");
97
97
  }
98
- }, children: [t.label, _jsx("span", { className: "tab-count", children: counts[t.key] ?? 0 })] }, t.key))) }), _jsxs("form", { className: "filterbar", onSubmit: (e) => {
98
+ }, children: [t.label, _jsx("span", { className: "blog_tab-count", children: counts[t.key] ?? 0 })] }, t.key))) }), _jsxs("form", { className: "blog_filterbar", onSubmit: (e) => {
99
99
  e.preventDefault();
100
100
  applyFilters();
101
- }, children: [_jsx("input", { className: "fld", type: "search", name: "q", placeholder: "Search titles\u2026", value: searchDraft, onChange: (e) => setSearchDraft(e.target.value), "aria-label": "Search post titles" }), _jsxs("select", { className: "fld", name: "cat", "aria-label": "Filter by category", value: categoryDraft, onChange: (e) => setCategoryDraft(e.target.value), children: [_jsx("option", { value: "", children: "All categories" }), categories.map((c) => (_jsx("option", { value: c.id, children: c.name }, c.id)))] }), _jsx("select", { className: "fld", name: "sort", "aria-label": "Sort", value: sortDraft, onChange: (e) => setSortDraft(e.target.value), children: SORTS.map((s) => (_jsx("option", { value: s.key, children: s.label }, s.key))) }), _jsx("button", { className: "btn", type: "submit", children: "Filter" }), search || categoryId ? (_jsx("button", { type: "button", className: "btn btn-ghost", onClick: clearFilters, children: "Clear" })) : null] }), isTrash ? (_jsxs("p", { className: "explain", children: ["Trashed posts are ", _jsx("b", { children: "soft-deleted" }), ": they keep their versions, their slug and their redirects, and no ordinary query returns them. Restoring one puts it back exactly as it was. Deleting permanently is a brand-admin action and cannot be undone."] })) : null, _jsx("section", { className: "panel", children: _jsx(PostsTable, { rows: pageRows, minRows: MIN_TABLE_ROWS, totalCount: rows.length, page: page, pageSize: PER_PAGE, categories: categories, state: tab, showBrand: showBrand, onEdit: onEdit, onView: onView }) }), rows.length > 0 ? (_jsxs("nav", { className: "pager", "aria-label": "Pagination", children: [page > 1 ? (_jsx("button", { type: "button", className: "btn", onClick: () => setPage((p) => p - 1), children: "\u2190 Newer" })) : (_jsx("span", {})), _jsxs("span", { className: "note", children: ["Showing ", pageStart, "\u2013", pageEnd, " of ", rows.length, totalPages > 1 ? ` · Page ${page} of ${totalPages}` : ""] }), page < totalPages ? (_jsx("button", { type: "button", className: "btn", onClick: () => setPage((p) => p + 1), children: "Older \u2192" })) : (_jsx("span", {}))] })) : null] }));
101
+ }, children: [_jsx("input", { className: "blog_fld", type: "search", name: "q", placeholder: "Search titles\u2026", value: searchDraft, onChange: (e) => setSearchDraft(e.target.value), "aria-label": "Search post titles" }), _jsxs("select", { className: "blog_fld", name: "cat", "aria-label": "Filter by category", value: categoryDraft, onChange: (e) => setCategoryDraft(e.target.value), children: [_jsx("option", { value: "", children: "All categories" }), categories.map((c) => (_jsx("option", { value: c.id, children: c.name }, c.id)))] }), _jsx("select", { className: "blog_fld", name: "sort", "aria-label": "Sort", value: sortDraft, onChange: (e) => setSortDraft(e.target.value), children: SORTS.map((s) => (_jsx("option", { value: s.key, children: s.label }, s.key))) }), _jsx("button", { className: "blog_btn", type: "submit", children: "Filter" }), search || categoryId ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-ghost", onClick: clearFilters, children: "Clear" })) : null] }), isTrash ? (_jsxs("p", { className: "blog_explain", children: ["Trashed posts are ", _jsx("b", { children: "soft-deleted" }), ": they keep their versions, their slug and their redirects, and no ordinary query returns them. Restoring one puts it back exactly as it was. Deleting permanently is a brand-admin action and cannot be undone."] })) : null, _jsx("section", { className: "blog_panel", children: _jsx(PostsTable, { rows: pageRows, minRows: MIN_TABLE_ROWS, totalCount: rows.length, page: page, pageSize: PER_PAGE, categories: categories, state: tab, showBrand: showBrand, onEdit: onEdit, onView: onView }) }), rows.length > 0 ? (_jsxs("nav", { className: "blog_pager", "aria-label": "Pagination", children: [page > 1 ? (_jsx("button", { type: "button", className: "blog_btn", onClick: () => setPage((p) => p - 1), children: "\u2190 Newer" })) : (_jsx("span", {})), _jsxs("span", { className: "blog_note", children: ["Showing ", pageStart, "\u2013", pageEnd, " of ", rows.length, totalPages > 1 ? ` · Page ${page} of ${totalPages}` : ""] }), page < totalPages ? (_jsx("button", { type: "button", className: "blog_btn", onClick: () => setPage((p) => p + 1), children: "Older \u2192" })) : (_jsx("span", {}))] })) : null] }));
102
102
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PostsTable.d.ts","sourceRoot":"","sources":["../../../app/components/admin/PostsTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAuBF,eAAO,MAAM,UAAU,GAAI,8FAWxB,KAAK,gCA0bP,CAAC"}
1
+ {"version":3,"file":"PostsTable.d.ts","sourceRoot":"","sources":["../../../app/components/admin/PostsTable.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,KAAK,KAAK,GAAG;IACX,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAAC;AAwBF,eAAO,MAAM,UAAU,GAAI,8FAWxB,KAAK,gCA0bP,CAAC"}
@@ -14,15 +14,15 @@ const toLocalInput = (iso) => {
14
14
  };
15
15
  const StateChip = ({ row }) => {
16
16
  if (row.trashed)
17
- return _jsx("span", { className: "chip chip-blocked", children: "Trashed" });
17
+ return _jsx("span", { className: "blog_chip blog_chip-blocked", children: "Trashed" });
18
18
  if (row.status === "published")
19
- return _jsx("span", { className: "chip chip-live", children: "Live" });
19
+ return _jsx("span", { className: "blog_chip blog_chip-live", children: "Live" });
20
20
  if (row.scheduledFor && row.status === "draft") {
21
- return _jsx("span", { className: "chip chip-approved", children: "Scheduled" });
21
+ return _jsx("span", { className: "blog_chip blog_chip-approved", children: "Scheduled" });
22
22
  }
23
23
  const rs = row.reviewState;
24
- const cls = rs === "in-review" ? "chip-review" : rs === "approved" ? "chip-approved" : "chip-writing";
25
- return _jsx("span", { className: `chip ${cls}`, children: REVIEW_LABELS[rs] ?? "Draft" });
24
+ const cls = rs === "in-review" ? "blog_chip-review" : rs === "approved" ? "blog_chip-approved" : "blog_chip-writing";
25
+ return _jsx("span", { className: `blog_chip ${cls}`, children: REVIEW_LABELS[rs] ?? "Draft" });
26
26
  };
27
27
  export const PostsTable = ({ rows, minRows = 0, totalCount, page, pageSize, categories, state, showBrand, onEdit, onView, }) => {
28
28
  const store = useAdminMock();
@@ -86,11 +86,11 @@ export const PostsTable = ({ rows, minRows = 0, totalCount, page, pageSize, cate
86
86
  }
87
87
  run(() => store.bulkPostAction(selected, bulk), `${selected.length} post(s) updated.`);
88
88
  };
89
- return (_jsxs("div", { className: "list", children: [_jsxs("div", { className: "list-bar", children: [_jsxs("div", { className: "bulk", children: [_jsxs("select", { className: "fld fld-sm", value: bulk, onChange: (e) => setBulk(e.target.value), "aria-label": "Bulk action", children: [_jsx("option", { value: "", children: "Bulk actions\u2026" }), isTrash ? (_jsxs(_Fragment, { children: [_jsx("option", { value: "restore", children: "Restore" }), _jsx("option", { value: "delete", children: "Delete permanently" })] })) : (_jsxs(_Fragment, { children: [_jsx("option", { value: "submit", children: "Submit for review" }), _jsx("option", { value: "approve", children: "Approve" }), _jsx("option", { value: "send-back", children: "Send back to writing" }), _jsx("option", { value: "publish", children: "Publish" }), _jsx("option", { value: "draft", children: "Switch to draft" }), _jsx("option", { value: "trash", children: "Move to trash" })] }))] }), _jsx("button", { type: "button", className: "btn", disabled: !bulk || !selected.length || pending, onClick: applyBulk, children: "Apply" }), _jsx("span", { className: "note", children: selected.length
89
+ return (_jsxs("div", { className: "blog_list", children: [_jsxs("div", { className: "blog_list-bar", children: [_jsxs("div", { className: "blog_bulk", children: [_jsxs("select", { className: "blog_fld blog_fld-sm", value: bulk, onChange: (e) => setBulk(e.target.value), "aria-label": "Bulk action", children: [_jsx("option", { value: "", children: "Bulk actions\u2026" }), isTrash ? (_jsxs(_Fragment, { children: [_jsx("option", { value: "restore", children: "Restore" }), _jsx("option", { value: "delete", children: "Delete permanently" })] })) : (_jsxs(_Fragment, { children: [_jsx("option", { value: "submit", children: "Submit for review" }), _jsx("option", { value: "approve", children: "Approve" }), _jsx("option", { value: "send-back", children: "Send back to writing" }), _jsx("option", { value: "publish", children: "Publish" }), _jsx("option", { value: "draft", children: "Switch to draft" }), _jsx("option", { value: "trash", children: "Move to trash" })] }))] }), _jsx("button", { type: "button", className: "blog_btn", disabled: !bulk || !selected.length || pending, onClick: applyBulk, children: "Apply" }), _jsx("span", { className: "blog_note", children: selected.length
90
90
  ? `${selected.length} selected`
91
91
  : totalCount != null && page != null && pageSize != null
92
92
  ? `${rows.length} on this page · ${totalCount} total`
93
- : `${rows.length} shown` })] }), pending ? _jsx("span", { className: "note", children: "Working\u2026" }) : null] }), error ? (_jsx("p", { className: "form-error", role: "alert", children: error })) : null, flash ? (_jsx("p", { className: "form-ok", role: "status", children: flash })) : null, _jsx("div", { className: "tw", children: _jsxs("table", { className: "tbl tbl-list", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: "col-check", children: _jsx("input", { type: "checkbox", checked: allChecked, "aria-label": "Select all posts", onChange: (e) => setSelected(e.target.checked ? rows.map((r) => r.id) : []) }) }), _jsx("th", { children: "Title" }), showBrand ? _jsx("th", { className: "col-narrow", children: "Brand" }) : null, _jsx("th", { className: "col-narrow", children: "Byline" }), _jsx("th", { className: "col-narrow", children: "Category" }), _jsx("th", { className: "col-narrow", children: "Date" }), _jsx("th", { className: "col-narrow num", children: "Views 30d" }), _jsx("th", { className: "col-narrow", children: "Status" })] }) }), _jsxs("tbody", { children: [rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: showBrand ? 8 : 7, children: _jsx("p", { className: "d-empty", children: "No posts match this view." }) }) })) : null, rows.map((row) => (_jsxs(Fragment, { children: [_jsxs("tr", { className: selected.includes(row.id) ? "is-selected" : undefined, children: [_jsx("td", { className: "col-check", children: _jsx("input", { type: "checkbox", checked: selected.includes(row.id), "aria-label": `Select ${row.title}`, onChange: (e) => setSelected((list) => e.target.checked ? [...list, row.id] : list.filter((id) => id !== row.id)) }) }), _jsxs("td", { className: "col-title", children: [_jsx("button", { type: "button", className: "row-title", onClick: () => onEdit(row.id), children: row.title || "(no title)" }), row.blockers.length && row.status !== "published" && !row.trashed ? (_jsx("ul", { className: "blockers", children: row.blockers.map((b) => (_jsxs("li", { children: ["needs ", b] }, b))) })) : null, _jsx("div", { className: "row-actions", children: isTrash ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => run(() => store.bulkPostAction([row.id], "restore"), "Restored."), children: "Restore" }), _jsx("button", { type: "button", className: "danger", onClick: () => {
93
+ : `${rows.length} shown` })] }), pending ? _jsx("span", { className: "blog_note", children: "Working\u2026" }) : null] }), error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, flash ? (_jsx("p", { className: "blog_form-ok", role: "status", children: flash })) : null, _jsx("div", { className: "blog_tw", children: _jsxs("table", { className: "blog_tbl blog_tbl-list", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { className: "blog_col-check", children: _jsx("input", { type: "checkbox", checked: allChecked, "aria-label": "Select all posts", onChange: (e) => setSelected(e.target.checked ? rows.map((r) => r.id) : []) }) }), _jsx("th", { children: "Title" }), showBrand ? _jsx("th", { className: "blog_col-narrow", children: "Brand" }) : null, _jsx("th", { className: "blog_col-narrow", children: "Byline" }), _jsx("th", { className: "blog_col-narrow", children: "Category" }), _jsx("th", { className: "blog_col-narrow", children: "Date" }), _jsx("th", { className: "blog_col-narrow blog_num", children: "Views 30d" }), _jsx("th", { className: "blog_col-narrow", children: "Status" })] }) }), _jsxs("tbody", { children: [rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: showBrand ? 8 : 7, children: _jsx("p", { className: "blog_d-empty", children: "No posts match this view." }) }) })) : null, rows.map((row) => (_jsxs(Fragment, { children: [_jsxs("tr", { className: selected.includes(row.id) ? "blog_is-selected" : undefined, children: [_jsx("td", { className: "blog_col-check", children: _jsx("input", { type: "checkbox", checked: selected.includes(row.id), "aria-label": `Select ${row.title}`, onChange: (e) => setSelected((list) => e.target.checked ? [...list, row.id] : list.filter((id) => id !== row.id)) }) }), _jsxs("td", { className: "blog_col-title", children: [_jsx("button", { type: "button", className: "blog_row-title", onClick: () => onEdit(row.id), children: row.title || "(no title)" }), row.blockers.length && row.status !== "published" && !row.trashed ? (_jsx("ul", { className: "blog_blockers", children: row.blockers.map((b) => (_jsxs("li", { children: ["needs ", b] }, b))) })) : null, _jsx("div", { className: "blog_row-actions", children: isTrash ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", onClick: () => run(() => store.bulkPostAction([row.id], "restore"), "Restored."), children: "Restore" }), _jsx("button", { type: "button", className: "blog_danger", onClick: () => {
94
94
  if (window.confirm("Delete this post permanently? This cannot be undone.")) {
95
95
  run(() => store.bulkPostAction([row.id], "delete"), "Deleted.");
96
96
  }
@@ -98,7 +98,7 @@ export const PostsTable = ({ rows, minRows = 0, totalCount, page, pageSize, cate
98
98
  setScheduling(row.id);
99
99
  setWhen(toLocalInput(row.scheduledFor) ||
100
100
  toLocalInput(new Date(Date.now() + 3600000).toISOString()));
101
- }, children: "Schedule" })] })) : null, row.status === "published" && row.canPublish ? (_jsx("button", { type: "button", onClick: () => run(() => store.unpublish(row.id), "Switched to draft."), children: "Unpublish" })) : null, _jsx("button", { type: "button", onClick: () => run(() => store.duplicatePost(row.id), "Copied as a new draft."), children: "Duplicate" }), _jsx("button", { type: "button", className: "danger", onClick: () => run(() => store.bulkPostAction([row.id], "trash"), "Moved to trash."), children: "Trash" }), row.status === "published" && onView ? (_jsx("button", { type: "button", onClick: () => onView(row.id), children: "View" })) : null] })) }), scheduling === row.id ? (_jsxs("div", { className: "inline-form", children: [_jsx("input", { type: "datetime-local", className: "fld fld-sm", value: when, onChange: (e) => setWhen(e.target.value), "aria-label": "Publish date and time" }), _jsx("button", { type: "button", className: "btn btn-primary btn-tiny", onClick: () => run(() => store.schedulePost(row.id, new Date(when).toISOString()), "Scheduled."), children: "Confirm" }), _jsx("button", { type: "button", className: "btn btn-tiny", onClick: () => setScheduling(null), children: "Cancel" })] })) : null] }), showBrand ? _jsx("td", { className: "col-narrow muted", children: row.brandName ?? "—" }) : null, _jsx("td", { className: "col-narrow muted", children: row.authorNames.join(", ") || "—" }), _jsx("td", { className: "col-narrow muted", children: row.categoryNames.join(", ") || "—" }), _jsx("td", { className: "col-narrow muted", children: row.status === "published" ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "cell-lbl", children: "Published" }), fmtDate(row.publishedAt)] })) : row.scheduledFor ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "cell-lbl", children: "Scheduled" }), fmtDateTime(row.scheduledFor)] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "cell-lbl", children: "Edited" }), fmtDate(row.updatedAt)] })) }), _jsx("td", { className: "col-narrow num", children: row.views == null ? "—" : row.views }), _jsx("td", { className: "col-narrow", children: _jsx(StateChip, { row: row }) })] }), editing === row.id && editRow ? (_jsx("tr", { className: "quick-row", children: _jsx("td", { colSpan: showBrand ? 8 : 7, children: _jsxs("div", { className: "quick", children: [_jsx("p", { className: "quick-head", children: "Quick edit \u2014 metadata only, the body stays untouched" }), _jsxs("div", { className: "quick-grid", children: [_jsxs("label", { children: [_jsx("span", { children: "Title" }), _jsx("input", { className: "fld", value: draft.title, onChange: (e) => setDraft((d) => ({ ...d, title: e.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "Slug" }), _jsx("input", { className: "fld mono", value: draft.slug, onChange: (e) => setDraft((d) => ({ ...d, slug: e.target.value })) })] }), _jsxs("div", { className: "span-2", children: [_jsx("span", { className: "fld-lbl", style: { display: "block", marginBottom: 6 }, children: "Categories" }), _jsx("div", { className: "pick-list pick-list-compact", children: categories.length === 0 ? (_jsx("p", { className: "note", children: "No categories." })) : (categories.map((c) => (_jsxs("label", { className: "pick-row", children: [_jsx("input", { type: "checkbox", checked: draft.category.includes(c.id), onChange: () => toggleDraftCategory(c.id) }), c.name] }, c.id)))) })] }), _jsxs("label", { children: [_jsx("span", { children: "Published date" }), _jsx("input", { type: "datetime-local", className: "fld", value: draft.date, onChange: (e) => setDraft((d) => ({ ...d, date: e.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "Status" }), _jsxs("select", { className: "fld", value: draft.status, disabled: !row.canPublish, onChange: (e) => setDraft((d) => ({ ...d, status: e.target.value })), children: [_jsx("option", { value: "draft", children: "Draft" }), _jsx("option", { value: "published", children: "Published" })] })] })] }), _jsxs("div", { className: "btn-row", children: [_jsx("button", { type: "button", className: "btn btn-primary", disabled: pending, onClick: () => run(() => store.quickEditPost({
101
+ }, children: "Schedule" })] })) : null, row.status === "published" && row.canPublish ? (_jsx("button", { type: "button", onClick: () => run(() => store.unpublish(row.id), "Switched to draft."), children: "Unpublish" })) : null, _jsx("button", { type: "button", onClick: () => run(() => store.duplicatePost(row.id), "Copied as a new draft."), children: "Duplicate" }), _jsx("button", { type: "button", className: "blog_danger", onClick: () => run(() => store.bulkPostAction([row.id], "trash"), "Moved to trash."), children: "Trash" }), row.status === "published" && onView ? (_jsx("button", { type: "button", onClick: () => onView(row.id), children: "View" })) : null] })) }), scheduling === row.id ? (_jsxs("div", { className: "blog_inline-form", children: [_jsx("input", { type: "datetime-local", className: "blog_fld blog_fld-sm", value: when, onChange: (e) => setWhen(e.target.value), "aria-label": "Publish date and time" }), _jsx("button", { type: "button", className: "blog_btn blog_btn-primary blog_btn-tiny", onClick: () => run(() => store.schedulePost(row.id, new Date(when).toISOString()), "Scheduled."), children: "Confirm" }), _jsx("button", { type: "button", className: "blog_btn blog_btn-tiny", onClick: () => setScheduling(null), children: "Cancel" })] })) : null] }), showBrand ? _jsx("td", { className: "blog_col-narrow blog_muted", children: row.brandName ?? "—" }) : null, _jsx("td", { className: "blog_col-narrow blog_muted", children: row.authorNames.join(", ") || "—" }), _jsx("td", { className: "blog_col-narrow blog_muted", children: row.categoryNames.join(", ") || "—" }), _jsx("td", { className: "blog_col-narrow blog_muted", children: row.status === "published" ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "blog_cell-lbl", children: "Published" }), fmtDate(row.publishedAt)] })) : row.scheduledFor ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "blog_cell-lbl", children: "Scheduled" }), fmtDateTime(row.scheduledFor)] })) : (_jsxs(_Fragment, { children: [_jsx("span", { className: "blog_cell-lbl", children: "Edited" }), fmtDate(row.updatedAt)] })) }), _jsx("td", { className: "blog_col-narrow blog_num", children: row.views == null ? "—" : row.views }), _jsx("td", { className: "blog_col-narrow", children: _jsx(StateChip, { row: row }) })] }), editing === row.id && editRow ? (_jsx("tr", { className: "blog_quick-row", children: _jsx("td", { colSpan: showBrand ? 8 : 7, children: _jsxs("div", { className: "blog_quick", children: [_jsx("p", { className: "blog_quick-head", children: "Quick edit \u2014 metadata only, the body stays untouched" }), _jsxs("div", { className: "blog_quick-grid", children: [_jsxs("label", { children: [_jsx("span", { children: "Title" }), _jsx("input", { className: "blog_fld", value: draft.title, onChange: (e) => setDraft((d) => ({ ...d, title: e.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "Slug" }), _jsx("input", { className: "blog_fld blog_mono", value: draft.slug, onChange: (e) => setDraft((d) => ({ ...d, slug: e.target.value })) })] }), _jsxs("div", { className: "blog_span-2", children: [_jsx("span", { className: "blog_fld-lbl", style: { display: "block", marginBottom: 6 }, children: "Categories" }), _jsx("div", { className: "blog_pick-list blog_pick-list-compact", children: categories.length === 0 ? (_jsx("p", { className: "blog_note", children: "No categories." })) : (categories.map((c) => (_jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: draft.category.includes(c.id), onChange: () => toggleDraftCategory(c.id) }), c.name] }, c.id)))) })] }), _jsxs("label", { children: [_jsx("span", { children: "Published date" }), _jsx("input", { type: "datetime-local", className: "blog_fld", value: draft.date, onChange: (e) => setDraft((d) => ({ ...d, date: e.target.value })) })] }), _jsxs("label", { children: [_jsx("span", { children: "Status" }), _jsxs("select", { className: "blog_fld", value: draft.status, disabled: !row.canPublish, onChange: (e) => setDraft((d) => ({ ...d, status: e.target.value })), children: [_jsx("option", { value: "draft", children: "Draft" }), _jsx("option", { value: "published", children: "Published" })] })] })] }), _jsxs("div", { className: "blog_btn-row", children: [_jsx("button", { type: "button", className: "blog_btn blog_btn-primary", disabled: pending, onClick: () => run(() => store.quickEditPost({
102
102
  id: row.id,
103
103
  title: draft.title,
104
104
  slug: draft.slug,
@@ -106,7 +106,7 @@ export const PostsTable = ({ rows, minRows = 0, totalCount, page, pageSize, cate
106
106
  publishedAt: draft.date ? new Date(draft.date).toISOString() : null,
107
107
  scheduledFor: row.scheduledFor,
108
108
  status: draft.status,
109
- }), "Saved."), children: "Save" }), _jsx("button", { type: "button", className: "btn", onClick: () => setEditing(null), children: "Cancel" }), _jsx("span", { className: "note", children: "Changing the slug of a live post writes a 301 from the old URL automatically." })] })] }) }) })) : null] }, row.id))), minRows > 0 && rows.length > 0 && rows.length < minRows
110
- ? Array.from({ length: minRows - rows.length }).map((_, i) => (_jsx("tr", { className: "tbl-row-pad", "aria-hidden": "true", children: _jsx("td", { colSpan: showBrand ? 8 : 7 }) }, `pad-${i}`)))
109
+ }), "Saved."), children: "Save" }), _jsx("button", { type: "button", className: "blog_btn", onClick: () => setEditing(null), children: "Cancel" }), _jsx("span", { className: "blog_note", children: "Changing the slug of a live post writes a 301 from the old URL automatically." })] })] }) }) })) : null] }, row.id))), minRows > 0 && rows.length > 0 && rows.length < minRows
110
+ ? Array.from({ length: minRows - rows.length }).map((_, i) => (_jsx("tr", { className: "blog_tbl-row-pad", "aria-hidden": "true", children: _jsx("td", { colSpan: showBrand ? 8 : 7 }) }, `pad-${i}`)))
111
111
  : null] })] }) })] }));
112
112
  };
@@ -92,8 +92,8 @@ const NAV = [
92
92
  },
93
93
  ];
94
94
  export const Shell = ({ children, active, onNavigate, title, subtitle, actions, wide, branding, className, userName = "Platform Admin", userRole = "Platform admin", onProfile, }) => {
95
- return (_jsxs("div", { className: cx("shell", className), children: [_jsxs("aside", { className: "side", children: [_jsxs("div", { className: "side-brand", children: [_jsx("div", { className: "side-mark", "aria-hidden": "true", style: branding?.logo ? { background: 'transparent', padding: 0 } : undefined, children: branding?.logo ? _jsx("img", { src: branding.logo, alt: branding.name ?? "Brand", style: { height: 24 } }) : (branding?.name || "B")[0] }), _jsxs("div", { children: [_jsx("div", { className: "side-name", children: branding?.name || "Blog Portal" }), _jsx("div", { className: "side-role", children: branding?.subtitle || "2 brands" })] })] }), _jsxs("button", { type: "button", className: "side-new", onClick: () => onNavigate("posts-new"), children: [_jsx("span", { "aria-hidden": "true", children: "\uFF0B" }), "New post"] }), _jsxs("div", { className: "side-scroll", children: [NAV.map((section, idx) => (_jsxs("div", { className: "side-group", children: [_jsx("p", { className: "side-sect", children: section.title }), _jsx("nav", { className: "side-nav", children: section.items.map((item) => {
95
+ return (_jsxs("div", { className: cx("blog_shell", className), children: [_jsxs("aside", { className: "blog_side", children: [_jsxs("div", { className: "blog_side-brand", children: [_jsx("div", { className: "blog_side-mark", "aria-hidden": "true", style: branding?.logo ? { background: 'transparent', padding: 0 } : undefined, children: branding?.logo ? _jsx("img", { src: branding.logo, alt: branding.name ?? "Brand", style: { height: 24 } }) : (branding?.name || "B")[0] }), _jsxs("div", { children: [_jsx("div", { className: "blog_side-name", children: branding?.name || "Blog Portal" }), _jsx("div", { className: "blog_side-role", children: branding?.subtitle || "2 brands" })] })] }), _jsxs("button", { type: "button", className: "blog_side-new", onClick: () => onNavigate("posts-new"), children: [_jsx("span", { "aria-hidden": "true", children: "\uFF0B" }), "New post"] }), _jsxs("div", { className: "blog_side-scroll", children: [NAV.map((section, idx) => (_jsxs("div", { className: "blog_side-group", children: [_jsx("p", { className: "blog_side-sect", children: section.title }), _jsx("nav", { className: "blog_side-nav", children: section.items.map((item) => {
96
96
  const isActive = active === item.key || item.children?.some(c => c.key === active);
97
- return (_jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => onNavigate(item.key), "aria-current": isActive ? "page" : undefined, children: [item.icon && _jsx(Icon, { path: ICONS[item.icon] }), item.label] }), item.children && isActive && (_jsx("div", { className: "side-sub", children: item.children.map((child) => (_jsx("button", { type: "button", onClick: () => onNavigate(child.key), "aria-current": active === child.key ? "page" : undefined, style: { cursor: "pointer", width: "100%", textAlign: "left", background: "none", border: "none", padding: "4px 8px", color: active === child.key ? "var(--d-surface)" : "var(--d-side-ink-2)" }, children: child.label }, child.key))) }))] }, item.key));
98
- }) })] }, idx))), _jsx("div", { className: "side-group", children: _jsx("nav", { className: "side-nav", children: _jsx("button", { type: "button", children: "Log out" }) }) })] }), _jsx("div", { className: "side-foot", children: _jsxs("button", { type: "button", className: "side-user-card", style: { width: "100%", background: "none", border: "none", textAlign: "left", cursor: "pointer" }, onClick: () => (onProfile ? onProfile() : onNavigate("profile")), children: [_jsx("div", { className: "side-user-avatar-fallback side-user-avatar", children: (userName || "P").slice(0, 1).toUpperCase() }), _jsxs("div", { className: "side-user-meta", children: [_jsx("div", { className: "side-user-name", style: { color: "#fff" }, children: userName }), _jsx("div", { className: "side-user-role", children: userRole })] })] }) })] }), _jsxs("main", { className: "main", children: [_jsxs("header", { className: "top", children: [_jsxs("div", { className: "top-title", children: [_jsx("h1", { children: title }), subtitle ? _jsx("p", { className: "sub", children: subtitle }) : null] }), _jsx("div", { className: "top-actions", children: actions })] }), _jsx("div", { className: wide ? 'body body-wide' : 'body', children: children })] })] }));
97
+ return (_jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => onNavigate(item.key), "aria-current": isActive ? "page" : undefined, children: [item.icon && _jsx(Icon, { path: ICONS[item.icon] }), item.label] }), item.children && isActive && (_jsx("div", { className: "blog_side-sub", children: item.children.map((child) => (_jsx("button", { type: "button", onClick: () => onNavigate(child.key), "aria-current": active === child.key ? "page" : undefined, style: { cursor: "pointer", width: "100%", textAlign: "left", background: "none", border: "none", padding: "4px 8px", color: active === child.key ? "var(--d-surface)" : "var(--d-side-ink-2)" }, children: child.label }, child.key))) }))] }, item.key));
98
+ }) })] }, idx))), _jsx("div", { className: "blog_side-group", children: _jsx("nav", { className: "blog_side-nav", children: _jsx("button", { type: "button", children: "Log out" }) }) })] }), _jsx("div", { className: "blog_side-foot", children: _jsxs("button", { type: "button", className: "blog_side-user-card", style: { width: "100%", background: "none", border: "none", textAlign: "left", cursor: "pointer" }, onClick: () => (onProfile ? onProfile() : onNavigate("profile")), children: [_jsx("div", { className: "blog_side-user-avatar-fallback blog_side-user-avatar", children: (userName || "P").slice(0, 1).toUpperCase() }), _jsxs("div", { className: "blog_side-user-meta", children: [_jsx("div", { className: "blog_side-user-name", style: { color: "#fff" }, children: userName }), _jsx("div", { className: "blog_side-user-role", children: userRole })] })] }) })] }), _jsxs("main", { className: "blog_main", children: [_jsxs("header", { className: "blog_top", children: [_jsxs("div", { className: "blog_top-title", children: [_jsx("h1", { children: title }), subtitle ? _jsx("p", { className: "blog_sub", children: subtitle }) : null] }), _jsx("div", { className: "blog_top-actions", children: actions })] }), _jsx("div", { className: wide ? 'blog_body blog_body-wide' : 'blog_body', children: children })] })] }));
99
99
  };