Skip to content

Website Builder UX Improvements

  • “Open in Builder” button exists on each WebPage form
  • Users must navigate to each page individually to edit it
  • Preview only refreshes after clicking Save
  • Builder is page-centric, not website-centric

Add “Open Website Builder” button on the Website form that opens the upgraded PageBuilder where users can:

  • See all pages in the website (left sidebar)
  • Switch between pages without leaving the builder
  • Build the entire website from one interface

Decision: Upgrade existing PageBuilder (not a separate component)

2. Real-Time Preview Updates (Auto-update with Debounce)

Section titled “2. Real-Time Preview Updates (Auto-update with Debounce)”

Currently: Preview refreshes only after Save Decision: Auto-update preview as user types (debounced 300-500ms)

Implementation approach:

  • Add debounced onChange handlers to SectionSchemaRenderer fields
  • On change: Update local state immediately
  • After debounce (300ms): Reload iframe to show changes
  • Keep explicit Save button for persisting to database

Simple approach for initial implementation:

  • Reload iframe on debounced change (no backend changes needed)
  • Iframe reloads from database state + pending changes
  • Works with existing templates without modification

Future optimization (Phase 4):

  • Add ?preview=1&draft=<base64> to iframe URL
  • Backend reads draft data from query and uses it for rendering
  • Avoids database writes for preview-only changes

New Layout (Website Builder):

┌─────────────────────────────────────────────────────────────────┐
│ Website: Main Website [Preview] [Save] [×] │
├──────────┬──────────────────────────────────────┬───────────────┤
│ PAGES │ │ SECTION │
│ │ │ SETTINGS │
│ • Home │ │ │
│ • About │ LIVE PREVIEW │ [Form fields] │
│ • Contact│ (iframe) │ │
│ │ │ │
│ [+Page] │ │ │
├──────────┤ │ │
│ SECTIONS │ │ │
│ on page │ │ │
│ │ │ │
│ □ Hero │ │ │
│ □ Feature│ │ │
│ □ CTA │ │ │
│ [+Section│ │ │
└──────────┴──────────────────────────────────────┴───────────────┘

Changes from current PageBuilder:

  1. Add “Pages” panel above “Sections” panel in left sidebar
  2. Clicking a page switches the preview and section list
  3. Track unsaved changes per page
  4. Warn before switching pages with unsaved changes

Backend:

  • fullfinity/modules/website/models/website.py - Add action_open_website_builder method
  • fullfinity/modules/website/views/website_views.json - Add actionButton to Website form

Frontend (upgrade existing components):

  • app/src/components/Website/PageBuilder.jsx - Add page list sidebar, real-time preview
  • app/src/components/Website/PageBuilderPage.jsx - Support both pageId and websiteId params
  • app/src/components/Website/SectionEditor.jsx - Add onChange callback for real-time updates
  • app/src/components/Website/SectionSchemaRenderer.jsx - Add debounced onChange handlers
  • app/src/App.jsx - Add route for /app/website/builder/:websiteId

SectionSchemaRenderer changes:

// Add debounced onChange callback
const debouncedOnChange = useMemo(
() => debounce((newSettings) => {
onPreviewUpdate?.(newSettings);
}, 300),
[onPreviewUpdate]
);
// Call on every field change
const handleFieldChange = (field, value) => {
const newSettings = { ...settings, [field]: value };
setLocalSettings(newSettings);
debouncedOnChange(newSettings);
};

PageBuilder changes:

// Track draft settings separately from saved settings
const [draftSettings, setDraftSettings] = useState({});
// Update preview URL to include draft data
const previewUrl = useMemo(() => {
const base = page?.slug ? `/${page.slug}` : '';
if (Object.keys(draftSettings).length > 0) {
const draft = btoa(JSON.stringify(draftSettings));
return `${base}?preview=1&draft=${draft}`;
}
return base;
}, [page?.slug, draftSettings]);

Backend route changes (web_website.py):

async def _get_page(self, path: str):
# ... existing code ...
# Check for preview mode with draft data
if self._current_request:
preview = self._current_request.query_params.get("preview")
draft = self._current_request.query_params.get("draft")
if preview and draft:
# Store draft data for use in _render_block
import base64
import json
self._draft_settings = json.loads(base64.b64decode(draft))

Phase 1: Real-time preview (quick win)

  • Add debounced onChange to SectionSchemaRenderer
  • Pass changes up to PageBuilder via callback
  • Reload iframe on debounced change
  • Simple but effective improvement

Phase 2: Page switching in PageBuilder

  • Add “Pages” panel to left sidebar (above Sections)
  • Fetch all pages for the website
  • Track current page, switch preview and sections on page click
  • Warn about unsaved changes when switching

Phase 3: Website-level entry point

  • Add action_open_website_builder to Website model
  • Add route /app/website/builder/:websiteId
  • Update PageBuilderPage to handle websiteId param

Phase 4 (Future): Draft preview optimization

  • Add draft query param support to backend
  • Avoid full database save for preview
  • Better performance for rapid changes
  1. Edit section setting → Preview updates within 500ms
  2. Switch between pages → Correct sections shown
  3. Unsaved changes warning when switching pages
  4. Save persists all changes to database
  5. Preview works in both page builder and website builder