feat: Page Editor v1.0 - canonical schema, SSR parity, and migration
Major improvements to WooNooW Page Editor system: Schema & Architecture: - Canonical section schema with unified sectionSchema.ts - Normalized feature-grid to use items (not features) - Standardized default values across all section types - Schema versioning with automatic migration on read Backend (PHP): - Enhanced PlaceholderRenderer with typed output contracts - Added fallback behavior for empty/invalid dynamic sources - Added caching support for post data resolution - New SchemaMigration class for backward compatibility - New Features class for feature flags - Enhanced PageSSR with full style support - Removed controller-level special-casing for related_posts Frontend (Admin SPA): - Updated CanvasRenderer with schema-aware transformation - Enhanced InspectorPanel with canonical schema metadata - Added new section renderers Frontend (Customer SPA): - New section components: BentoCategoryGrid, MarqueeBanner, ProductCarousel, ShoppableImage - Updated FeatureGridSection for items prop contract Testing: - Add PHP tests: SchemaMigrationTest, PlaceholderRendererTest, PageSSRTest - Add TypeScript tests: schema-integration, feature-grid-regression - Add parity tests for React vs SSR content matching - Add CI script: check-schema-drift.mjs - Add VERIFICATION_CHECKLIST.md Documentation: - RELEASE_NOTES-v1.0.md with full release notes - docs/PAGE_EDITOR_SECTION_SCHEMA_V1.md - docs/PAGE_EDITOR_SSR_COVERAGE_AUDIT.md
This commit is contained in:
54
admin-spa/src/components/layout/Sidebar.tsx
Normal file
54
admin-spa/src/components/layout/Sidebar.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { PanelLeft, PanelLeftClose, Package } from 'lucide-react';
|
||||
import { useActiveSection } from '@/hooks/useActiveSection';
|
||||
import { __ } from '@/lib/i18n';
|
||||
import { iconMap } from '@/lib/nav-icons';
|
||||
|
||||
interface SidebarProps {
|
||||
collapsed: boolean;
|
||||
onToggle: () => void;
|
||||
}
|
||||
|
||||
export function Sidebar({ collapsed, onToggle }: SidebarProps) {
|
||||
const link = "flex items-center gap-2 rounded-md px-3 py-2 hover:bg-accent hover:text-accent-foreground shadow-none hover:shadow-none focus:shadow-none focus:outline-none focus:ring-0 transition-all";
|
||||
const linkCollapsed = "flex items-center justify-center rounded-md p-2 hover:bg-accent hover:text-accent-foreground shadow-none hover:shadow-none focus:shadow-none focus:outline-none focus:ring-0 transition-all";
|
||||
const active = "bg-secondary";
|
||||
const { main } = useActiveSection();
|
||||
|
||||
// Get navigation tree from backend
|
||||
const navTree = window.WNW_NAV_TREE || [];
|
||||
|
||||
return (
|
||||
<aside className={`flex-shrink-0 border-r border-border sticky top-16 h-[calc(100vh-64px)] overflow-y-auto bg-background flex flex-col transition-all duration-200 ${collapsed ? 'w-14' : 'w-56'}`}>
|
||||
{/* Toggle button */}
|
||||
<div className={`p-2 border-b border-border ${collapsed ? 'flex justify-center' : 'flex justify-end'}`}>
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="p-2 rounded-md hover:bg-accent hover:text-accent-foreground transition-colors"
|
||||
title={collapsed ? __('Expand sidebar') : __('Collapse sidebar')}
|
||||
>
|
||||
{collapsed ? <PanelLeft className="w-4 h-4" /> : <PanelLeftClose className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<nav className={`flex flex-col gap-1 flex-1 ${collapsed ? 'p-1' : 'p-3'}`}>
|
||||
{navTree.map((item: any) => {
|
||||
const IconComponent = iconMap[item.icon] || Package;
|
||||
const isActive = main.key === item.key;
|
||||
return (
|
||||
<Link
|
||||
key={item.key}
|
||||
to={item.path}
|
||||
className={`${collapsed ? linkCollapsed : link} ${isActive ? active : ''}`}
|
||||
title={collapsed ? item.label : undefined}
|
||||
>
|
||||
<IconComponent className="w-4 h-4 flex-shrink-0" />
|
||||
{!collapsed && <span>{item.label}</span>}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user