@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.
- package/dist/components/admin/AdminPostDetail.js +5 -5
- package/dist/components/admin/BrandSettings.js +5 -5
- package/dist/components/admin/BrandSwitcher.js +1 -1
- package/dist/components/admin/Chips.js +5 -5
- package/dist/components/admin/CommentsManager.js +6 -6
- package/dist/components/admin/Dashboard.js +1 -1
- package/dist/components/admin/MediaLibrary.js +5 -5
- package/dist/components/admin/MediaPicker.js +4 -4
- package/dist/components/admin/PostList.js +3 -3
- package/dist/components/admin/PostsTable.d.ts.map +1 -1
- package/dist/components/admin/PostsTable.js +10 -10
- package/dist/components/admin/Shell.js +3 -3
- package/dist/components/admin/TermManager.js +4 -4
- package/dist/components/admin/UsersManager.js +3 -3
- package/dist/components/admin/charts.js +7 -7
- package/dist/components/admin/editor/PostEditor.js +16 -16
- package/dist/components/admin/editor/RichTextEditor.js +8 -8
- package/dist/components/admin/editor/YoastCollapsible.js +2 -2
- package/dist/components/admin/editor/YoastInsightsPanel.js +1 -1
- package/dist/components/admin/editor/YoastInternalLinksPanel.js +1 -1
- package/dist/components/admin/editor/YoastSeoAnalysisPanel.js +6 -6
- package/dist/components/admin/editor/YoastSeoMetabox.js +8 -8
- package/dist/components/admin/editor/YoastSnippetField.js +2 -2
- package/dist/components/admin/internal/States.js +3 -3
- package/dist/components/admin/seo/Ga4Settings.js +6 -6
- package/dist/components/admin/seo/RedirectAnalyticsDashboard.js +1 -1
- package/dist/components/admin/seo/RedirectDetail.js +6 -6
- package/dist/components/admin/seo/RedirectForm.js +1 -1
- package/dist/components/admin/seo/RedirectList.js +4 -4
- package/dist/components/admin/seo/RobotsEditor.js +1 -1
- package/dist/components/admin/seo/shared.js +2 -2
- package/dist/components/admin/tools/ToolsHub.js +4 -4
- package/dist/components/user/BlogCard.js +3 -3
- package/dist/components/user/BlogCategories.js +1 -1
- package/dist/components/user/BlogDetail.js +1 -1
- package/dist/components/user/BlogList.js +1 -1
- package/dist/components/user/BlogSearch.js +2 -2
- package/dist/components/user/BlogTags.js +1 -1
- package/dist/components/user/FeaturedBlogs.js +1 -1
- package/dist/components/user/RelatedBlogs.js +1 -1
- package/dist/components/user/SiteMediaHero.js +1 -1
- package/dist/components/user/detail/ArticleDetailHero.js +5 -5
- package/dist/components/user/detail/ArticleRailDetails.js +2 -2
- package/dist/components/user/detail/CommentSection.js +2 -2
- package/dist/components/user/detail/HeroFadeSlide.js +1 -1
- package/dist/components/user/detail/ReadingProgress.js +1 -1
- package/dist/components/user/detail/ShareRow.js +1 -1
- package/dist/components/user/internal/States.js +4 -4
- package/dist/lib/lexical-doc.js +1 -1
- package/dist/pages/admin/BlogAdmin.js +7 -7
- package/dist/style.css +1018 -1018
- package/package.json +2 -1
|
@@ -19,11 +19,11 @@ const TABS = [
|
|
|
19
19
|
{ id: 'schema', label: 'Schema' },
|
|
20
20
|
{ id: 'social', label: 'Social' },
|
|
21
21
|
];
|
|
22
|
-
const Dot = ({ tone }) => (_jsx("span", { className: `
|
|
22
|
+
const Dot = ({ tone }) => (_jsx("span", { className: `blog_yoast-dot blog_yoast-dot-${tone}`, "aria-hidden": "true" }));
|
|
23
23
|
const CheckList = ({ title, items, count }) => {
|
|
24
24
|
if (!items.length)
|
|
25
25
|
return null;
|
|
26
|
-
return (_jsxs("div", { className: "
|
|
26
|
+
return (_jsxs("div", { className: "blog_seo-group", children: [title ? (_jsxs("p", { className: "blog_seo-group-title", children: [title, count ? _jsxs("span", { className: "blog_yoast-count", children: [" (", items.length, ")"] }) : null] })) : null, _jsx("ul", { className: "blog_seo-checks", children: items.map((c) => (_jsxs("li", { children: [_jsx(Dot, { tone: c.tone }), _jsxs("div", { children: [_jsx("strong", { children: c.label }), _jsx("span", { children: c.detail })] })] }, c.id))) })] }));
|
|
27
27
|
};
|
|
28
28
|
const highlightPhrase = (text, phrase) => {
|
|
29
29
|
if (!phrase.trim() || !text)
|
|
@@ -76,26 +76,26 @@ export const YoastSeoMetabox = ({ title, slug, excerpt, visibility, featuredImag
|
|
|
76
76
|
const previewHost = `${(siteName || 'example').toLowerCase().replace(/[^a-z0-9]+/g, '')}.com`;
|
|
77
77
|
const hasKeyphrase = Boolean(seo.focusKeyphrase.trim());
|
|
78
78
|
const seoTitleQuickVars = SEO_TITLE_QUICK;
|
|
79
|
-
return (_jsxs("div", { className: "
|
|
79
|
+
return (_jsxs("div", { className: "blog_box blog_yoast-box", id: "wpseo_meta", children: [_jsx("div", { className: "blog_box-head", children: _jsx("h3", { children: "Yoast SEO" }) }), _jsx("div", { className: "blog_yoast-tabs", role: "tablist", "aria-label": "Yoast SEO", children: TABS.map(({ id, label }) => (_jsxs("button", { type: "button", role: "tab", id: `yoast-tab-${id}`, "aria-selected": tab === id, "aria-controls": `yoast-panel-${id}`, className: `blog_yoast-tab${tab === id ? ' blog_is-active' : ''}`, onClick: () => setTab(id), children: [_jsx(Dot, { tone: tabTone[id] }), label] }, id))) }), _jsxs("div", { className: "blog_box-body blog_yoast-inside blog_wpseo-metabox-content", children: [tab === 'seo' ? (_jsxs("div", { className: "blog_yoast-panel blog_yoast-panel-seo", role: "tabpanel", id: "yoast-panel-seo", "aria-labelledby": "yoast-tab-seo", children: [_jsx("p", { className: "blog_yoast-intro", children: "Optimize your content for discovery." }), _jsxs("div", { className: "blog_yoast-accordion", children: [_jsx(YoastCollapsible, { title: "Focus keyphrase", defaultOpen: false, status: !hasKeyphrase ? _jsx("span", { className: "blog_yoast-status-bad", title: "Missing focus keyphrase", children: "!" }) : _jsx(Dot, { tone: seoTone }), children: _jsx("div", { className: "blog_yoast-accordion-panel", children: _jsxs("div", { className: "blog_yoast-field", children: [_jsx("input", { id: "yoast-focus-keyphrase", className: "blog_fld blog_yoast-input", value: seo.focusKeyphrase, "aria-label": "Focus keyphrase", onChange: (e) => onSeoChange('focusKeyphrase', e.target.value) }), _jsxs("p", { className: "blog_yoast-help", children: ["Use the main word or phrase you want your content found for across search, AI, and beyond.", ' ', _jsx("a", { className: "blog_yoast-learn-more", href: "https://yoast.com/focus-keyword/", target: "_blank", rel: "noreferrer", children: "Learn more about keyword research" })] }), _jsx("button", { type: "button", className: "blog_yoast-link-btn", disabled: true, title: "Requires Yoast SEO Premium", children: "Get related keyphrases" })] }) }) }), !hasKeyphrase ? (_jsx("p", { className: "blog_yoast-accordion-note", role: "status", children: "Please enter a focus keyphrase to see your SEO score." })) : null, _jsx(YoastCollapsible, { title: "Google preview", defaultOpen: false, children: _jsxs("div", { className: "blog_yoast-accordion-panel", children: [_jsxs("div", { className: "blog_yoast-preview-toolbar", children: [_jsx("span", { className: "blog_yoast-preview-label", children: "Preview as:" }), _jsxs("div", { className: "blog_yoast-preview-modes", role: "group", "aria-label": "Preview device", children: [_jsx("button", { type: "button", className: `blog_yoast-preview-mode${previewMode === 'mobile' ? ' blog_is-active' : ''}`, "aria-pressed": previewMode === 'mobile', onClick: () => setPreviewMode('mobile'), children: "Mobile result" }), _jsx("button", { type: "button", className: `blog_yoast-preview-mode${previewMode === 'desktop' ? ' blog_is-active' : ''}`, "aria-pressed": previewMode === 'desktop', onClick: () => setPreviewMode('desktop'), children: "Desktop result" })] })] }), _jsxs("div", { className: `blog_yoast-google-card blog_yoast-google-${previewMode}`, children: [_jsxs("div", { className: "blog_yoast-google-site", children: [_jsx("span", { className: "blog_yoast-google-favicon", "aria-hidden": "true", children: siteName.charAt(0).toUpperCase() }), _jsxs("div", { className: "blog_yoast-google-site-meta", children: [_jsx("div", { className: "blog_yoast-google-site-name", children: siteName }), _jsxs("div", { className: "blog_serp-url blog_mono", children: [previewHost, " \u203A blog \u203A ", slugDisplay] })] })] }), _jsx("div", { className: "blog_serp-title blog_yoast-google-title", children: highlightPhrase(seoTitle || title || 'Your post title', seo.focusKeyphrase) }), _jsx("div", { className: "blog_serp-desc blog_yoast-google-desc", children: highlightPhrase(metaDesc || 'Please provide a meta description by editing the snippet below.', seo.focusKeyphrase) })] }), _jsxs("div", { className: "blog_yoast-snippet-fields blog_stack", children: [_jsx(YoastSnippetField, { id: "yoast-seo-title", label: "SEO title", value: seo.metaTitle, placeholder: title || 'Falls back to the post title', maxLength: SEO_FIELD_LIMITS.metaTitle, expandedLength: seoTitle.length, meterGoodMin: 30, meterGoodMax: 60, meterMax: SEO_FIELD_LIMITS.metaTitle, variables: SEO_TITLE_VARIABLES, quickVariables: seoTitleQuickVars, generateLabel: "Generate SEO title", error: fieldErrors['seo.metaTitle'], onChange: (v) => {
|
|
80
80
|
onClearFieldError('seo.metaTitle');
|
|
81
81
|
onSeoChange('metaTitle', v);
|
|
82
|
-
}, onGenerate: () => onSeoChange('metaTitle', generateSeoTitleSnippet(titleTemplate)) }), _jsxs("div", { className: "
|
|
82
|
+
}, onGenerate: () => onSeoChange('metaTitle', generateSeoTitleSnippet(titleTemplate)) }), _jsxs("div", { className: "blog_yoast-field", children: [_jsx("label", { className: "blog_yoast-label", htmlFor: "yoast-slug", children: "Slug" }), _jsx("input", { id: "yoast-slug", className: "blog_fld blog_yoast-input blog_mono", value: slug, placeholder: slugify(title) || 'post-slug', onChange: (e) => onSlugChange(e.target.value), onBlur: onSlugBlur })] }), _jsx(YoastSnippetField, { id: "yoast-meta-description", label: "Meta description", value: seo.metaDescription, placeholder: "Falls back to the excerpt. Aim for 140\u2013160 characters.", multiline: true, maxLength: SEO_FIELD_LIMITS.metaDescription, expandedLength: metaDesc.length, meterGoodMin: 120, meterGoodMax: 156, meterMax: SEO_FIELD_LIMITS.metaDescription, variables: META_DESCRIPTION_VARIABLES, quickVariables: META_DESCRIPTION_VARIABLES.slice(0, 2), generateLabel: "Generate meta description", error: fieldErrors['seo.metaDescription'], onChange: (v) => {
|
|
83
83
|
onClearFieldError('seo.metaDescription');
|
|
84
84
|
onSeoChange('metaDescription', v);
|
|
85
|
-
}, onGenerate: () => onSeoChange('metaDescription', generateMetaDescriptionSnippet(snippetCtx)) })] })] }) }), _jsx(YoastCollapsible, { title: "SEO analysis", defaultOpen: false, status: _jsx(Dot, { tone: hasKeyphrase ? seoTone : 'bad' }), children: _jsx(YoastSeoAnalysisPanel, { checks: seoChecks, tone: seoTone, hasKeyphrase: hasKeyphrase }) }), _jsx(YoastCollapsible, { title: "Track SEO performance", defaultOpen: false, children: _jsxs("div", { className: "
|
|
85
|
+
}, onGenerate: () => onSeoChange('metaDescription', generateMetaDescriptionSnippet(snippetCtx)) })] })] }) }), _jsx(YoastCollapsible, { title: "SEO analysis", defaultOpen: false, status: _jsx(Dot, { tone: hasKeyphrase ? seoTone : 'bad' }), children: _jsx(YoastSeoAnalysisPanel, { checks: seoChecks, tone: seoTone, hasKeyphrase: hasKeyphrase }) }), _jsx(YoastCollapsible, { title: "Track SEO performance", defaultOpen: false, children: _jsxs("div", { className: "blog_yoast-accordion-panel", children: [_jsx("p", { className: "blog_yoast-help", children: "Track your rankings and see how your content performs in search." }), _jsxs("button", { type: "button", className: "blog_yoast-premium-inline-btn", disabled: true, children: [_jsx("span", { className: "blog_yoast-footer-badge", children: "Wincher" }), "Track SEO performance"] })] }) }), _jsx(YoastCollapsible, { title: "Cornerstone content", defaultOpen: false, children: _jsxs("div", { className: "blog_yoast-accordion-panel", children: [_jsxs("label", { className: "blog_yoast-toggle-row", children: [_jsx("input", { type: "checkbox", checked: cornerstone, onChange: (e) => setCornerstone(e.target.checked) }), _jsx("span", { children: "Mark as cornerstone content" })] }), _jsx("p", { className: "blog_yoast-help", children: "Cornerstone articles should be the most important on your site." })] }) }), _jsx(YoastCollapsible, { title: "Advanced", defaultOpen: false, children: _jsx("div", { className: "blog_yoast-accordion-panel", children: _jsxs("div", { className: "blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Allow search engines to show this Post in search results?" }), _jsxs("select", { className: "blog_fld", value: seo.noindex || visibility === 'private' ? 'no' : 'default', onChange: (e) => onSeoChange('noindex', e.target.value === 'no'), children: [_jsx("option", { value: "default", children: "Default for Posts (Yes)" }), _jsx("option", { value: "yes", children: "Yes" }), _jsx("option", { value: "no", children: "No" })] })] }), _jsxs("fieldset", { className: "blog_yoast-radio-fieldset", children: [_jsx("legend", { children: "Should search engines follow links on this Post?" }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: "yoast-nofollow", checked: !seo.nofollow, onChange: () => onSeoChange('nofollow', false) }), "Yes"] }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: "yoast-nofollow", checked: seo.nofollow, onChange: () => onSeoChange('nofollow', true) }), "No"] })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Meta robots advanced" }), _jsxs("select", { className: "blog_fld", value: metaRobots, onChange: (e) => setMetaRobots(e.target.value), children: [_jsx("option", { value: "", children: "\u2014 None \u2014" }), _jsx("option", { value: "noimageindex", children: "No Image Index" }), _jsx("option", { value: "noarchive", children: "No Archive" }), _jsx("option", { value: "nosnippet", children: "No Snippet" })] })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Breadcrumbs title" }), _jsx("input", { className: "blog_fld", value: seo.breadcrumbTitle, placeholder: title || 'Same as post title', onChange: (e) => onSeoChange('breadcrumbTitle', e.target.value) })] }), _jsxs("label", { className: "blog_fld-row", id: "seo-canonical", children: [_jsx("span", { className: "blog_fld-lbl", children: "Canonical URL" }), _jsx("input", { className: `blog_fld blog_mono${fieldErrors['seo.canonicalOverride'] ? ' blog_is-invalid' : ''}`, type: "url", inputMode: "url", autoComplete: "off", spellCheck: false, value: seo.canonicalOverride, placeholder: "https://brand.com/blog/post", onChange: (e) => {
|
|
86
86
|
onSeoChange('canonicalOverride', e.target.value);
|
|
87
87
|
onClearFieldError('seo.canonicalOverride');
|
|
88
88
|
}, onBlur: (e) => {
|
|
89
89
|
const check = validateCanonicalOverride(e.target.value);
|
|
90
90
|
if (check !== true)
|
|
91
91
|
onSetFieldError('seo.canonicalOverride', check);
|
|
92
|
-
} }), fieldErrors['seo.canonicalOverride'] ? (_jsx("span", { className: "
|
|
92
|
+
} }), fieldErrors['seo.canonicalOverride'] ? (_jsx("span", { className: "blog_fld-error", children: fieldErrors['seo.canonicalOverride'] })) : (_jsx("span", { className: "blog_fld-hint", children: CANONICAL_HINT }))] })] }) }) }), _jsx(YoastCollapsible, { title: "Insights", defaultOpen: false, children: _jsx(YoastInsightsPanel, { contentText: contentText }) }), _jsx(YoastCollapsible, { title: "Internal linking suggestions", defaultOpen: false, children: _jsx(YoastInternalLinksPanel, { contentHtml: contentHtml }) })] })] })) : null, tab === 'readability' ? (_jsxs("div", { className: "blog_yoast-panel", role: "tabpanel", id: "yoast-panel-readability", "aria-labelledby": "yoast-tab-readability", children: [_jsx("p", { className: "blog_yoast-intro", children: "Make your content easy to read. Yoast SEO checks sentence length, passive voice, and more." }), _jsx("div", { className: "blog_yoast-accordion", children: _jsx(YoastCollapsible, { title: "Readability analysis", status: _jsx(Dot, { tone: readTone }), defaultOpen: false, children: _jsx(YoastReadabilityPanel, { checks: readChecks, tone: readTone }) }) })] })) : null, tab === 'schema' ? (_jsxs("div", { className: "blog_yoast-panel", role: "tabpanel", id: "yoast-panel-schema", "aria-labelledby": "yoast-tab-schema", children: [_jsx("p", { className: "blog_yoast-intro", children: "Yoast SEO automatically describes your pages using schema.org. You can change the article type below." }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Page type" }), _jsx("input", { className: "blog_fld", value: "Web Page", readOnly: true, disabled: true }), _jsx("span", { className: "blog_fld-hint", children: "Fixed for blog posts." })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Article type" }), _jsxs("select", { className: "blog_fld", value: seo.schemaType, onChange: (e) => onSeoChange('schemaType', e.target.value), children: [_jsx("option", { value: "Article", children: "Article" }), _jsx("option", { value: "BlogPosting", children: "Blog posting" }), _jsx("option", { value: "NewsArticle", children: "News article" })] })] }), _jsxs("div", { className: "blog_yoast-schema-preview", children: [_jsx("p", { className: "blog_yoast-section-title", children: "Structured data preview" }), _jsxs("ul", { className: "blog_yoast-schema-list", children: [_jsxs("li", { children: [_jsx("strong", { children: seo.schemaType }), " \u2014 headline, dates, authors, publisher"] }), _jsxs("li", { children: [_jsx("strong", { children: "BreadcrumbList" }), " \u2014 Home \u203A Blog \u203A ", categoryName || 'category', " \u203A post"] }), _jsxs("li", { children: [_jsx("strong", { children: "Organization" }), " \u2014 ", siteName] })] })] })] })) : null, tab === 'social' ? (_jsxs("div", { className: "blog_yoast-panel", role: "tabpanel", id: "yoast-panel-social", "aria-labelledby": "yoast-tab-social", children: [_jsx("p", { className: "blog_yoast-intro", children: "Determine how your post should look on social media and in messaging apps." }), _jsxs("div", { className: "blog_yoast-social-preview", children: [socialImage ? (_jsx("img", { className: "blog_yoast-social-img", src: socialImage.url, alt: socialImage.alt || '' })) : (_jsx("div", { className: "blog_yoast-social-img blog_yoast-social-img-empty", children: "No image set" })), _jsxs("div", { className: "blog_yoast-social-text", children: [_jsx("div", { className: "blog_yoast-social-site", children: siteName.toUpperCase() }), _jsx("div", { className: "blog_yoast-social-title", children: socialTitle || 'Post title' }), _jsx("div", { className: "blog_yoast-social-desc", children: socialDesc || 'Description preview…' })] })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Social title ", _jsxs("em", { children: [socialTitle.length, "/", SEO_FIELD_LIMITS.ogTitle] })] }), _jsx("input", { className: `blog_fld${fieldErrors['seo.ogTitle'] ? ' blog_is-invalid' : ''}`, maxLength: SEO_FIELD_LIMITS.ogTitle, value: seo.ogTitle, placeholder: seoTitle || title || 'Falls back to SEO title', onChange: (e) => {
|
|
93
93
|
onClearFieldError('seo.ogTitle');
|
|
94
94
|
onSeoChange('ogTitle', e.target.value);
|
|
95
|
-
} }), fieldErrors['seo.ogTitle'] ? _jsx("span", { className: "
|
|
95
|
+
} }), fieldErrors['seo.ogTitle'] ? _jsx("span", { className: "blog_fld-error", children: fieldErrors['seo.ogTitle'] }) : null] }), _jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Social description ", _jsxs("em", { children: [seo.ogDescription.length, "/", SEO_FIELD_LIMITS.ogDescription] })] }), _jsx("textarea", { className: `blog_fld${fieldErrors['seo.ogDescription'] ? ' blog_is-invalid' : ''}`, rows: 3, maxLength: SEO_FIELD_LIMITS.ogDescription, value: seo.ogDescription, placeholder: metaDesc || 'Falls back to meta description', onChange: (e) => {
|
|
96
96
|
onClearFieldError('seo.ogDescription');
|
|
97
97
|
onSeoChange('ogDescription', e.target.value);
|
|
98
|
-
} }), fieldErrors['seo.ogDescription'] ? _jsx("span", { className: "
|
|
98
|
+
} }), fieldErrors['seo.ogDescription'] ? _jsx("span", { className: "blog_fld-error", children: fieldErrors['seo.ogDescription'] }) : null] }), _jsxs("div", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Social image" }), seo.ogImage ? (_jsxs("div", { className: "blog_thumb-row", children: [_jsx("img", { className: "blog_thumb", src: seo.ogImage.url, alt: seo.ogImage.alt }), _jsxs("div", { className: "blog_btn-row", children: [_jsx("button", { type: "button", className: "blog_btn blog_btn-tiny", onClick: onPickOgImage, children: "Replace" }), _jsx("button", { type: "button", className: "blog_btn blog_btn-tiny", onClick: () => onSeoChange('ogImage', null), children: "Remove" })] })] })) : (_jsxs("div", { className: "blog_stack", children: [_jsx("button", { type: "button", className: "blog_btn blog_btn-tiny", onClick: onPickOgImage, children: "Choose image" }), _jsx("span", { className: "blog_fld-hint", children: featuredImage
|
|
99
99
|
? 'Falls back to the featured image when blank. 1200×630 recommended.'
|
|
100
100
|
: 'Set a featured image or choose a social image. 1200×630 recommended.' })] }))] })] })) : null] })] }));
|
|
101
101
|
};
|
|
@@ -4,7 +4,7 @@ import { useEffect, useId, useRef, useState } from 'react';
|
|
|
4
4
|
const LengthMeter = ({ length, goodMin, goodMax, max, }) => {
|
|
5
5
|
const pct = Math.min(100, Math.round((length / max) * 100));
|
|
6
6
|
const tone = length === 0 ? 'bad' : length < goodMin || length > goodMax ? 'ok' : 'good';
|
|
7
|
-
return (_jsx("div", { className: "
|
|
7
|
+
return (_jsx("div", { className: "blog_yoast-meter", "aria-hidden": "true", children: _jsx("div", { className: "blog_yoast-meter-track", children: _jsx("div", { className: `blog_yoast-meter-fill blog_yoast-meter-${tone}`, style: { width: `${pct}%` } }) }) }));
|
|
8
8
|
};
|
|
9
9
|
export const YoastSnippetField = ({ id, label, value, placeholder, multiline, maxLength, expandedLength, meterGoodMin, meterGoodMax, meterMax, variables, quickVariables = [], generateLabel, error, onChange, onGenerate, }) => {
|
|
10
10
|
const listId = useId();
|
|
@@ -47,5 +47,5 @@ export const YoastSnippetField = ({ id, label, value, placeholder, multiline, ma
|
|
|
47
47
|
maxLength,
|
|
48
48
|
onChange: (e) => onChange(e.target.value),
|
|
49
49
|
};
|
|
50
|
-
return (_jsxs("div", { className: "
|
|
50
|
+
return (_jsxs("div", { className: "blog_yoast-snippet-field", children: [_jsxs("div", { className: "blog_yoast-snippet-label-row", children: [_jsx("label", { className: "blog_yoast-label", htmlFor: id, children: label }), _jsxs("div", { className: "blog_yoast-snippet-actions blog_yoast-snippet-actions-top blog_btn-row", children: [_jsxs("div", { className: "blog_yoast-var-picker", ref: pickerRef, children: [_jsx("button", { type: "button", className: "blog_btn blog_btn-tiny", "aria-expanded": varsOpen, "aria-controls": listId, onClick: () => setVarsOpen((v) => !v), children: "Insert variable" }), varsOpen ? (_jsx("ul", { className: "blog_yoast-var-menu", id: listId, role: "listbox", children: variables.map((v) => (_jsx("li", { children: _jsxs("button", { type: "button", role: "option", className: "blog_yoast-var-option", onClick: () => insertToken(v.token), children: [_jsx("span", { className: "blog_yoast-var-option-label", children: v.label }), _jsx("span", { className: "blog_yoast-var-option-token blog_mono", children: v.token })] }) }, v.label))) })) : null] }), _jsx("button", { type: "button", className: "blog_btn blog_btn-tiny", onClick: onGenerate, children: generateLabel })] })] }), _jsxs("div", { className: "blog_yoast-composite-field", children: [quickVariables.length ? (_jsx("div", { className: "blog_yoast-var-chips blog_yoast-var-chips-inset", "aria-label": `${label} variables`, children: quickVariables.map((v) => (_jsx("button", { type: "button", className: "blog_yoast-var-chip blog_token", onClick: () => insertToken(v.token), children: v.label }, v.label))) })) : null, multiline ? _jsx("textarea", { ...fieldProps, ref: textareaRef, rows: 3 }) : _jsx("input", { ...fieldProps, ref: inputRef, type: "text" })] }), _jsxs("div", { className: "blog_yoast-field-foot", children: [_jsx(LengthMeter, { length: expandedLength, goodMin: meterGoodMin, goodMax: meterGoodMax, max: meterMax }), _jsxs("span", { className: "blog_yoast-char-count", children: [expandedLength, " / ", meterMax] })] }), error ? _jsx("span", { className: "blog_fld-error", children: error }) : null] }));
|
|
51
51
|
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
export function LoadingState({ label = "Loading..." }) {
|
|
3
|
-
return (_jsx("div", { className: "
|
|
3
|
+
return (_jsx("div", { className: "blog_bp-state blog_bp-state--loading", role: "status", children: label }));
|
|
4
4
|
}
|
|
5
5
|
export function ErrorState({ message, authError, }) {
|
|
6
|
-
return (_jsx("div", { className: "
|
|
6
|
+
return (_jsx("div", { className: "blog_bp-state blog_bp-state--error", role: "alert", children: authError
|
|
7
7
|
? "Authentication failed. Check the admin API key. Never use an admin key in a public website."
|
|
8
8
|
: message || "Something went wrong." }));
|
|
9
9
|
}
|
|
10
10
|
export function EmptyState({ label = "Nothing here yet." }) {
|
|
11
|
-
return _jsx("div", { className: "
|
|
11
|
+
return _jsx("div", { className: "blog_bp-state blog_bp-state--empty", children: label });
|
|
12
12
|
}
|
|
13
13
|
export function Field({ label, children, }) {
|
|
14
14
|
return (_jsxs("label", { style: { display: "grid", gap: "0.35rem", marginBottom: "0.85rem" }, children: [_jsx("span", { style: { fontSize: "0.85rem", color: "var(--bp-color-muted)" }, children: label }), children] }));
|
|
@@ -23,9 +23,9 @@ export function Ga4Settings({ brandId, canEdit = true }) {
|
|
|
23
23
|
setFlash("Google Analytics settings saved.");
|
|
24
24
|
});
|
|
25
25
|
};
|
|
26
|
-
return (_jsxs("fieldset", { className: "
|
|
26
|
+
return (_jsxs("fieldset", { className: "blog_seo-module", disabled: !canEdit, children: [!canEdit ? _jsxs("p", { className: "blog_explain", children: ["Only platform admins can change analytics for ", brandName, "."] }) : 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_grid blog_grid-2 blog_seo-grid", children: _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "GA4 measurement" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsx(SeoStatus, { ok: connected, label: connected ? "Measurement ID ready" : "Not connected", detail: connected
|
|
27
27
|
? "ID is saved in the mock store for this session."
|
|
28
|
-
: "Paste a GA4 Measurement ID to start collecting traffic." }), _jsxs("label", { className: "
|
|
28
|
+
: "Paste a GA4 Measurement ID to start collecting traffic." }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Measurement ID" }), _jsx("input", { className: "blog_fld blog_mono", placeholder: "G-XXXXXXXXXX", value: value, onChange: (e) => setValue(e.target.value) })] }), canEdit ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-primary", disabled: pending, onClick: save, children: pending ? "Saving…" : "Save" })) : null] })] }) })] }));
|
|
29
29
|
}
|
|
30
30
|
export function SearchConsoleSettings({ brandId, canEdit = true }) {
|
|
31
31
|
const store = useAdminMock();
|
|
@@ -49,9 +49,9 @@ export function SearchConsoleSettings({ brandId, canEdit = true }) {
|
|
|
49
49
|
setFlash("Search Console verification saved.");
|
|
50
50
|
});
|
|
51
51
|
};
|
|
52
|
-
return (_jsxs("fieldset", { className: "
|
|
52
|
+
return (_jsxs("fieldset", { className: "blog_seo-module", disabled: !canEdit, children: [!canEdit ? _jsxs("p", { className: "blog_explain", children: ["Only platform admins can change verification for ", brandName, "."] }) : 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_grid blog_grid-2 blog_seo-grid", children: _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "HTML tag verification" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsx(SeoStatus, { ok: connected, label: connected ? "Meta tag will publish" : "Not verified yet", detail: connected
|
|
53
53
|
? `Emitted as google-site-verification on ${primaryDomain}.`
|
|
54
|
-
: "Paste the content value from Search Console’s HTML tag method." }), _jsxs("label", { className: "
|
|
54
|
+
: "Paste the content value from Search Console’s HTML tag method." }), _jsxs("label", { className: "blog_fld-row", children: [_jsxs("span", { className: "blog_fld-lbl", children: ["Verification token ", _jsx("em", { children: "content=\u2026 only, not the full meta tag" })] }), _jsx("input", { className: "blog_fld blog_mono", value: value, onChange: (e) => setValue(e.target.value) })] }), canEdit ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-primary", disabled: pending, onClick: save, children: pending ? "Saving…" : "Save" })) : null] })] }) })] }));
|
|
55
55
|
}
|
|
56
56
|
export function SeoBrandList({ rows, onOpen, canEdit = true, canClear, onClear, clearLabel = "Clear", }) {
|
|
57
57
|
const [pending, start] = useTransition();
|
|
@@ -66,14 +66,14 @@ export function SeoBrandList({ rows, onOpen, canEdit = true, canClear, onClear,
|
|
|
66
66
|
alert(res.error);
|
|
67
67
|
});
|
|
68
68
|
};
|
|
69
|
-
return (_jsxs("section", { className: "
|
|
69
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "All brands" }), _jsx("span", { className: "blog_hint", children: rows.length })] }), _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: "Status" }), _jsx("th", { children: "Summary" })] }) }), _jsx("tbody", { children: rows.map((row) => (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("button", { type: "button", className: "blog_row-title", onClick: () => onOpen(row.slug), children: row.name }), _jsx("span", { className: "blog_cell-sub blog_mono", children: row.primaryDomain }), _jsxs("div", { className: "blog_row-actions", children: [_jsx("button", { type: "button", onClick: () => onOpen(row.slug), children: "View" }), canEdit ? (_jsx("button", { type: "button", onClick: () => onOpen(row.slug), children: "Edit" })) : null, canClear && onClear && row.status !== "missing" && row.status !== "default" ? (_jsx("button", { type: "button", className: "blog_danger", disabled: pending, onClick: () => clear(row), children: clearLabel })) : null] })] }), _jsx("td", { children: _jsx("span", { className: `blog_chip ${row.status === "configured" ? "blog_chip-approved" : row.status === "default" ? "blog_chip-writing" : "blog_chip-draft"}`, children: row.statusLabel }) }), _jsx("td", { className: "blog_muted", children: row.summary })] }, row.id))) })] }) })] }));
|
|
70
70
|
}
|
|
71
71
|
export function SitemapPanel({ brandId }) {
|
|
72
72
|
const store = useAdminMock();
|
|
73
73
|
const brand = store.brands.find((b) => b.id === brandId);
|
|
74
74
|
const url = store.data.sitemapNotes[brandId] ?? `https://${brand?.primaryDomain ?? "example.com"}/sitemap.xml`;
|
|
75
75
|
const postCount = store.filterPosts({ state: "live", brandId }).length;
|
|
76
|
-
return (_jsxs("section", { className: "
|
|
76
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "XML Sitemap" }), _jsx("span", { className: "blog_hint", children: brand?.name })] }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("p", { className: "blog_note", style: { marginTop: 0 }, children: ["Mock sitemap for ", brand?.name, ". ", postCount, " published posts would be included."] }), _jsx("p", { className: "blog_mono", children: url }), _jsx("button", { type: "button", className: "blog_btn", onClick: () => {
|
|
77
77
|
void navigator.clipboard?.writeText(url);
|
|
78
78
|
alert("Sitemap URL copied.");
|
|
79
79
|
}, children: "Copy URL" })] })] }));
|
|
@@ -20,5 +20,5 @@ const logTime = (iso) => {
|
|
|
20
20
|
};
|
|
21
21
|
export const RedirectAnalyticsDashboard = ({ data }) => {
|
|
22
22
|
const hasSeries = data.series.some((d) => d.views > 0);
|
|
23
|
-
return (_jsxs("div", { className: "
|
|
23
|
+
return (_jsxs("div", { className: "blog_redir-analytics", children: [_jsxs("section", { className: "blog_kpis", children: [_jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "Total Redirects" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: nf.format(data.totalRules) }) }), _jsx("span", { className: "blog_kpi-sub", children: "Active rules in this scope" })] }), _jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "Today" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: nf.format(data.hitsToday) }) }), _jsx("span", { className: "blog_kpi-sub", children: "Hits since midnight UTC" })] }), _jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "This Week" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: nf.format(data.hitsWeek) }) }), _jsx("span", { className: "blog_kpi-sub", children: "Last 7 days" })] }), _jsxs("div", { className: "blog_kpi", children: [_jsx("span", { className: "blog_kpi-l", children: "This Month" }), _jsx("div", { className: "blog_kpi-row", children: _jsx("span", { className: "blog_kpi-n", children: nf.format(data.hitsMonth) }) }), _jsx("span", { className: "blog_kpi-sub", children: "Last 30 days" })] })] }), _jsxs("div", { className: "blog_redir-analytics-grid", children: [_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Top Redirects" }), _jsx("span", { className: "blog_hint", children: "30 days" })] }), _jsx("div", { className: "blog_panel-body", children: _jsx(BarList, { items: data.topRedirects, unit: " hits", colorVar: "var(--viz-1)" }) })] }), _jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Broken URLs" }), _jsx("span", { className: "blog_hint", children: "404 / 410 / 451" })] }), _jsx("div", { className: "blog_panel-body", children: _jsx(BarList, { items: data.brokenUrls, unit: " hits", colorVar: "var(--viz-4)" }) })] })] }), _jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Last 30 Days" }), _jsx("span", { className: "blog_hint", children: "Daily redirect hits" })] }), _jsx("div", { className: "blog_panel-body", children: hasSeries ? (_jsx(TrendArea, { data: data.series, height: 200 })) : (_jsx("p", { className: "blog_d-empty", style: { margin: 0 }, children: "No redirect traffic recorded yet." })) })] }), _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Recent hits" }) }), _jsx("div", { className: "blog_tw", children: _jsxs("table", { className: "blog_tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "When" }), _jsx("th", { children: "From" }), _jsx("th", { children: "To" }), _jsx("th", { children: "Type" })] }) }), _jsx("tbody", { children: data.recentLogs.map((log) => (_jsxs("tr", { children: [_jsx("td", { className: "blog_mono blog_muted", children: logTime(log.at) }), _jsx("td", { className: "blog_mono", children: log.from }), _jsx("td", { className: "blog_mono blog_muted", children: log.to || "—" }), _jsx("td", { children: _jsx("span", { className: `blog_chip ${log.ok ? "blog_chip-approved" : "blog_chip-draft"}`, children: log.type }) })] }, log.id))) })] }) })] })] }));
|
|
24
24
|
};
|
|
@@ -7,7 +7,7 @@ export function RedirectDetail({ redirectId, onEdit, onBack, canEdit = true, })
|
|
|
7
7
|
const row = store.getRedirect(redirectId);
|
|
8
8
|
const [pending, start] = useTransition();
|
|
9
9
|
if (!row) {
|
|
10
|
-
return (_jsx("section", { className: "
|
|
10
|
+
return (_jsx("section", { className: "blog_panel", children: _jsxs("div", { className: "blog_panel-body", children: [_jsx("p", { className: "blog_d-empty", children: "Redirect not found." }), _jsx("button", { type: "button", className: "blog_btn", onClick: onBack, children: "Back to list" })] }) }));
|
|
11
11
|
}
|
|
12
12
|
const remove = () => {
|
|
13
13
|
if (!confirm(`Delete redirect “${row.from}”?`))
|
|
@@ -21,10 +21,10 @@ export function RedirectDetail({ redirectId, onEdit, onBack, canEdit = true, })
|
|
|
21
21
|
onBack();
|
|
22
22
|
});
|
|
23
23
|
};
|
|
24
|
-
return (_jsxs(_Fragment, { children: [_jsx(RedirectDetailCard, { row: row }), _jsxs("div", { className: "
|
|
24
|
+
return (_jsxs(_Fragment, { children: [_jsx(RedirectDetailCard, { row: row }), _jsxs("div", { className: "blog_btn-row", children: [canEdit ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-primary", onClick: onEdit, children: "Edit" })) : null, canEdit ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-ghost", disabled: pending, onClick: remove, children: pending ? "Deleting…" : "Delete" })) : null, _jsx("button", { type: "button", className: "blog_btn", onClick: onBack, children: "Back to list" })] })] }));
|
|
25
25
|
}
|
|
26
|
-
export const RedirectDetailCard = ({ row }) => (_jsxs("section", { className: "
|
|
27
|
-
? "
|
|
26
|
+
export const RedirectDetailCard = ({ row }) => (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Redirect details" }), _jsx("span", { className: `blog_chip ${row.type === "301" || row.type === "308"
|
|
27
|
+
? "blog_chip-approved"
|
|
28
28
|
: row.type === "404" || row.type === "410" || row.type === "451"
|
|
29
|
-
? "
|
|
30
|
-
: "
|
|
29
|
+
? "blog_chip-draft"
|
|
30
|
+
: "blog_chip-writing"}`, children: row.type })] }), _jsx("div", { className: "blog_panel-body", children: _jsxs("dl", { className: "blog_seo-dl", children: [_jsxs("div", { children: [_jsx("dt", { children: "From" }), _jsx("dd", { className: "blog_mono", children: row.from })] }), _jsxs("div", { children: [_jsx("dt", { children: "Target URL" }), _jsx("dd", { className: "blog_mono", children: row.to || "—" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Origin" }), _jsx("dd", { children: SOURCE_LABEL[row.source] ?? row.source })] }), _jsxs("div", { children: [_jsx("dt", { children: "Brand" }), _jsx("dd", { children: row.brandName ?? "—" })] }), _jsxs("div", { children: [_jsx("dt", { children: "Active" }), _jsx("dd", { children: row.active === false ? "No" : "Yes" })] }), row.note ? (_jsxs("div", { children: [_jsx("dt", { children: "Note" }), _jsx("dd", { children: row.note })] })) : null] }) })] }));
|
|
@@ -69,7 +69,7 @@ export function RedirectForm({ initial, mode, onDone, onCancel, }) {
|
|
|
69
69
|
onDone();
|
|
70
70
|
});
|
|
71
71
|
};
|
|
72
|
-
return (_jsxs("section", { className: "
|
|
72
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: mode === "create" ? "Add redirect" : "Edit redirect" }), _jsx("span", { className: "blog_hint", children: brandName })] }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, form.sources.map((src, i) => (_jsxs("div", { className: "blog_btn-row", style: { alignItems: "flex-end" }, children: [_jsxs("label", { className: "blog_fld-row", style: { flex: 1 }, children: [_jsx("span", { className: "blog_fld-lbl", children: "From path" }), _jsx("input", { className: "blog_fld blog_mono", value: src.path, onChange: (e) => setSource(i, { path: e.target.value }), placeholder: "/old-path" })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Match" }), _jsxs("select", { className: "blog_fld", value: src.match, onChange: (e) => setSource(i, { match: e.target.value }), children: [_jsx("option", { value: "exact", children: "Exact" }), _jsx("option", { value: "contains", children: "Contains" }), _jsx("option", { value: "regex", children: "Regex" })] })] })] }, i))), _jsx("button", { type: "button", className: "blog_btn", onClick: () => setForm((f) => ({ ...f, sources: [...f.sources, emptySource()] })), children: "Add source path" }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Type" }), _jsx("select", { className: "blog_fld", value: form.type, onChange: (e) => set("type", e.target.value), children: TYPE_OPTIONS.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) })] }), needsTarget ? (_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Target URL" }), _jsx("input", { className: "blog_fld blog_mono", value: form.to, onChange: (e) => set("to", e.target.value), placeholder: "/new-path" })] })) : null, _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Note" }), _jsx("input", { className: "blog_fld", value: form.note, onChange: (e) => set("note", e.target.value) })] }), _jsxs("div", { className: "blog_chips", children: [_jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: form.active, onChange: (e) => set("active", e.target.checked) }), " Active"] }), _jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: form.ignoreCase, onChange: (e) => set("ignoreCase", e.target.checked) }), " Ignore case"] }), _jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: form.ignoreTrailingSlash, onChange: (e) => set("ignoreTrailingSlash", e.target.checked) }), " ", "Ignore trailing slash"] }), _jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: form.forceHttps, onChange: (e) => set("forceHttps", e.target.checked) }), " Force HTTPS"] }), _jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: form.preserveQuery, onChange: (e) => set("preserveQuery", e.target.checked) }), " ", "Preserve query"] })] }), _jsxs("div", { className: "blog_btn-row", children: [_jsx("button", { type: "button", className: "blog_btn blog_btn-primary", disabled: pending, onClick: submit, children: pending ? "Saving…" : mode === "create" ? "Create redirect" : "Save redirect" }), _jsx("button", { type: "button", className: "blog_btn", onClick: onCancel, children: "Cancel" })] })] })] }));
|
|
73
73
|
}
|
|
74
74
|
export function redirectToFormValues(row) {
|
|
75
75
|
return {
|
|
@@ -20,9 +20,9 @@ export function RedirectList({ onView, onEdit, onCreate, canEdit = true, }) {
|
|
|
20
20
|
alert(res.error);
|
|
21
21
|
});
|
|
22
22
|
};
|
|
23
|
-
return (_jsxs("section", { className: "
|
|
24
|
-
? "
|
|
23
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "All redirects" }), _jsx("span", { className: "blog_hint", children: rows.length })] }), rows.length === 0 ? (_jsx("div", { className: "blog_panel-body", children: _jsxs("p", { className: "blog_d-empty", style: { margin: 0 }, children: ["No redirects yet.", " ", canEdit ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-ghost blog_btn-sm", onClick: onCreate, children: "Add the first one" })) : null] }) })) : (_jsx("div", { className: "blog_tw", children: _jsxs("table", { className: "blog_tbl", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "From" }), _jsx("th", { children: "To" }), _jsx("th", { children: "Type" }), _jsx("th", { children: "Origin" }), showBrand ? _jsx("th", { children: "Brand" }) : null] }) }), _jsx("tbody", { children: rows.map((r) => (_jsxs("tr", { children: [_jsxs("td", { children: [_jsx("button", { type: "button", className: "blog_row-title blog_mono", onClick: () => onView(r.id), children: r.from }), r.note ? _jsx("span", { className: "blog_cell-sub", children: r.note }) : null, _jsxs("div", { className: "blog_row-actions", children: [_jsx("button", { type: "button", onClick: () => onView(r.id), children: "View" }), canEdit ? (_jsx("button", { type: "button", onClick: () => onEdit(r.id), children: "Edit" })) : null, canEdit ? (_jsx("button", { type: "button", className: "blog_danger", disabled: pending, onClick: () => remove(r), children: "Delete" })) : null] })] }), _jsx("td", { className: "blog_mono blog_muted", children: r.to || "—" }), _jsxs("td", { children: [_jsx("span", { className: `blog_chip ${r.type === "301" || r.type === "308"
|
|
24
|
+
? "blog_chip-approved"
|
|
25
25
|
: r.type === "404" || r.type === "410" || r.type === "451"
|
|
26
|
-
? "
|
|
27
|
-
: "
|
|
26
|
+
? "blog_chip-draft"
|
|
27
|
+
: "blog_chip-writing"}`, children: r.type }), r.active === false ? _jsx("span", { className: "blog_chip blog_chip-draft", children: "Off" }) : null] }), _jsx("td", { className: "blog_muted", children: SOURCE_LABEL[r.source] ?? r.source }), showBrand ? _jsx("td", { className: "blog_muted", children: r.brandName ?? "—" }) : null] }, r.id))) })] }) }))] }));
|
|
28
28
|
}
|
|
@@ -46,5 +46,5 @@ export function RobotsEditor({ brandId, canEdit = true, }) {
|
|
|
46
46
|
setFlash("Robots.txt saved.");
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
|
-
return (_jsxs("fieldset", { className: "
|
|
49
|
+
return (_jsxs("fieldset", { className: "blog_seo-module", disabled: !canEdit, children: [!canEdit ? _jsxs("p", { className: "blog_explain", children: ["Only platform admins can change robots.txt for ", brandName, "."] }) : 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 blog_seo-grid", children: [_jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsxs("h2", { children: ["Rules for ", brandName] }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Allow paths (one per line)" }), _jsx("textarea", { className: "blog_fld blog_mono", rows: 4, value: allow, onChange: (e) => setAllow(e.target.value) })] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Disallow paths (one per line)" }), _jsx("textarea", { className: "blog_fld blog_mono", rows: 4, value: disallow, onChange: (e) => setDisallow(e.target.value) })] }), _jsxs("label", { className: "blog_pick-row", children: [_jsx("input", { type: "checkbox", checked: includeSitemap, onChange: (e) => setIncludeSitemap(e.target.checked) }), " ", "Include sitemap URL"] }), _jsxs("label", { className: "blog_fld-row", children: [_jsx("span", { className: "blog_fld-lbl", children: "Extra rules" }), _jsx("textarea", { className: "blog_fld blog_mono", rows: 3, value: extraRules, onChange: (e) => setExtraRules(e.target.value) })] }), canEdit ? (_jsx("button", { type: "button", className: "blog_btn blog_btn-primary", disabled: pending, onClick: save, children: pending ? "Saving…" : "Save robots.txt" })) : null] })] }), _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Preview" }) }), _jsx("div", { className: "blog_panel-body", children: _jsx("pre", { className: "blog_mono", style: { whiteSpace: "pre-wrap", margin: 0 }, children: preview }) })] })] })] }));
|
|
50
50
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useAdminMock } from "../mock/store";
|
|
3
|
-
export const SeoStatus = ({ ok, label, detail, }) => (_jsxs("div", { className: `
|
|
3
|
+
export const SeoStatus = ({ ok, label, detail, }) => (_jsxs("div", { className: `blog_seo-status ${ok ? "blog_is-ok" : "blog_is-warn"}`, children: [_jsx("span", { className: "blog_seo-status-dot", "aria-hidden": "true" }), _jsxs("div", { children: [_jsx("strong", { children: label }), _jsx("p", { children: detail })] })] }));
|
|
4
4
|
export function BrandPickPanel({ title, onPick, }) {
|
|
5
5
|
const store = useAdminMock();
|
|
6
|
-
return (_jsxs("section", { className: "
|
|
6
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Which brand?" }) }), _jsxs("div", { className: "blog_panel-body", children: [_jsxs("p", { className: "blog_explain", style: { marginTop: 0 }, children: [title, " \u2014 these settings are per brand. Pick one to continue."] }), _jsx("div", { className: "blog_chips", children: store.brands.map((t) => (_jsx("button", { type: "button", className: "blog_btn", onClick: () => onPick(t.id), children: t.name }, t.id))) })] })] }));
|
|
7
7
|
}
|
|
@@ -50,7 +50,7 @@ export function ExportTool() {
|
|
|
50
50
|
setBusy(false);
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
|
-
return (_jsxs("section", { className: "
|
|
53
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Choose what to export" }) }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("p", { className: "blog_note", style: { marginTop: 0 }, children: ["Download a JSON, XML, or CSV file from the mock store", brandSlug ? ` (currently ${brandName})` : " (all brands)", "."] }), error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, _jsxs("fieldset", { className: "blog_export-fieldset", children: [_jsx("legend", { className: "blog_sr-only", children: "Export type" }), options.map((opt) => (_jsxs("label", { className: `blog_export-option${kind === opt.value ? " blog_is-on" : ""}`, children: [_jsx("input", { type: "radio", name: "export-kind", value: opt.value, checked: kind === opt.value, onChange: () => setKind(opt.value) }), _jsxs("span", { className: "blog_export-option-body", children: [_jsx("span", { className: "blog_export-option-label", children: opt.label }), _jsx("span", { className: "blog_export-option-desc", children: opt.description })] })] }, opt.value)))] }), _jsxs("fieldset", { className: "blog_export-fieldset", children: [_jsx("legend", { className: "blog_export-fieldset-label", children: "File format" }), formats.map((opt) => (_jsxs("label", { className: `blog_export-option${format === opt.value ? " blog_is-on" : ""}`, children: [_jsx("input", { type: "radio", name: "export-format", value: opt.value, checked: format === opt.value, onChange: () => setFormat(opt.value) }), _jsxs("span", { className: "blog_export-option-body", children: [_jsx("span", { className: "blog_export-option-label", children: opt.label }), _jsx("span", { className: "blog_export-option-desc", children: opt.description })] })] }, opt.value)))] }), _jsx("div", { className: "blog_btn-row", children: _jsx("button", { type: "button", className: "blog_btn blog_btn-primary", onClick: download, disabled: busy, children: busy ? "Preparing…" : `Download ${format.toUpperCase()} File` }) })] })] }));
|
|
54
54
|
}
|
|
55
55
|
export function ImportTool() {
|
|
56
56
|
const store = useAdminMock();
|
|
@@ -95,12 +95,12 @@ export function ImportTool() {
|
|
|
95
95
|
setBusy(false);
|
|
96
96
|
}
|
|
97
97
|
};
|
|
98
|
-
return (_jsxs("section", { className: "
|
|
98
|
+
return (_jsxs("section", { className: "blog_panel", children: [_jsxs("div", { className: "blog_panel-head", children: [_jsx("h2", { children: "Choose what to import" }), _jsx("span", { className: "blog_hint", children: brandName })] }), _jsxs("div", { className: "blog_panel-body blog_stack", children: [_jsxs("p", { className: "blog_note", style: { marginTop: 0 }, children: ["Upload a JSON file from Tools \u2192 Export. Scoped to ", brandSlug || brandName, "."] }), error ? (_jsx("p", { className: "blog_form-error", role: "alert", children: error })) : null, result ? (_jsxs("div", { className: "blog_form-ok", role: "status", children: ["Imported ", result.postsCreated, " post", result.postsCreated === 1 ? "" : "s", result.postsSkipped ? ` (${result.postsSkipped} skipped)` : "", ", ", result.commentsCreated, " comment", result.commentsCreated === 1 ? "" : "s", result.commentsSkipped ? ` (${result.commentsSkipped} skipped)` : "", "."] })) : null, _jsxs("fieldset", { className: "blog_export-fieldset", children: [_jsx("legend", { className: "blog_sr-only", children: "Import type" }), options.map((opt) => (_jsxs("label", { className: `blog_export-option${kind === opt.value ? " blog_is-on" : ""}`, children: [_jsx("input", { type: "radio", name: "import-kind", value: opt.value, checked: kind === opt.value, onChange: () => setKind(opt.value) }), _jsxs("span", { className: "blog_export-option-body", children: [_jsx("span", { className: "blog_export-option-label", children: opt.label }), _jsx("span", { className: "blog_export-option-desc", children: opt.description })] })] }, opt.value)))] }), _jsxs("div", { className: "blog_import-file", children: [_jsx("input", { ref: fileRef, type: "file", accept: ".json,application/json", className: "blog_sr-only", onChange: (e) => {
|
|
99
99
|
setFile(e.target.files?.[0] ?? null);
|
|
100
100
|
setResult(null);
|
|
101
101
|
setError(null);
|
|
102
|
-
} }), _jsx("button", { type: "button", className: "
|
|
102
|
+
} }), _jsx("button", { type: "button", className: "blog_btn", onClick: () => fileRef.current?.click(), disabled: busy, children: file ? "Change file" : "Choose file" }), _jsx("span", { className: "blog_import-file-name blog_mono", children: file ? file.name : "JSON" })] }), _jsx("div", { className: "blog_btn-row", children: _jsx("button", { type: "button", className: "blog_btn blog_btn-primary", onClick: () => void runImport(), disabled: busy || !file, children: busy ? "Importing…" : "Run Import" }) })] })] }));
|
|
103
103
|
}
|
|
104
104
|
export function ToolsHub({ onExport, onImport }) {
|
|
105
|
-
return (_jsxs(_Fragment, { children: [_jsx("p", { className: "
|
|
105
|
+
return (_jsxs(_Fragment, { children: [_jsx("p", { className: "blog_explain", children: "Utilities for moving content in and out of the portal. Import and export are scoped to the brand selected in the top bar." }), _jsxs("section", { className: "blog_panel", children: [_jsx("div", { className: "blog_panel-head", children: _jsx("h2", { children: "Available Tools" }) }), _jsxs("ul", { className: "blog_seo-link-list", children: [_jsx("li", { children: _jsxs("button", { type: "button", onClick: onExport, style: { width: "100%", textAlign: "left" }, children: [_jsxs("span", { children: [_jsx("strong", { children: "Export" }), _jsx("span", { className: "blog_cell-sub", style: { display: "block", marginTop: 4 }, children: "Download posts and media as JSON, XML, or CSV." })] }), _jsx("span", { className: "blog_mono", children: "Open \u2192" })] }) }), _jsx("li", { children: _jsxs("button", { type: "button", onClick: onImport, style: { width: "100%", textAlign: "left" }, children: [_jsxs("span", { children: [_jsx("strong", { children: "Import" }), _jsx("span", { className: "blog_cell-sub", style: { display: "block", marginTop: 4 }, children: "Bulk import blog posts and comments from JSON." })] }), _jsx("span", { className: "blog_mono", children: "Open \u2192" })] }) })] })] })] }));
|
|
106
106
|
}
|
|
@@ -10,13 +10,13 @@ export function BlogCard({ blog, theme, onSelect, href, lead = false, index = 0,
|
|
|
10
10
|
const thumb = blog.featured_image;
|
|
11
11
|
const showThumb = Boolean(thumb) && !imgFailed;
|
|
12
12
|
const readingMinutes = estimateReadingMinutes([blog.excerpt, blog.content].filter(Boolean).join(" "));
|
|
13
|
-
const body = (_jsxs(_Fragment, { children: [showThumb ? (_jsx("span", { className: "
|
|
14
|
-
return (_jsx("li", { className: lead ? "
|
|
13
|
+
const body = (_jsxs(_Fragment, { children: [showThumb ? (_jsx("span", { className: "blog_card-img", children: _jsx("img", { src: thumb, alt: blog.title, width: lead ? 1600 : 768, height: lead ? 900 : 512, loading: priority ? "eager" : "lazy", decoding: "async", onError: () => setImgFailed(true) }) })) : (_jsx("span", { className: "blog_card-img blog_card-img-blank", "aria-hidden": "true" })), _jsxs("span", { className: "blog_card-body", children: [categoryName ? _jsx("span", { className: "blog_card-eyebrow", children: categoryName }) : null, _jsx("span", { className: "blog_card-title", children: blog.title }), resolved.showExcerpt && blog.excerpt ? (_jsx("span", { className: "blog_card-excerpt", children: blog.excerpt })) : null, _jsxs("span", { className: "blog_card-meta", children: [resolved.showDate && published ? (_jsx("time", { dateTime: published, children: formatDate(published) })) : null, resolved.showAuthor && blog.author?.name ? (_jsx("span", { children: blog.author.name })) : null, _jsxs("span", { children: [readingMinutes, " min read"] })] })] })] }));
|
|
14
|
+
return (_jsx("li", { className: lead ? "blog_card blog_card-lead" : "blog_card", style: { ["--motion-i"]: index }, children: href ? (_jsx("a", { href: href, children: body })) : (_jsx("button", { type: "button", className: "blog_card-link", onClick: () => onSelect?.(blog), children: body })) }));
|
|
15
15
|
}
|
|
16
16
|
export function BlogGrid({ blogs, theme, onSelect, getHref, className, leadFirst = false, }) {
|
|
17
17
|
if (blogs.length === 0)
|
|
18
18
|
return null;
|
|
19
19
|
const lead = leadFirst ? blogs[0] : null;
|
|
20
20
|
const rest = leadFirst ? blogs.slice(1) : blogs;
|
|
21
|
-
return (_jsxs(_Fragment, { children: [lead ? (_jsx("ul", { className: "
|
|
21
|
+
return (_jsxs(_Fragment, { children: [lead ? (_jsx("ul", { className: "blog_post-grid blog_post-grid-lead", children: _jsx(BlogCard, { blog: lead, theme: theme, onSelect: onSelect, href: getHref?.(lead), lead: true, priority: true, index: 0 }) })) : null, rest.length > 0 ? (_jsx("ul", { className: className ? `post-grid ${className}` : "blog_post-grid", children: rest.map((blog, i) => (_jsx(BlogCard, { blog: blog, theme: theme, onSelect: onSelect, href: getHref?.(blog), priority: !lead && i === 0, index: i }, blog.id))) })) : null] }));
|
|
22
22
|
}
|
|
@@ -7,5 +7,5 @@ import { EmptyState, ErrorState, LoadingState, Scope } from "./internal/States";
|
|
|
7
7
|
export function BlogCategories({ config, theme, branding, className, onSelect, }) {
|
|
8
8
|
const client = useMemo(() => new BlogClient(config), [config.apiUrl, config.publicApiKey, config.email, config.domain, config.timeoutMs]);
|
|
9
9
|
const state = useAsync(() => client.getCategories(), [client], (data) => data.length === 0);
|
|
10
|
-
return (_jsxs(Scope, { className: cx("
|
|
10
|
+
return (_jsxs(Scope, { className: cx("blog_bp-blog-categories", branding?.className, className), style: themeVars(theme, branding), css: branding?.css, children: [state.status === "loading" ? _jsx(LoadingState, { label: "Loading categories..." }) : null, state.status === "error" ? (_jsx(ErrorState, { message: state.error, authError: state.authError })) : null, state.status === "empty" ? _jsx(EmptyState, { label: "No categories yet." }) : null, state.status === "success" ? (_jsx("ul", { className: "blog_bp-blog-categories__list", style: { listStyle: "none", padding: 0, margin: 0 }, children: state.data.map((category) => (_jsx("li", { style: { marginBottom: "0.5rem" }, children: _jsx("button", { type: "button", onClick: () => onSelect?.(category), children: category.name }) }, category.id))) })) : null] }));
|
|
11
11
|
}
|
|
@@ -86,5 +86,5 @@ export function BlogDetail({ config, slug, theme, branding, className, trackView
|
|
|
86
86
|
publishedAt: r.published_at,
|
|
87
87
|
readingMinutes: estimateReadingMinutes(r.content || ""),
|
|
88
88
|
}));
|
|
89
|
-
return (_jsxs(Scope, { className: cx("
|
|
89
|
+
return (_jsxs(Scope, { className: cx("blog_bp-blog-detail", "blog_bp-site-article", branding?.className, className), style: themeVars(theme, branding), css: branding?.css, children: [state.status === "loading" ? _jsx(LoadingState, { label: "Loading..." }) : null, state.status === "error" ? (_jsx(ErrorState, { message: state.authError ? state.error : "Blog not found.", authError: state.authError })) : null, post ? (_jsxs(_Fragment, { children: [_jsx(ReadingProgress, {}), _jsx(ArticleDetailHero, { homeHref: homeHref, homeLabel: homeLabel, category: post.category ? { slug: post.category.slug, name: post.category.name } : null, categoryHref: post.category ? categoryPath(post.category.slug) : null, title: post.title, excerpt: post.excerpt, publishedAt: post.published_at, readingMinutes: readingMinutes, authors: authors, mediaUrl: mediaUrl, mediaAlt: post.title, onBack: onBack, onHome: onHome, onCategory: onCategory }), _jsxs("main", { className: "blog_wrap blog_article-shell", children: [_jsx(ArticleRailDetails, { className: "blog_rail-details-mobile", owners: authors, related: railRelated, hrefFor: postPath, onSelect: onSelectRelated }), _jsxs("article", { className: "blog_article", children: [_jsx("div", { className: "blog_prose", dangerouslySetInnerHTML: { __html: contentHtml } }), categories.length > 0 || tags.length > 0 ? (_jsxs("div", { className: "blog_tag-row", children: [categories.map((c) => onCategory ? (_jsx("button", { type: "button", className: "blog_tag-pill", onClick: () => onCategory(c.slug), children: c.name }, c.id)) : (_jsx("a", { className: "blog_tag-pill", href: categoryPath(c.slug), 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 || (config.domain ? `https://${config.domain}` : ""), path: postPath(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: allowComments, initialComments: initialComments, onSubmitComment: onSubmitComment })] }), _jsxs("aside", { className: "blog_rail", children: [_jsx(ArticleRailDetails, { className: "blog_rail-details-desktop", owners: authors, related: railRelated, hrefFor: postPath, onSelect: onSelectRelated }), 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] })] })] })) : state.status === "success" || state.status === "empty" ? (_jsx(EmptyState, { label: "Blog not found." })) : null] }));
|
|
90
90
|
}
|
|
@@ -52,5 +52,5 @@ export function BlogList({ config, theme, branding, className, params, onSelect,
|
|
|
52
52
|
setCategoryId(id);
|
|
53
53
|
setPage(1);
|
|
54
54
|
};
|
|
55
|
-
return (_jsxs(Scope, { className: cx("
|
|
55
|
+
return (_jsxs(Scope, { className: cx("blog_bp-site-index", branding?.className, className), style: themeVars(resolvedTheme, branding), css: branding?.css, children: [showMediaHero ? (_jsx(SiteMediaHero, { slides: heroSlides, siteName: siteName, onSelect: onSelect })) : (_jsxs("section", { className: "blog_site-hero blog_site-animate-in", children: [_jsxs("div", { className: "blog_site-hero-inner", children: [_jsx("p", { className: "blog_site-hero-eyebrow blog_site-animate-item", children: siteName }), _jsx("h1", { className: "blog_site-hero-title blog_site-animate-item", children: heroTitle }), _jsx("p", { className: "blog_site-hero-desc blog_site-animate-item", children: heroDesc })] }), _jsx("div", { className: "blog_site-hero-glow", "aria-hidden": "true" })] })), _jsxs("section", { className: "blog_site-index-feed", "aria-label": feedLabel, children: [_jsxs("div", { className: "blog_site-index-bridge", "aria-hidden": "true", children: [_jsx("span", { className: "blog_site-index-bridge-glow" }), _jsx("span", { className: "blog_site-index-bridge-line" })] }), _jsxs("div", { className: "blog_site-index-feed-inner", children: [_jsxs("header", { className: "blog_site-index-feed-head", children: [_jsx("p", { className: "blog_site-index-feed-eyebrow", children: feedLabel }), _jsx("span", { className: "blog_site-index-feed-rule", "aria-hidden": "true" })] }), _jsxs("div", { className: "blog_site-page blog_site-index-feed-body", children: [categories.length > 0 ? (_jsxs("nav", { className: "blog_cat-bar blog_site-animate-in", "aria-label": "Filter by category", children: [_jsx("button", { type: "button", className: "blog_site-animate-item", "aria-current": !categoryId ? "page" : undefined, onClick: () => selectCategory(undefined), children: "All" }), categories.map((c) => (_jsx("button", { type: "button", className: "blog_site-animate-item", "aria-current": categoryId === c.id ? "page" : undefined, onClick: () => selectCategory(c.id), children: c.name }, c.id)))] })) : null, state.status === "loading" ? _jsx(LoadingState, { label: "Loading blogs..." }) : null, state.status === "error" ? (_jsx(ErrorState, { message: state.error, authError: state.authError })) : null, state.status === "empty" ? (_jsx("p", { className: "blog_empty blog_site-animate-in", children: _jsx("span", { className: "blog_site-animate-item", children: "Nothing published yet." }) })) : null, state.status === "success" ? (_jsxs(_Fragment, { children: [_jsx(BlogGrid, { blogs: state.data.items, theme: resolvedTheme, onSelect: onSelect, getHref: getHref, leadFirst: showLeadCard && state.data.items.length > 0 }), totalPages > 1 ? (_jsxs("div", { className: "blog_pagination", children: [_jsx("button", { type: "button", disabled: page <= 1, onClick: () => setPage((value) => Math.max(1, value - 1)), children: "Previous" }), _jsxs("span", { children: ["Page ", page, " of ", totalPages] }), _jsx("button", { type: "button", disabled: page >= totalPages, onClick: () => setPage((value) => value + 1), children: "Next" })] })) : null] })) : null] })] })] })] }));
|
|
56
56
|
}
|
|
@@ -12,8 +12,8 @@ export function BlogSearch({ config, theme, branding, className, onSelect, getHr
|
|
|
12
12
|
const state = useAsync(() => submitted
|
|
13
13
|
? client.searchBlogs(submitted, { page: 1, page_size: 12 })
|
|
14
14
|
: Promise.resolve({ items: [], page: 1, pageSize: 12, total: 0 }), [client, submitted], (data) => submitted !== "" && data.items.length === 0);
|
|
15
|
-
return (_jsxs(Scope, { className: cx("
|
|
15
|
+
return (_jsxs(Scope, { className: cx("blog_bp-site-index", "blog_bp-blog-search", branding?.className, className), style: themeVars(theme, branding), css: branding?.css, children: [_jsxs("form", { className: "blog_bp-blog-search__form", onSubmit: (event) => {
|
|
16
16
|
event.preventDefault();
|
|
17
17
|
setSubmitted(query.trim());
|
|
18
|
-
}, style: { display: "flex", gap: "0.5rem", marginBottom: "1rem" }, children: [_jsx("input", { value: query, onChange: (event) => setQuery(event.target.value), placeholder: placeholder, "aria-label": "Search blogs", style: { flex: 1, padding: "0.6rem 0.75rem", borderRadius: "var(--bp-radius)" } }), _jsx("button", { type: "submit", children: "Search" })] }), !submitted ? _jsx("p", { className: "
|
|
18
|
+
}, style: { display: "flex", gap: "0.5rem", marginBottom: "1rem" }, children: [_jsx("input", { value: query, onChange: (event) => setQuery(event.target.value), placeholder: placeholder, "aria-label": "Search blogs", style: { flex: 1, padding: "0.6rem 0.75rem", borderRadius: "var(--bp-radius)" } }), _jsx("button", { type: "submit", children: "Search" })] }), !submitted ? _jsx("p", { className: "blog_bp-state", children: "Enter a search term to find posts." }) : null, submitted && state.status === "loading" ? _jsx(LoadingState, { label: "Searching..." }) : null, state.status === "error" ? (_jsx(ErrorState, { message: state.error, authError: state.authError })) : null, state.status === "empty" ? _jsx(EmptyState, { label: "No matching posts." }) : null, state.status === "success" ? (_jsx(BlogGrid, { blogs: state.data.items, theme: theme, onSelect: onSelect, getHref: getHref })) : null] }));
|
|
19
19
|
}
|