Theme Editor
Overview
The Theme Editor (editor.siyahfy.com) is a visual drag-and-drop editor that allows vendors to customize their storefront theme without writing any code. Vendors can rearrange sections, edit content, adjust styles, configure color schemes, and see changes in a live preview — all from a browser-based interface similar to Shopify’s theme customizer.
Users: Vendors (store owners) and Staff members with theme access
Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 16.x | React framework with App Router |
| React | 19.x | UI library |
| TypeScript | 5.x | Type safety |
| Zustand | 5.x | State management |
| dnd-kit | 6.x / 10.x | Drag-and-drop for section reordering |
| TipTap | 3.x | Inline rich text editing |
| CodeMirror | 6.x | CSS code editing |
| Tailwind CSS | 4.x | Utility-first styling |
| Polaris Icons | 9.x | Consistent iconography |
| canvas-confetti | 1.x | Save celebration animation |
Folder Structure
editor.siyahfy.com/
├── app/
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Landing / redirect
│ ├── editor/
│ │ └── [store_slug]/ # Editor workspace (per store)
│ │ └── page.tsx # Main editor page
│ └── onboarding/
│ └── [store]/ # New store onboarding editor
│ └── page.tsx
├── components/
│ ├── editor/ # Editor panel components
│ │ ├── SectionSidebar.tsx # Left sidebar: section list
│ │ ├── SidebarPanels.tsx # Panel switcher
│ │ ├── SectionSettings.tsx # Section-level settings form
│ │ ├── SubItemSettings.tsx # Block/sub-item settings
│ │ ├── WidgetSettings.tsx # Widget configuration
│ │ ├── WidgetsPanel.tsx # Widget library browser
│ │ ├── WidgetPalette.tsx # Drag-to-add widget palette
│ │ ├── ThemeSettingsPanel.tsx # Global theme settings
│ │ ├── HeaderSettings.tsx # Header configuration
│ │ ├── CheckoutSettingsPanel.tsx # Checkout page settings
│ │ ├── BackgroundPanel.tsx # Section background controls
│ │ ├── ButtonStylePanel.tsx # Button style configuration
│ │ ├── ProductCardSettings.tsx # Product card appearance
│ │ ├── ColorSchemePicker.tsx # Color scheme selector
│ │ ├── ColorPickerWithReset.tsx # Color picker with reset
│ │ ├── SpacingBoxInput.tsx # Margin/padding visual editor
│ │ ├── StepperInput.tsx # Numeric stepper input
│ │ ├── MediaLibraryModal.tsx # Image upload & selection
│ │ ├── LinkPicker.tsx # URL/page link selector
│ │ ├── ProductPickerModal.tsx # Product picker for sections
│ │ ├── CollectionPickerModal.tsx # Collection picker
│ │ ├── PageSelector.tsx # Page selection dropdown
│ │ ├── AddSectionModal.tsx # Add new section dialog
│ │ ├── StructurePicker.tsx # Column layout picker
│ │ ├── CssCodeEditor.tsx # Custom CSS editor (CodeMirror)
│ │ ├── VersionHistoryPanel.tsx # Theme version history
│ │ ├── EditorTopBar.tsx # Top toolbar (save, preview, publish)
│ │ ├── PreviewFrame.tsx # Live preview iframe
│ │ ├── IconRail.tsx # Left icon navigation rail
│ │ ├── ContextMenu.tsx # Right-click context menu
│ │ ├── CustomSectionSettings.tsx # Custom section config
│ │ └── SessionExpiredModal.tsx # Auth expiry handler
│ ├── preview/ # Preview renderers
│ │ ├── SectionRenderer.tsx # Routes section type to component
│ │ ├── HeaderPreview.tsx # Header live preview
│ │ ├── FooterPreview.tsx # Footer live preview
│ │ ├── HeroBanner.tsx # Hero banner preview
│ │ ├── FeaturedCollection.tsx # Featured collection preview
│ │ ├── RichText.tsx # Rich text section preview
│ │ ├── Newsletter.tsx # Newsletter section preview
│ │ ├── AnnouncementBar.tsx # Announcement bar preview
│ │ ├── CartDrawer.tsx # Cart drawer preview
│ │ ├── CustomSectionPreview.tsx # Custom section renderer
│ │ ├── ProductDetailPreview.tsx # Product page preview
│ │ ├── CollectionTemplatePreview.tsx # Collection page preview
│ │ ├── CheckoutContentPreview.tsx # Checkout page preview
│ │ ├── AccountContentPreview.tsx # Account page preview
│ │ ├── CartContentPreview.tsx # Cart page preview
│ │ ├── SearchModal.tsx # Search overlay preview
│ │ └── widgets/ # Widget preview renderers
│ ├── EditorHeader.tsx # App header bar
│ └── ProfileDropdown.tsx # User profile menu
├── hooks/
│ ├── useInlineEditable.ts # Inline text editing in preview
│ └── useIsMobile.ts # Responsive detection
├── lib/
│ ├── editor-store.ts # Zustand store (main editor state)
│ ├── section-schemas.ts # Section type definitions
│ ├── widget-schemas.ts # Widget type definitions
│ ├── column-style-schema.ts # Column layout schemas
│ ├── structure-layouts.ts # Pre-defined column structures
│ ├── color-schemes.ts # Color scheme definitions
│ ├── hover-animations.ts # Hover animation presets
│ ├── icon-library.tsx # Icon set for widgets
│ ├── auth.ts # Authentication helpers
│ └── tiptap-title-chip.ts # TipTap extension for title chips
└── public/ # Static assetsHow the Visual Editor Works
The editor follows a three-panel layout:
┌─────────────────────────────────────────────────────────┐
│ EditorTopBar (Save, Undo, Redo, Preview, Publish) │
├────┬───────────────┬────────────────────────────────────┤
│Icon│ SectionSidebar│ PreviewFrame │
│Rail│ (drag-to- │ (live iframe or │
│ │ reorder │ in-app preview) │
│ │ sections) │ │
│ │ │ │
│ │ SectionSettings │
│ │ (when a │ │
│ │ section is │ │
│ │ selected) │ │
└────┴───────────────┴────────────────────────────────────┘Architecture
-
Zustand Store (
lib/editor-store.ts) — Holds the entire editor state: section list, selected section, theme settings, color schemes, undo/redo history, and dirty-state tracking. -
Section Schemas (
lib/section-schemas.ts) — Define what settings each section type exposes (text fields, color pickers, toggles, sliders, image uploads). The settings panel is auto-generated from these schemas. -
Preview Rendering — The
SectionRenderercomponent reads the section type and dispatches to the correct preview component (HeroBanner,FeaturedCollection, etc.). Changes in the settings panel update the Zustand store, which triggers an immediate re-render in the preview. -
Drag-and-Drop — Uses
@dnd-kit/coreand@dnd-kit/sortableto let vendors reorder sections by dragging them in the sidebar list.
Section Schema System
Each section type has a schema defining its settings, organized by tabs:
// Example section schema structure
{
type: 'hero-banner',
name: 'Hero Banner',
icon: 'ImageIcon',
max_blocks: 5,
settings: [
{ key: 'heading', type: 'text', label: 'Heading', tab: 'content' },
{ key: 'subheading', type: 'text', label: 'Subheading', tab: 'content' },
{ key: 'image', type: 'image', label: 'Background Image', tab: 'content' },
{ key: 'button_text', type: 'text', label: 'Button Text', tab: 'content' },
{ key: 'button_link', type: 'link', label: 'Button Link', tab: 'content' },
{ key: 'color_scheme', type: 'color_scheme', label: 'Color Scheme', tab: 'style' },
{ key: 'height', type: 'range', label: 'Height', min: 300, max: 800, tab: 'style' },
],
blocks: [
{
type: 'slide',
name: 'Slide',
settings: [
{ key: 'image', type: 'image', label: 'Slide Image' },
{ key: 'heading', type: 'text', label: 'Heading' },
]
}
]
}Setting types include: text, textarea, richtext, image, link, color, color_scheme, range, select, toggle, number, product, collection, and page.
Widget System
Widgets are drag-and-drop elements that can be placed inside Custom Sections. The widget palette includes 27+ widgets:
| Widget | Description |
|---|---|
HeadingWidget | Configurable heading (H1-H6) |
TextWidget | Rich text block |
ImageWidget / ImageBoxWidget | Image with optional overlay |
ImageGalleryWidget | Multi-image gallery |
ButtonWidget | Call-to-action button |
VideoWidget | Embedded video player |
IconWidget / IconListWidget | Icon displays |
DividerWidget | Horizontal divider |
SpacerWidget | Vertical spacing |
AccordionWidget | Expandable FAQ/content |
TabsWidget | Tabbed content sections |
CounterWidget | Animated number counter |
TestimonialWidget | Customer testimonial card |
ProductsWidget | Product grid/carousel |
CategoriesWidget | Category display |
SocialIconsWidget | Social media links |
GoogleMapsWidget | Embedded map |
StarRatingWidget | Star rating display |
ProgressBarWidget | Progress bar |
MenuWidget | Navigation menu |
InnerSectionWidget | Nested layout container |
API Communication
The editor communicates with the backend through authenticated API calls:
// Typical pattern
const response = await fetch(`${API_URL}/api/theme-editor/save`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({
store_slug: storeSlug,
sections: editorStore.sections,
settings: editorStore.themeSettings,
})
});Key API endpoints used:
GET /api/theme-editor/load/:store_slug— Load theme configurationPOST /api/theme-editor/save— Save theme changesPOST /api/files/upload— Upload media filesGET /api/storefront/products— Fetch products for pickersGET /api/storefront/collections— Fetch collections for pickers
Key Routes
| Route | Description |
|---|---|
/editor/[store_slug] | Main editor workspace for a store |
/onboarding/[store] | First-time theme setup during onboarding |
State Management
All editor state lives in a single Zustand store (lib/editor-store.ts). Key state includes:
sections— Array of section objects with their settingsselectedSectionId— Currently selected section for editingthemeSettings— Global theme settings (colors, fonts, spacing)colorSchemes— Available color scheme definitionsundoStack/redoStack— Undo/redo historyisDirty— Whether unsaved changes existisSaving— Save operation in progress
Environment Variables
| Variable | Description |
|---|---|
NEXT_PUBLIC_API_URL | Backend API base URL |
NEXT_PUBLIC_STOREFRONT_URL | Storefront preview URL |
NEXT_PUBLIC_EDITOR_URL | Editor URL (self-reference) |
NEXT_PUBLIC_DASHBOARD_URL | Dashboard URL for navigation |