first commit
Some checks failed
Build / run (push) Has been cancelled

This commit is contained in:
maher
2025-10-29 11:42:25 +01:00
commit 703f50a09d
4595 changed files with 385164 additions and 0 deletions

View File

@@ -0,0 +1,100 @@
import {useCallback, useEffect} from 'react';
import {useNavigate} from 'react-router-dom';
import {AllCommands} from '@common/admin/appearance/commands/commands';
import {
removeThemeValue,
setThemeValue,
} from '@common/ui/themes/utils/set-theme-value';
import {applyThemeToDom} from '@common/ui/themes/utils/apply-theme-to-dom';
import {useBootstrapData} from '@common/core/bootstrap-data/bootstrap-data-context';
import {loadFonts} from '@common/ui/font-picker/load-fonts';
export function AppearanceListener() {
const navigate = useNavigate();
const {mergeBootstrapData, data: currentData} = useBootstrapData();
const handleCommand = useCallback(
(command: AllCommands) => {
switch (command.type) {
case 'navigate':
return navigate(command.to);
case 'setValues':
return mergeBootstrapData({
themes: {
...currentData.themes,
all: command.values.appearance.themes.all,
},
settings: {
...currentData.settings,
...command.values.settings,
},
});
case 'setThemeFont':
if (command.value) {
setThemeValue('--be-font-family', command.value.family);
loadFonts([command.value], {
id: 'be-primary-font',
forceAssetLoad: true,
});
} else {
removeThemeValue('--be-font-family');
}
return;
case 'setThemeValue':
return setThemeValue(command.name, command.value);
case 'setActiveTheme':
const theme = currentData.themes.all.find(
t => t.id === command.themeId,
);
if (theme) {
applyThemeToDom(theme);
}
return;
case 'setCustomCode':
return renderCustomCode(command.mode, command.value);
default:
}
},
[currentData, mergeBootstrapData, navigate],
);
useEffect(() => {
const handleMessage = (e: MessageEvent) => {
if (isAppearanceEvent(e) && eventIsTrusted(e)) {
handleCommand(e.data);
}
};
window.addEventListener('message', handleMessage);
return () => {
window.removeEventListener('message', handleMessage);
};
}, [navigate, handleCommand]);
return null;
}
function isAppearanceEvent(e: MessageEvent) {
return e.data?.source === 'be-appearance-editor';
}
function eventIsTrusted(e: MessageEvent): boolean {
return new URL(e.origin).hostname === window.location.hostname;
}
function renderCustomCode(mode: 'html' | 'css', value?: string) {
const parent = mode === 'html' ? document.body : document.head;
const nodeType = mode === 'html' ? 'div' : 'style';
let customNode = parent.querySelector('#be-custom-code');
if (!value) {
if (customNode) {
customNode.remove();
}
} else {
if (!customNode) {
customNode = document.createElement(nodeType);
customNode.id = 'be-custom-code';
parent.appendChild(customNode);
}
customNode.innerHTML = value;
}
}

View File

@@ -0,0 +1,48 @@
import {To} from 'react-router-dom';
import {AppearanceValues} from '../appearance-store';
import {FontConfig} from '@common/http/value-lists';
export interface AppearanceCommand {
source: 'be-appearance-editor';
type: string;
}
export interface Navigate {
type: 'navigate';
to: To;
}
export interface SetAppearanceValues {
type: 'setValues';
values: AppearanceValues;
}
export interface SetThemeValue {
type: 'setThemeValue';
name: string;
value: string;
}
export interface SetActiveTheme {
type: 'setActiveTheme';
themeId: number | string;
}
export interface SetCustomCode {
type: 'setCustomCode';
mode: 'css' | 'html';
value?: string;
}
export interface SetThemeFont {
type: 'setThemeFont';
value: FontConfig | null;
}
export type AllCommands =
| Navigate
| SetAppearanceValues
| SetThemeValue
| SetThemeFont
| SetActiveTheme
| SetCustomCode;

View File

@@ -0,0 +1,11 @@
import {isSsr} from '@common/utils/dom/is-ssr';
export function useAppearanceEditorMode() {
return {
isAppearanceEditorActive:
!isSsr() &&
((window.frameElement as HTMLIFrameElement) || undefined)?.src.includes(
'appearanceEditor=true'
),
};
}