Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Comment thread
benlife5 marked this conversation as resolved.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/visual-editor/src/editor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export type LocalDevOptions = {
locale?: string;
locales?: string[];
layoutScopeKey?: string;
themeScopeKey?: string;
initialLayoutData?: Record<string, unknown>;
showOverrideButtons?: boolean;
};
Original file line number Diff line number Diff line change
Expand Up @@ -206,9 +206,9 @@ export const LayoutEditor = (props: LayoutEditorProps) => {
}
}

// Otherwise start fresh from Content
// Otherwise start fresh from published layout data
devLogger.log(
"Layout Dev Mode - No localStorage. Using layout data from Content"
"Layout Dev Mode - No localStorage. Using published layout data"
);
if (layoutData) {
setPuckInitialHistory({
Expand All @@ -221,12 +221,12 @@ export const LayoutEditor = (props: LayoutEditorProps) => {
return;
}

// Nothing in save_state table, start fresh from Content
// Nothing in save_state table, start fresh from published layout data
if (!layoutSaveState) {
clearVisualConfigLocalStorage();

devLogger.log(
"Layout Prod Mode - No saveState. Using layout data from Content"
"Layout Prod Mode - No saveState. Using published layout data"
);
if (layoutData) {
setPuckInitialHistory({
Expand Down
36 changes: 30 additions & 6 deletions packages/visual-editor/src/internal/components/ThemeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,17 @@ export const ThemeEditor = (props: ThemeEditorProps) => {
const localHistoryArray = lzstring.decompress(
window.localStorage.getItem(buildVisualConfigLocalStorageKey()) || ""
);
const localHistories = (
localHistoryArray ? JSON.parse(localHistoryArray) : []
) as History<AppState>[];
let localHistories: History<AppState>[] = [];
if (localHistoryArray) {
try {
localHistories = JSON.parse(localHistoryArray) as History<AppState>[];
} catch (error) {
console.warn(
"Failed to parse local theme editor layout history. Falling back to template layout data.",
error
);
}
}
const histories = localHistories
.filter((h) => h?.state)
.map((h) => {
Expand All @@ -109,6 +117,12 @@ export const ThemeEditor = (props: ThemeEditorProps) => {
sendDevLayoutSaveStateData({
payload: { devSaveStateData: JSON.stringify(layoutToSend) },
});
} else if (layoutData) {
devLogger.log("Theme Dev Mode - Using published layout data");
setPuckInitialHistory({
histories: [{ id: "root", state: { data: layoutData } }],
appendData: false,
});
}
setPuckInitialHistoryFetched(true);
return;
Expand Down Expand Up @@ -150,13 +164,23 @@ export const ThemeEditor = (props: ThemeEditorProps) => {
// Use localStorage directly if it exists
if (localHistoryArray) {
devLogger.log("Theme Dev Mode - Using theme localStorage");
histories = JSON.parse(localHistoryArray) as ThemeHistory[];
index = histories.length - 1;
} else {
try {
histories = JSON.parse(localHistoryArray) as ThemeHistory[];
index = histories.length - 1;
} catch (error) {
console.warn(
"Failed to parse local theme history. Falling back to theme data from Content.",
error
);
}
}

if (!histories?.length) {
// Otherwise start fresh from Content
devLogger.log(
"Theme Dev Mode - No localStorage. Using theme data from Content"
);
index = 0;
if (themeData) {
histories = [{ id: "root", data: themeData }];
}
Expand Down
14 changes: 14 additions & 0 deletions packages/visual-editor/src/internal/types/templateMetadata.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,18 @@ describe("generateTemplateMetadata", () => {
"type.image"
);
});

it("uses themeScopeKey for a shared local-dev theme entity", () => {
const directoryMetadata = generateTemplateMetadata(undefined, {
templateId: "directory",
themeScopeKey: "local-editor",
});
const locatorMetadata = generateTemplateMetadata(undefined, {
templateId: "locator",
themeScopeKey: "local-editor",
});

expect(directoryMetadata.themeEntityId).toBeDefined();
expect(directoryMetadata.themeEntityId).toBe(locatorMetadata.themeEntityId);
});
});
2 changes: 2 additions & 0 deletions packages/visual-editor/src/internal/types/templateMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export function generateTemplateMetadata(
entityId: localDevOptions?.entityId ?? cleanString,
locale,
});
const themeScopeKey = localDevOptions?.themeScopeKey;
const locales = localDevOptions?.locales?.length
? localDevOptions.locales
: ["en", "es", "fr"];
Expand All @@ -141,6 +142,7 @@ export function generateTemplateMetadata(
siteId: 1337,
templateId,
entityId,
themeEntityId: themeScopeKey ? hashCode(themeScopeKey) : undefined,
layoutId: hashCode(layoutScopeKey),
assignment: "ALL",
isDevMode: true,
Expand Down
30 changes: 29 additions & 1 deletion packages/visual-editor/src/local-editor/LocalEditorControls.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import React from "react";
import type { LocalEditorEntityOption } from "./types.ts";
import type { LocalEditorEntityOption, LocalEditorMode } from "./types.ts";

type LocalEditorControlsProps = {
activeEntities: LocalEditorEntityOption[];
activeTemplateOptions: string[];
controlsDisabled: boolean;
selectedEntityId?: string;
selectedLocale: string;
selectedMode: LocalEditorMode;
selectedTemplateId: string;
onEntityChange: (entityId: string) => void;
onLocaleChange: (locale: string) => void;
onModeChange: (mode: LocalEditorMode) => void;
onTemplateChange: (templateId: string) => void;
};

Expand All @@ -19,9 +21,11 @@ export const LocalEditorControls = ({
controlsDisabled,
selectedEntityId,
selectedLocale,
selectedMode,
selectedTemplateId,
onEntityChange,
onLocaleChange,
onModeChange,
onTemplateChange,
}: LocalEditorControlsProps) => {
const selectedEntity = activeEntities.find((entity) => {
Expand Down Expand Up @@ -53,6 +57,30 @@ export const LocalEditorControls = ({
</select>
</ControlGroup>

<ControlGroup label="Editor">
<button
type="button"
disabled={controlsDisabled}
onClick={() => {
onModeChange(selectedMode === "layout" ? "theme" : "layout");
}}
style={{
appearance: "none",
background: controlsDisabled ? "#f5f5f5" : "#111",
border: "1px solid #111",
borderRadius: "6px",
color: controlsDisabled ? "#777" : "#fff",
cursor: controlsDisabled ? "not-allowed" : "pointer",
font: "inherit",
minHeight: "34px",
padding: "6px 10px",
textAlign: "left",
}}
>
{selectedMode === "layout" ? "Layout Editor" : "Theme Editor"}
</button>
</ControlGroup>

<ControlGroup label="Entity">
<select
value={selectedEntityId ?? ""}
Expand Down
22 changes: 19 additions & 3 deletions packages/visual-editor/src/local-editor/LocalEditorShell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,24 @@ export const LocalEditorShell = ({
selectedTemplateDefaults,
selectedEntity,
selectedLocale,
selectedMode,
} = React.useMemo(() => {
return buildLocalEditorSelection(manifest, componentRegistry, searchParams);
}, [componentRegistry, manifest, searchParams]);

React.useEffect(() => {
syncSelectionToUrl(selectedTemplateId, selectedEntity, selectedLocale);
}, [selectedEntity?.entityId, selectedLocale, selectedTemplateId]);
syncSelectionToUrl(
selectedTemplateId,
selectedEntity,
selectedLocale,
selectedMode
);
}, [
selectedEntity?.entityId,
selectedLocale,
selectedMode,
selectedTemplateId,
]);

const documentRequestPath = React.useMemo(() => {
return buildLocalEditorDocumentRequestPath({
Expand Down Expand Up @@ -93,7 +104,7 @@ export const LocalEditorShell = ({
);
}, [manifest?.entitiesByTemplate]);
const controlsDisabled = isManifestLoading || !activeTemplateOptions.length;
const editorKey = `${selectedTemplateId}:${selectedLocale}`;
const editorKey = `${selectedTemplateId}:${selectedLocale}:${selectedMode}`;
const shouldRenderEditorFrame =
isDocumentLoading || (!!documentResponse?.document && !!selectedTemplateId);
const editorLocalDevOptions = React.useMemo(() => {
Expand Down Expand Up @@ -152,13 +163,17 @@ export const LocalEditorShell = ({
controlsDisabled={controlsDisabled}
selectedEntityId={selectedEntity?.entityId}
selectedLocale={selectedLocale}
selectedMode={selectedMode}
selectedTemplateId={selectedTemplateId}
onEntityChange={(entityId) => {
updateSearchParam("entityId", entityId);
}}
onLocaleChange={(locale) => {
updateSearchParam("locale", locale);
}}
onModeChange={(mode) => {
updateSearchParam("mode", mode);
}}
onTemplateChange={(templateId) => {
updateSearchParam("templateId", templateId);
}}
Expand Down Expand Up @@ -249,6 +264,7 @@ export const LocalEditorShell = ({
themeConfig={themeConfig}
localDev={true}
localDevOptions={editorLocalDevOptions}
forceThemeMode={selectedMode === "theme"}
/>
</VisualEditorProvider>
)}
Expand Down
10 changes: 9 additions & 1 deletion packages/visual-editor/src/local-editor/selection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Config } from "@puckeditor/core";
import type { LocalDevOptions } from "../editor/types.ts";
import type {
LocalEditorMode,
LocalEditorEntityOption,
LocalEditorManifestResponse,
BuildEditorLocalDevOptionsArgs,
Expand All @@ -13,6 +14,7 @@ type SelectionResult = {
selectedTemplateDefaults?: BuildEditorLocalDevOptionsArgs["selectedTemplateDefaults"];
selectedEntity?: LocalEditorEntityOption;
selectedLocale: string;
selectedMode: LocalEditorMode;
};

export const updateSearchParam = (key: string, value: string) => {
Expand Down Expand Up @@ -68,6 +70,8 @@ export const buildLocalEditorSelection = (
selectedTemplateDefaults?.locale,
manifest?.defaults.locale
) ?? "";
const selectedMode =
searchParams.get("mode") === "theme" ? "theme" : "layout";

return {
supportedTemplateIds,
Expand All @@ -76,20 +80,23 @@ export const buildLocalEditorSelection = (
selectedTemplateDefaults,
selectedEntity,
selectedLocale,
selectedMode,
};
};

export const syncSelectionToUrl = (
selectedTemplateId: string,
selectedEntity: LocalEditorEntityOption | undefined,
selectedLocale: string
selectedLocale: string,
selectedMode: LocalEditorMode
) => {
if (typeof window === "undefined" || !selectedTemplateId) {
return;
}

const nextSearchParams = new URLSearchParams(window.location.search);
nextSearchParams.set("templateId", selectedTemplateId);
nextSearchParams.set("mode", selectedMode);

if (selectedEntity?.entityId) {
nextSearchParams.set("entityId", selectedEntity.entityId);
Expand Down Expand Up @@ -155,6 +162,7 @@ export const buildEditorLocalDevOptions = ({
locale: selectedLocale,
locales: selectedEntity?.locales ?? [],
layoutScopeKey: `${selectedTemplateId}:${selectedLocale}`,
themeScopeKey: "local-editor",
initialLayoutData: selectedTemplateDefaults?.defaultLayoutData as
| Record<string, unknown>
| undefined,
Expand Down
2 changes: 2 additions & 0 deletions packages/visual-editor/src/local-editor/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export type LocalEditorShellProps = {
themeConfig?: ThemeConfig;
};

export type LocalEditorMode = "layout" | "theme";

export type BuildEditorLocalDevOptionsArgs = {
selectedTemplateId: string;
selectedEntity?: LocalEditorEntityOption;
Expand Down
Loading
Loading