topbar: surface publish warnings instead of discarding them

handlePublish's JSON response has always included a `warnings` array
(e.g. the contact-form relay's "submissions will not be delivered"
notice), but nothing in the editor ever read it. Adds a PublishWarnings
banner, held in its own state independent of the 3s publishStatus
flash so the customer has time to read it, rendered in both the
desktop and mobile TopBar branches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-15 21:52:11 -07:00
co-authored by Claude Opus 4.8
parent 2b1569202a
commit d460e8ac33
4 changed files with 132 additions and 0 deletions
+9
View File
@@ -10,6 +10,7 @@ import { DeviceMode } from '../../types';
import { TemplateModal } from './TemplateModal';
import { HeadCodeModal } from './HeadCodeModal';
import { TopBarOverflowMenu } from './TopBarOverflowMenu';
import { PublishWarnings } from './PublishWarnings';
import { SitesmithButton } from '../sitesmith/SitesmithButton';
import { useSitesmithModal } from '../../state/SitesmithContext';
@@ -33,6 +34,7 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange, showGuid
const [saveStatus, setSaveStatus] = useState<'idle' | 'saving' | 'saved' | 'error'>('idle');
const [publishStatus, setPublishStatus] = useState<'idle' | 'publishing' | 'published' | 'error'>('idle');
const [publishWarnings, setPublishWarnings] = useState<string[]>([]);
const [isDraft, setIsDraft] = useState(false);
// Mobile-A2: lifted from private useState into MobileChromeContext so
// opening a mobile sheet can close these modals (item 3) -- behavior is
@@ -100,11 +102,16 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange, showGuid
const handlePublish = useCallback(async () => {
setPublishStatus('publishing');
setPublishWarnings([]);
try {
const result = await publish();
if (result?.success) {
setPublishStatus('published');
setIsDraft(false);
// The site published; these are fixable problems, not failures. Held
// independently of publishStatus so the 3s "Published" flash doesn't
// take the warning down with it.
setPublishWarnings(Array.isArray(result.warnings) ? result.warnings : []);
if (publishTimeoutRef.current) clearTimeout(publishTimeoutRef.current);
publishTimeoutRef.current = setTimeout(() => setPublishStatus('idle'), 3000);
} else {
@@ -220,6 +227,7 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange, showGuid
if (isMobile) {
return (
<nav className="topbar topbar-mobile">
<PublishWarnings warnings={publishWarnings} onDismiss={() => setPublishWarnings([])} />
<div className="topbar-left">
{isWHP && (
<a
@@ -307,6 +315,7 @@ export const TopBar: React.FC<TopBarProps> = ({ device, onDeviceChange, showGuid
return (
<nav className="topbar">
<PublishWarnings warnings={publishWarnings} onDismiss={() => setPublishWarnings([])} />
<div className="topbar-left">
{isWHP && (
<a href={whpConfig!.backUrl} className="topbar-btn back-btn" aria-label="Back to Panel">