Files
mtdb_movie/common/resources/client/admin/appearance/appearance-store.ts
maher 703f50a09d
Some checks failed
Build / run (push) Has been cancelled
first commit
2025-10-29 11:42:25 +01:00

135 lines
4.0 KiB
TypeScript
Executable File

import {create} from 'zustand';
import {subscribeWithSelector} from 'zustand/middleware';
import {immer} from 'zustand/middleware/immer';
import {Settings} from '../../core/settings/settings';
import type {IAppearanceConfig} from './types/appearance-editor-config';
import {AllCommands} from './commands/commands';
import mergedAppearanceConfig from './config/merged-appearance-config';
import {BootstrapData} from '../../core/bootstrap-data/bootstrap-data';
import {FontConfig} from '@common/http/value-lists';
export interface AppearanceValues {
appearance: {
env: {app_name: string; app_url: string};
seo: {
key: string;
name: string;
value: string;
defaultValue: string;
}[];
themes: BootstrapData['themes'];
custom_code: {
css?: string;
html?: string;
};
};
settings: Settings;
}
export interface AppearanceDefaults {
appearance: {
themes: {
light: Record<string, string>;
dark: Record<string, string>;
};
};
settings: Settings;
}
interface AppearanceStore {
defaults: AppearanceDefaults | null;
iframeWindow: Window | null;
config: IAppearanceConfig | null;
setDefaults: (value: AppearanceDefaults) => void;
setIframeWindow: (value: Window) => void;
preview: {
navigate: (sectionName: string) => void;
setValues: (settings: AppearanceValues) => void;
setThemeFont: (font: FontConfig | null) => void;
setThemeValue: (name: string, value: string) => void;
setActiveTheme: (themeId: number | string) => void;
setHighlight: (selector: string | null | undefined) => void;
setCustomCode: (mode: 'css' | 'html', value?: string) => void;
};
}
export const useAppearanceStore = create<AppearanceStore>()(
subscribeWithSelector(
immer((set, get) => ({
defaults: null,
iframeWindow: null,
config: mergedAppearanceConfig,
setDefaults: value => {
set(state => {
state.defaults = {...value};
});
},
setIframeWindow: value => {
set(() => {
return {iframeWindow: value};
});
},
preview: {
navigate: sectionName => {
const section = get().config?.sections[sectionName];
const route = section?.previewRoute || '/';
const preview = get().iframeWindow;
if (route) {
postMessage(preview, {type: 'navigate', to: route});
}
},
setValues: values => {
const preview = get().iframeWindow;
postMessage(preview, {type: 'setValues', values});
},
setThemeFont: font => {
const preview = get().iframeWindow;
postMessage(preview, {type: 'setThemeFont', value: font});
},
setThemeValue: (name, value) => {
const preview = get().iframeWindow;
postMessage(preview, {type: 'setThemeValue', name, value});
},
setActiveTheme: themeId => {
const preview = get().iframeWindow;
postMessage(preview, {type: 'setActiveTheme', themeId});
},
setCustomCode: (mode, value) => {
const preview = get().iframeWindow;
postMessage(preview, {type: 'setCustomCode', mode, value});
},
setHighlight: selector => {
set(() => {
let node: HTMLElement | null = null;
const document = get().iframeWindow?.document;
if (document && selector) {
node = document.querySelector(selector);
}
if (node) {
requestAnimationFrame(() => {
if (!node) return;
node.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'center',
});
});
}
});
},
},
})),
),
);
function postMessage(window: Window | null, command: AllCommands) {
if (window) {
window.postMessage({source: 'be-appearance-editor', ...command}, '*');
}
}
export function appearanceState() {
return useAppearanceStore.getState();
}