import React, { useState } from 'react'; import { usePages } from '../../state/PageContext'; import { clickableProps } from '../../utils/a11y'; import { PageSettingsModal } from './PageSettingsModal'; export const PagesPanel: React.FC = () => { const { pages, activePageId, isEditingHeader, isEditingFooter, switchPage, editHeader, editFooter, addPage, deletePage, renamePage, duplicatePage, movePage, setLandingPage, updatePageSeo, } = usePages(); const [isAdding, setIsAdding] = useState(false); const [newName, setNewName] = useState(''); const [newSlug, setNewSlug] = useState(''); const [editingId, setEditingId] = useState(null); const [editName, setEditName] = useState(''); const [editSlug, setEditSlug] = useState(''); const [deleteConfirmId, setDeleteConfirmId] = useState(null); const [seoSettingsPageId, setSeoSettingsPageId] = useState(null); const seoSettingsPage = pages.find((p) => p.id === seoSettingsPageId) || null; const handleAdd = () => { if (!newName.trim()) return; addPage(newName.trim(), newSlug.trim()); setNewName(''); setNewSlug(''); setIsAdding(false); }; const handleRename = (pageId: string) => { if (!editName.trim()) return; renamePage(pageId, editName.trim(), editSlug.trim()); setEditingId(null); }; const handleDelete = (pageId: string) => { deletePage(pageId); setDeleteConfirmId(null); }; const startEditing = (page: { id: string; name: string; slug: string }) => { setEditingId(page.id); setEditName(page.name); setEditSlug(page.slug); setDeleteConfirmId(null); }; const autoSlug = (name: string): string => { return name .toLowerCase() .trim() .replace(/[^a-z0-9\s-]/g, '') .replace(/\s+/g, '-') .replace(/-+/g, '-'); }; /* ---------- Zone row style ---------- * Same neutral surface language as the page-list rows below (Item 11) -- * header/footer are just two more items in the tree, not a louder, * differently-colored category. The active/editing state reuses the same * accent-outline treatment the page list already uses for the active page, * so there's one consistent "this is what's currently open" affordance. */ /* ---------- Per-page-row icon button ---------- * Shared 24x24 icon-button styling used by every action in the page row * (SEO settings, rename, duplicate, reorder, set-as-home, delete) so a new * action slots in looking identical to the pre-existing gear/pencil/trash * buttons -- same dark-theme neutral treatment, `disabled` dims the icon * (matching how `disabled` already reads elsewhere in this panel, e.g. the * "Add Page" button), and `danger` reuses the existing delete-button * accent color. */ const pageActionBtnStyle = (opts: { disabled?: boolean; danger?: boolean } = {}): React.CSSProperties => ({ width: 24, height: 24, display: 'inline-flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, color: opts.disabled ? 'var(--color-text-dim)' : opts.danger ? 'var(--color-danger)' : 'var(--color-text-muted)', background: 'transparent', border: 'none', borderRadius: 'var(--radius-sm)', cursor: opts.disabled ? 'default' : 'pointer', opacity: opts.disabled ? 0.5 : 1, }); const zoneRowStyle = (isActive: boolean): React.CSSProperties => ({ display: 'flex', alignItems: 'center', gap: 8, width: '100%', padding: '7px 10px', fontSize: 12, fontWeight: isActive ? 600 : 500, color: isActive ? 'var(--color-accent)' : 'var(--color-text-muted)', background: isActive ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)', border: `1px solid ${isActive ? 'var(--color-accent)' : 'var(--color-border)'}`, borderRadius: 'var(--radius-md)', cursor: 'pointer', transition: 'all var(--transition-fast)', textAlign: 'left' as const, }); return (
{/* Header/Footer zone rows */}
{/* Section label for pages */}
Pages
{/* Page list */} {pages.map((page, pageIndex) => { const isLanding = pageIndex === 0; return (
{editingId === page.id ? ( /* Editing mode */
{ setEditName(e.target.value); setEditSlug(autoSlug(e.target.value)); }} placeholder="Page name" className="control-input" style={{ fontSize: 12 }} autoFocus onKeyDown={(e) => { if (e.key === 'Enter') handleRename(page.id); if (e.key === 'Escape') setEditingId(null); }} /> {isLanding ? (
Landing page — URL locked to /
) : ( setEditSlug(e.target.value)} placeholder="page-slug" className="control-input" style={{ fontSize: 11 }} /> )}
) : deleteConfirmId === page.id ? ( /* Delete confirmation */
Delete "{page.name}"?
) : ( /* Normal page item */
switchPage(page.id))} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '8px 10px', background: page.id === activePageId ? 'var(--color-accent-subtle)' : 'var(--color-bg-elevated)', border: `1px solid ${page.id === activePageId ? 'var(--color-accent)' : 'var(--color-border)'}`, borderRadius: 'var(--radius-md)', cursor: 'pointer', transition: 'all var(--transition-fast)', }} >
{page.name} {isLanding && (