From e8826be2768e16b10d03a3d6f12e1c8d3a5a6970 Mon Sep 17 00:00:00 2001 From: "haitao(lj)" Date: Tue, 13 Dec 2022 16:43:29 +0800 Subject: [PATCH 1/5] feat(Customize): demo with customize --- ui/src/common/interface.ts | 1 + ui/src/components/Customize/index.tsx | 84 +++++++++++++++++++++++++ ui/src/components/SchemaForm/index.tsx | 2 + ui/src/components/index.ts | 2 + ui/src/pages/Admin/CssAndHtml/index.tsx | 7 +++ ui/src/pages/Layout/index.tsx | 3 +- ui/src/stores/customize.ts | 30 +++++++++ ui/src/stores/index.ts | 2 + ui/src/utils/guard.ts | 2 + 9 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 ui/src/components/Customize/index.tsx create mode 100644 ui/src/stores/customize.ts diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts index 843bb687..e9ea4cce 100644 --- a/ui/src/common/interface.ts +++ b/ui/src/common/interface.ts @@ -321,6 +321,7 @@ export interface SiteSettings { general: AdminSettingsGeneral; interface: AdminSettingsInterface; login: AdminSettingsLogin; + custom_css_html: AdminSettingsCustom; } export interface AdminSettingBranding { diff --git a/ui/src/components/Customize/index.tsx b/ui/src/components/Customize/index.tsx new file mode 100644 index 00000000..4f54bccd --- /dev/null +++ b/ui/src/components/Customize/index.tsx @@ -0,0 +1,84 @@ +import { FC, memo, useEffect } from 'react'; + +import { customizeStore } from '@/stores'; + +const getElementByAttr = (attr: string, elName: string) => { + let el = document.querySelector(`[${attr}]`); + if (!el) { + el = document.createElement(elName); + el.setAttribute(attr, ''); + } + return el; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const textToDf = (t) => { + const dummyDoc = document.createElement('div'); + dummyDoc.innerHTML = t; + const frag = document.createDocumentFragment(); + while (dummyDoc.childNodes.length) { + frag.appendChild(dummyDoc.children[0]); + } + return frag; +}; + +const injectCustomCSS = (t: string) => { + if (!t) { + return; + } + const el = getElementByAttr('data-custom-css', 'style'); + el.textContent = t; + document.head.insertBefore(el, document.head.lastChild); +}; + +const injectCustomHead = (t: string) => { + if (!t) { + return; + } + setTimeout(() => { + const el = getElementByAttr('data-custom-head', 'style'); + el.textContent = t; + document.head.appendChild(el); + }, 200); +}; + +const injectCustomHeader = (t: string) => { + if (!t) { + return; + } + // const frag = textToDf(t); + t = ' Customize Header '; + document.body.insertBefore( + document.createComment(t), + document.body.firstChild, + ); +}; + +const injectCustomFooter = (t: string) => { + if (!t) { + return; + } + // FIXME + t = ' Customize Footer '; + // const frag = textToDf(t); + document.documentElement.appendChild(document.createComment(t)); +}; + +const Index: FC = () => { + const { custom_css, custom_head, custom_header, custom_footer } = + customizeStore((state) => state); + useEffect(() => { + injectCustomCSS(custom_css); + injectCustomHead(custom_head); + injectCustomHeader(custom_header); + injectCustomFooter(custom_footer); + }, []); + return ( + <> + {null} + {/* App customize */} + + ); +}; + +export default memo(Index); diff --git a/ui/src/components/SchemaForm/index.tsx b/ui/src/components/SchemaForm/index.tsx index 73a94407..a004deb6 100644 --- a/ui/src/components/SchemaForm/index.tsx +++ b/ui/src/components/SchemaForm/index.tsx @@ -58,6 +58,7 @@ export interface UISchema { | 'url' | 'week'; empty?: string; + className?: string | string[]; validator?: ( value, formData?, @@ -459,6 +460,7 @@ const SchemaForm: ForwardRefRenderFunction = ( onChange={handleInputChange} isInvalid={formData[key].isInvalid} rows={options?.rows || 3} + className={classnames(options.className)} /> {formData[key]?.errorMsg} diff --git a/ui/src/components/index.ts b/ui/src/components/index.ts index f8fa4181..8ce3b751 100644 --- a/ui/src/components/index.ts +++ b/ui/src/components/index.ts @@ -27,6 +27,7 @@ import BrandUpload from './BrandUpload'; import SchemaForm, { JSONSchema, UISchema, initFormData } from './SchemaForm'; import Labels from './LabelsCard'; import DiffContent from './DiffContent'; +import Customize from './Customize'; export { Avatar, @@ -60,5 +61,6 @@ export { initFormData, Labels, DiffContent, + Customize, }; export type { EditorRef, JSONSchema, UISchema }; diff --git a/ui/src/pages/Admin/CssAndHtml/index.tsx b/ui/src/pages/Admin/CssAndHtml/index.tsx index b050d87e..f2ec26dd 100644 --- a/ui/src/pages/Admin/CssAndHtml/index.tsx +++ b/ui/src/pages/Admin/CssAndHtml/index.tsx @@ -42,24 +42,28 @@ const Index: FC = () => { 'ui:widget': 'textarea', 'ui:options': { rows: 10, + className: ['fs-14', 'font-monospace'], }, }, custom_head: { 'ui:widget': 'textarea', 'ui:options': { rows: 10, + className: ['fs-14', 'font-monospace'], }, }, custom_header: { 'ui:widget': 'textarea', 'ui:options': { rows: 10, + className: ['fs-14', 'font-monospace'], }, }, custom_footer: { 'ui:widget': 'textarea', 'ui:options': { rows: 10, + className: ['fs-14', 'font-monospace'], }, }, }; @@ -82,6 +86,9 @@ const Index: FC = () => { msg: t('update', { keyPrefix: 'toast' }), variant: 'success', }); + setTimeout(() => { + window.location.reload(); + }, 3000); }) .catch((err) => { if (err.isError) { diff --git a/ui/src/pages/Layout/index.tsx b/ui/src/pages/Layout/index.tsx index 7726574d..462b9beb 100644 --- a/ui/src/pages/Layout/index.tsx +++ b/ui/src/pages/Layout/index.tsx @@ -5,7 +5,7 @@ import { Helmet, HelmetProvider } from 'react-helmet-async'; import { SWRConfig } from 'swr'; import { toastStore, brandingStore, pageTagStore } from '@/stores'; -import { Header, Footer, Toast } from '@/components'; +import { Header, Footer, Toast, Customize } from '@/components'; const Layout: FC = () => { const { msg: toastMsg, variant, clear: toastClear } = toastStore(); @@ -41,6 +41,7 @@ const Layout: FC = () => {