Repository navigation
View and Edit Modes
The Page Builder runs in one of two modes. View mode renders saved pages for visitors (storefronts). Edit mode installs everything needed for the visual editor (dashboards). This page explains how to set up each mode, how lazy loading works, and which props and events the main components expose.
SetupPageBuilder (exported from @selldone/page-builder and @selldone/page-builder/page-builder.ts) installs the
builder as a Vue plugin:
options.mode |
Behavior |
|---|---|
"view" |
Installs the builder. No server options are needed. |
"edit" |
Requires options.server. Throws an error if server is missing. Logs an error if server.uploadImageUrl is not a function or returns an empty value for a test call. |
| anything else | Logs Invalid page builder initial mode! Use 'edit' or 'view'! and installs nothing. |
Calling it without options throws Options are not set in the setup page builder!.
When installed, the builder:
- registers all page elements (
XSection,XContainer,XRow,XColumn,XText,XButton,XUploader,XProducts,XCode, …) as global Vue components, - registers
UFadeScroll,UPriceandUCountDownfrom Components, because Vue code sections can use them, - installs the SVG filters used by CSS filter effects,
- imports the builder stylesheet (
styles/page-builder.scss).
The options object follows builder.IOptions in Builder.types.ts:
| Option | Type | Notes |
|---|---|---|
mode |
"edit" | "view" |
Required. |
server |
{ uploadImageUrl, uploadVideoUrl } |
Required in edit mode. See Upload Handlers. |
customFonts |
Shop.CustomFont[] |
Shop-managed fonts. Kept separate from style.fonts, which is reserved for Google Fonts. |
columnsPrefix |
{ mobile, tablet, desktop, widescreen, ultrawide } |
CSS class prefixes for responsive columns. Defaults: v-col-, v-col-sm-, v-col-md-, v-col-lg-, v-col-xl-. |
title, sections, style, css
|
— | Initial content. Usually left empty and loaded per page. |
type, model
|
"page" | "popup" | "menu", model |
Edit mode only. Normally set per page with $builder.setModel(). |
PageHyper(app, options) (from @selldone/page-builder/PageHyperService.ts) is the recommended entry point. It:
- saves your options as
app.config.globalProperties.$PageHyperOptions, - creates a service and provides it to the app as
$PageHyper, - returns the service, which has an
isInitializedref and aninitialize()method.
LPageViewer and LPageEditor inject $PageHyper, call initialize() on creation, and render only after
isInitialized becomes true. initialize() imports @selldone/page-builder dynamically and calls
SetupPageBuilder(app, options) once. If $PageHyper was never provided, the components log
Page Builder initialization failed: $PageHyper not found!.
import { PageHyper } from "@selldone/page-builder/PageHyperService.ts";
// Storefront (view mode)
const $PageHyper = PageHyper(app, { mode: "view" });// Dashboard (edit mode)
PageHyper(app, {
mode: "edit",
server: {
uploadImageUrl: (type, model) => window.API.POST_UPLOAD_PAGE_IMAGE(model.shop_id, model.id),
uploadVideoUrl: (type, model) => window.API.POST_UPLOAD_PAGE_VIDEO(model.shop_id, model.id),
},
});When you know a page will be shown immediately (for example, the shop home page is a landing page), load the builder up front and mark the service as ready. The Storefront does exactly this:
import { PageHyper } from "@selldone/page-builder/PageHyperService.ts";
import { SetupPageBuilder } from "@selldone/page-builder/page-builder.ts";
const $PageHyper = PageHyper(app, { mode: "view" });
SetupPageBuilder(app, { mode: "view" });
$PageHyper.isInitialized.value = true;@selldone/page-builder/LandingRender.vue (also exported as LandingRender from the package) fetches a page and
renders it with LPageViewer.
| Item | Details |
|---|---|
Prop forceFetchUrl
|
Full URL to fetch the page from. When set, route-based detection is skipped. |
Slot header
|
Content above the page (your shop menu). Positioned over the page when the page style sets menu_transparent. |
Event onFetch:data
|
Emitted with the server response ({ page, augment, asset, ... }). Use it for SEO. |
Event update:page
|
Emitted with the loaded page model. |
Without forceFetchUrl, the endpoint depends on the current route: the custom home page, a landing page by
$route.params.page_name, an include page, or a vendor landing page (all through window.XAPI from the
Storefront SDK). If the server pre-loaded the page in
window.PRE_LOADED_DATA.PAGE, it is used without a network request.
LandingRender also records anonymous mouse-move, click and scroll positions and sends them with the page statistics,
which powers the page heatmap in the Selldone dashboard. On the dashboard preview route (ShopPageRender) it shows the
heatmap instead of recording.
@selldone/page-builder/page/viewer/LPageViewer.vue renders page JSON you already have:
| Prop | Description |
|---|---|
initialPageData |
Page content: { title, sections, style }. |
initialPageCss |
Page CSS: { classes: [{ selector, value }], raw }. |
customFonts |
Optional shop fonts. Falls back to $shop.custom_fonts, then to customFonts passed to PageHyper. |
augment |
Optional dynamic values (key/value items) used to fill dynamic text and images. |
The viewer hides sections according to each section's data.hide flags: sm, md, lg, xl (per breakpoint),
guest (hidden from visitors who are not logged in) and user (hidden from logged-in customers).
@selldone/page-builder/page/editor/LPageEditor.vue is the full editor: artboard, top menu, left menu (hierarchy,
sections, elements, CSS, SEO, statistics, versions, assets), settings dialogs and the uploader toolbar. It injects
$shop and $PageHyper.
| Prop | Type | Description |
|---|---|---|
modelValue |
Object |
The page, popup or menu model. Use v-model to keep it in sync. |
histories |
Array |
Required. Saved versions shown in the Versions panel. Pass [] if you have none. |
backTo |
route location | Required. Target of the back button in the editor header. |
saveFunction |
Function |
Called with $builder.export() ({ title, sections, style }) on save and Ctrl/Cmd + S. |
busySave / busyFetch
|
Boolean |
Show progress while saving or loading. |
fetchPageData |
Function |
Lets the left menu reload the page from your server. |
isPopup / isMenu
|
Boolean |
Edit a popup or a menu page instead of a landing page. Controls the model type passed to upload handlers. |
customFonts |
Array |
Shop fonts available in the editor. |
device |
String |
desktop (default), tablet or mobile. |
hasSettingButton, demo
|
Boolean |
UI options. |
aiAutoFillFunction |
Function |
Optional. Shows an AI button on sections. See AI-Friendly JSON. |
aiPageGenerateFunction |
Function |
Optional. Shows a "generate page" action. See AI-Friendly JSON. |
| Event | Payload |
|---|---|
changeMode |
true when the editor enters edit mode. |
scale |
0.5 when the artboard is scaled down (side menu or sorting), 1 otherwise. |
load:template |
{ content, image } or a page object, when the user starts from a template. |
<template>
<LPageEditor
v-model="page"
:histories="page?.histories || []"
:back-to="{ name: 'ShopPages' }"
:save-function="save"
:busy-save="busySave"
/>
</template>
<script lang="ts">
import LPageEditor from "@selldone/page-builder/page/editor/LPageEditor.vue";
export default {
components: { LPageEditor },
data: () => ({ page: null, busySave: false }),
methods: {
async save(content) {
this.busySave = true;
try {
// Persist content (and page.css) with your API
} finally {
this.busySave = false;
}
},
},
};
</script>When modelValue changes, the editor calls $builder.setModel(type, model) and $builder.loadPage(model), then
saves an initial history entry.
| Shortcut | Action |
|---|---|
| Ctrl/Cmd + S | Save |
| Ctrl/Cmd + Z | Undo |
| Ctrl/Cmd + Y | Redo |
| Ctrl/Cmd + E | Toggle the copy-style pipette (click a source element, then a target) |
| Esc | Leave copy-style mode |
| Tab | Toggle the side menu and the scaled-down overview |
| Ctrl/Cmd + B, I, U, L, R | Bold, italic, underline, strike-through, remove formatting (inside editable text) |
| Ctrl/Cmd + 1 / 2 | Make selected text smaller / bigger (inside editable text) |
Set window.PAGE_BUILDER_BLOCK_LISTEN_KEYS = true to temporarily stop the editor from handling keys, for example while
your own dialog is open.
Both components create a reactive Builder instance and provide it to children as $builder. Useful methods:
| Method | Description |
|---|---|
loadPage({ content, css, direction }) |
Load page content, CSS and text direction (ltr, rtl, auto). Migrates old content. |
export() |
Return { title, sections, style } and write it to model.content when a model is set. |
setModel(type, model) |
Link the builder to a page, popup or menu model (used for upload URLs). |
setAssets(images, videos) / getAssets()
|
Media library shown in the editor. |
setCustomFonts(fonts) |
Replace the shop font catalog. |
add(section, position), remove(section), sort(old, new), find(uid), clear()
|
Manage sections. |
history.undo(), history.redo(), history.save()
|
Local history (up to 50 entries, saves are throttled to one every 2 seconds). |
importer.loadFile(file) |
Load a .landing file into the current page. |