@wikex/admin-kit 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/admin/before-login.d.ts +5 -0
- package/dist/admin/before-login.js +26 -0
- package/dist/admin/brand.d.ts +19 -0
- package/dist/admin/brand.js +15 -0
- package/dist/admin/header.d.ts +5 -0
- package/dist/admin/header.js +87 -0
- package/dist/admin/logout-button.d.ts +8 -0
- package/dist/admin/logout-button.js +7 -0
- package/dist/admin/nav.d.ts +19 -0
- package/dist/admin/nav.js +285 -0
- package/dist/admin/theme-toggle.d.ts +5 -0
- package/dist/admin/theme-toggle.js +7 -0
- package/dist/admin/view-site.d.ts +5 -0
- package/dist/admin/view-site.js +6 -0
- package/dist/chunk-7FEACJUN.js +151 -0
- package/dist/chunk-BUD6BMFV.js +117 -0
- package/dist/chunk-GGSOO4FQ.js +27 -0
- package/dist/chunk-IL2CUCDG.js +2062 -0
- package/dist/chunk-JJLHSZ3T.js +40 -0
- package/dist/chunk-LC2CP5SR.js +13 -0
- package/dist/chunk-LP22Y3NO.js +61 -0
- package/dist/chunk-MDMKKWPU.js +12 -0
- package/dist/chunk-W4ZKDOWJ.js +37 -0
- package/dist/chunk-XGKGKCQ6.js +50 -0
- package/dist/chunk-YMBJCWN3.js +73 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +44 -0
- package/dist/live-preview.d.ts +50 -0
- package/dist/live-preview.js +19 -0
- package/dist/project.d.ts +34 -0
- package/dist/project.js +8 -0
- package/dist/rich-text-client.d.ts +5 -0
- package/dist/rich-text-client.js +165 -0
- package/dist/rich-text.d.ts +5 -0
- package/dist/rich-text.js +6 -0
- package/dist/runtimeConfig-BwjQepcW.d.ts +30 -0
- package/dist/starter-client.d.ts +15 -0
- package/dist/starter-client.js +25 -0
- package/dist/starter.d.ts +40 -0
- package/dist/starter.js +62 -0
- package/dist/text-style-runtime.d.ts +5 -0
- package/dist/text-style-runtime.js +8 -0
- package/dist/text-styles.d.ts +86 -0
- package/dist/text-styles.js +22 -0
- package/package.json +23 -19
- package/src/TextStyleRuntime.tsx +0 -90
- package/src/admin/BeforeLogin.tsx +0 -19
- package/src/admin/Brand.tsx +0 -74
- package/src/admin/Header.tsx +0 -87
- package/src/admin/LogoutButton.tsx +0 -41
- package/src/admin/Nav.tsx +0 -35
- package/src/admin/NavClient.tsx +0 -288
- package/src/admin/ThemeToggle.tsx +0 -31
- package/src/admin/ViewSite.tsx +0 -11
- package/src/admin/useAdminBrand.ts +0 -81
- package/src/adminExperience.ts +0 -117
- package/src/index.ts +0 -11
- package/src/live-preview/GlobalInlineInspector.tsx +0 -334
- package/src/live-preview/LivePreviewEditor.tsx +0 -2088
- package/src/live-preview/TextStyleInspector.tsx +0 -289
- package/src/live-preview/index.ts +0 -23
- package/src/live-preview/runtimeConfig.ts +0 -52
- package/src/plugin.ts +0 -70
- package/src/project.ts +0 -82
- package/src/rich-text/client.tsx +0 -202
- package/src/rich-text/index.ts +0 -10
- package/src/starter/client.tsx +0 -22
- package/src/starter.ts +0 -95
- package/src/textStyles.ts +0 -161
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
type BlockPickerScope = 'page' | 'post';
|
|
2
|
+
type BlockPickerOption = {
|
|
3
|
+
description: string;
|
|
4
|
+
image?: string;
|
|
5
|
+
label: string;
|
|
6
|
+
payloadLabel?: string;
|
|
7
|
+
slug: string;
|
|
8
|
+
};
|
|
9
|
+
type VisualEditorDocumentTarget = {
|
|
10
|
+
collection: string;
|
|
11
|
+
documentID: string;
|
|
12
|
+
kind: 'collection';
|
|
13
|
+
} | {
|
|
14
|
+
global: string;
|
|
15
|
+
kind: 'global';
|
|
16
|
+
};
|
|
17
|
+
type VisualEditorScope = 'content' | 'footer' | 'header';
|
|
18
|
+
type VisualEditorRoute = {
|
|
19
|
+
documentTarget: VisualEditorDocumentTarget | null;
|
|
20
|
+
scope: VisualEditorScope;
|
|
21
|
+
type: 'collection' | 'global';
|
|
22
|
+
};
|
|
23
|
+
type LivePreviewRuntimeConfig = {
|
|
24
|
+
getVisualEditorRoute: (pathname: string) => VisualEditorRoute | null;
|
|
25
|
+
pageBlocks: readonly BlockPickerOption[];
|
|
26
|
+
postBlocks: readonly BlockPickerOption[];
|
|
27
|
+
};
|
|
28
|
+
declare const configureLivePreview: (config: LivePreviewRuntimeConfig) => void;
|
|
29
|
+
|
|
30
|
+
export { type BlockPickerOption as B, type LivePreviewRuntimeConfig as L, type VisualEditorDocumentTarget as V, type BlockPickerScope as a, type VisualEditorRoute as b, type VisualEditorScope as c, configureLivePreview as d };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { WikexStarter } from './starter.js';
|
|
3
|
+
import '@wikex/content-kit';
|
|
4
|
+
import './runtimeConfig-BwjQepcW.js';
|
|
5
|
+
import './project.js';
|
|
6
|
+
|
|
7
|
+
type LivePreviewConfig = WikexStarter['livePreview'] & {
|
|
8
|
+
getVisualEditorRoute: WikexStarter['getVisualEditorRoute'];
|
|
9
|
+
};
|
|
10
|
+
/** Configure and return the shared client-side Live Preview provider for a Wikex starter. */
|
|
11
|
+
declare const createWikexLivePreviewAdapter: ({ brand, getVisualEditorRoute, pageBlocks, postBlocks, }: LivePreviewConfig) => ({ children }: {
|
|
12
|
+
children?: React.ReactNode;
|
|
13
|
+
}) => react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
export { createWikexLivePreviewAdapter };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import {
|
|
3
|
+
LivePreviewEditor_default,
|
|
4
|
+
configureLivePreview
|
|
5
|
+
} from "./chunk-IL2CUCDG.js";
|
|
6
|
+
import "./chunk-BUD6BMFV.js";
|
|
7
|
+
import "./chunk-LP22Y3NO.js";
|
|
8
|
+
import {
|
|
9
|
+
configureAdminBrand
|
|
10
|
+
} from "./chunk-XGKGKCQ6.js";
|
|
11
|
+
|
|
12
|
+
// src/starter/client.tsx
|
|
13
|
+
var createWikexLivePreviewAdapter = ({
|
|
14
|
+
brand,
|
|
15
|
+
getVisualEditorRoute,
|
|
16
|
+
pageBlocks,
|
|
17
|
+
postBlocks
|
|
18
|
+
}) => {
|
|
19
|
+
configureAdminBrand({ logo: { alt: brand.name, ...brand.logo }, siteName: brand.name });
|
|
20
|
+
configureLivePreview({ getVisualEditorRoute, pageBlocks, postBlocks });
|
|
21
|
+
return LivePreviewEditor_default;
|
|
22
|
+
};
|
|
23
|
+
export {
|
|
24
|
+
createWikexLivePreviewAdapter
|
|
25
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { createContentModule, ContentModuleOptions } from '@wikex/content-kit';
|
|
2
|
+
import { b as VisualEditorRoute, B as BlockPickerOption } from './runtimeConfig-BwjQepcW.js';
|
|
3
|
+
import { defineWikexProject } from './project.js';
|
|
4
|
+
|
|
5
|
+
type WikexStarterBrand = {
|
|
6
|
+
description: string;
|
|
7
|
+
logo: {
|
|
8
|
+
height: number;
|
|
9
|
+
url: string;
|
|
10
|
+
width: number;
|
|
11
|
+
};
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
type WikexStarterOptions = {
|
|
15
|
+
brand: WikexStarterBrand;
|
|
16
|
+
content: ContentModuleOptions;
|
|
17
|
+
globals?: Readonly<Record<string, 'content' | 'footer' | 'header'>>;
|
|
18
|
+
id: string;
|
|
19
|
+
modules?: readonly string[];
|
|
20
|
+
provider: string;
|
|
21
|
+
};
|
|
22
|
+
type WikexStarter = {
|
|
23
|
+
collections: ReturnType<typeof createContentModule>['collections'];
|
|
24
|
+
getVisualEditorRoute: (pathname: string) => VisualEditorRoute | null;
|
|
25
|
+
livePreview: {
|
|
26
|
+
brand: WikexStarterBrand;
|
|
27
|
+
pageBlocks: readonly BlockPickerOption[];
|
|
28
|
+
postBlocks: readonly BlockPickerOption[];
|
|
29
|
+
};
|
|
30
|
+
plugins: ReturnType<typeof createContentModule>['plugins'];
|
|
31
|
+
project: ReturnType<typeof defineWikexProject>;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* One factory for the conventional Wikex Payload setup. The consuming project still owns
|
|
35
|
+
* its visual block components and frontend renderer, but no longer has to wire plugins,
|
|
36
|
+
* content schema, branding and preview routing independently.
|
|
37
|
+
*/
|
|
38
|
+
declare const createWikexStarter: (options: WikexStarterOptions) => WikexStarter;
|
|
39
|
+
|
|
40
|
+
export { type WikexStarter, type WikexStarterBrand, type WikexStarterOptions, createWikexStarter };
|
package/dist/starter.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {
|
|
2
|
+
adminExperiencePlugin,
|
|
3
|
+
wikexAdminPlugin
|
|
4
|
+
} from "./chunk-7FEACJUN.js";
|
|
5
|
+
import {
|
|
6
|
+
createVisualEditorRouteResolver,
|
|
7
|
+
defineWikexProject
|
|
8
|
+
} from "./chunk-JJLHSZ3T.js";
|
|
9
|
+
|
|
10
|
+
// src/starter.ts
|
|
11
|
+
import { createContentModule } from "@wikex/content-kit";
|
|
12
|
+
var getLabel = (block) => {
|
|
13
|
+
if (typeof block.labels === "object" && block.labels && "singular" in block.labels) {
|
|
14
|
+
const singular = block.labels.singular;
|
|
15
|
+
if (typeof singular === "string") return singular;
|
|
16
|
+
}
|
|
17
|
+
return block.slug;
|
|
18
|
+
};
|
|
19
|
+
var isStarterBlock = (block) => typeof block === "object" && block !== null && "slug" in block && typeof block.slug === "string";
|
|
20
|
+
var toBlockPickerOptions = (blocks) => {
|
|
21
|
+
if (!Array.isArray(blocks)) return [];
|
|
22
|
+
return blocks.filter(isStarterBlock).map((block) => {
|
|
23
|
+
const label = getLabel(block);
|
|
24
|
+
return { description: label, label, payloadLabel: label, slug: block.slug };
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
var createWikexStarter = (options) => {
|
|
28
|
+
const seo = options.content.seo === void 0 ? { siteName: options.brand.name } : options.content.seo;
|
|
29
|
+
const content = createContentModule({ ...options.content, seo });
|
|
30
|
+
const collections = [content.pageSlug, content.postSlug].filter(
|
|
31
|
+
(slug) => Boolean(slug)
|
|
32
|
+
);
|
|
33
|
+
const getVisualEditorRoute = createVisualEditorRouteResolver({
|
|
34
|
+
collections,
|
|
35
|
+
globals: options.globals
|
|
36
|
+
});
|
|
37
|
+
const project = defineWikexProject({
|
|
38
|
+
brand: options.brand,
|
|
39
|
+
id: options.id,
|
|
40
|
+
modules: options.modules ?? ["website", "blog"]
|
|
41
|
+
});
|
|
42
|
+
const pageBlocks = toBlockPickerOptions(
|
|
43
|
+
options.content.page === false ? void 0 : options.content.page?.blocks
|
|
44
|
+
);
|
|
45
|
+
const postBlocks = toBlockPickerOptions(
|
|
46
|
+
options.content.post === false ? void 0 : options.content.post?.blocks
|
|
47
|
+
);
|
|
48
|
+
return {
|
|
49
|
+
collections: content.collections,
|
|
50
|
+
getVisualEditorRoute,
|
|
51
|
+
livePreview: { brand: options.brand, pageBlocks, postBlocks },
|
|
52
|
+
plugins: [
|
|
53
|
+
adminExperiencePlugin,
|
|
54
|
+
...content.plugins,
|
|
55
|
+
wikexAdminPlugin({ components: { provider: options.provider } })
|
|
56
|
+
],
|
|
57
|
+
project
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
export {
|
|
61
|
+
createWikexStarter
|
|
62
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
declare const TEXT_FONT_OPTIONS: readonly [{
|
|
2
|
+
readonly css: "";
|
|
3
|
+
readonly label: "Mặc định";
|
|
4
|
+
readonly value: "default";
|
|
5
|
+
}, {
|
|
6
|
+
readonly css: "var(--font-manrope), sans-serif";
|
|
7
|
+
readonly label: "Manrope";
|
|
8
|
+
readonly value: "manrope";
|
|
9
|
+
}, {
|
|
10
|
+
readonly css: "var(--font-inter), sans-serif";
|
|
11
|
+
readonly label: "Inter";
|
|
12
|
+
readonly value: "inter";
|
|
13
|
+
}, {
|
|
14
|
+
readonly css: "var(--font-roboto), sans-serif";
|
|
15
|
+
readonly label: "Roboto";
|
|
16
|
+
readonly value: "roboto";
|
|
17
|
+
}, {
|
|
18
|
+
readonly css: "var(--font-montserrat), sans-serif";
|
|
19
|
+
readonly label: "Montserrat";
|
|
20
|
+
readonly value: "montserrat";
|
|
21
|
+
}, {
|
|
22
|
+
readonly css: "var(--font-lora), serif";
|
|
23
|
+
readonly label: "Lora";
|
|
24
|
+
readonly value: "lora";
|
|
25
|
+
}, {
|
|
26
|
+
readonly css: "var(--font-playfair-display), serif";
|
|
27
|
+
readonly label: "Playfair Display";
|
|
28
|
+
readonly value: "playfair-display";
|
|
29
|
+
}];
|
|
30
|
+
declare const TEXT_LINE_HEIGHT_OPTIONS: readonly [{
|
|
31
|
+
readonly css: "";
|
|
32
|
+
readonly label: "Mặc định";
|
|
33
|
+
readonly value: "default";
|
|
34
|
+
}, {
|
|
35
|
+
readonly css: "0.9";
|
|
36
|
+
readonly label: "Rất chặt · 0.9";
|
|
37
|
+
readonly value: "0.9";
|
|
38
|
+
}, {
|
|
39
|
+
readonly css: "1";
|
|
40
|
+
readonly label: "Chặt · 1.0";
|
|
41
|
+
readonly value: "1";
|
|
42
|
+
}, {
|
|
43
|
+
readonly css: "1.15";
|
|
44
|
+
readonly label: "Gọn · 1.15";
|
|
45
|
+
readonly value: "1.15";
|
|
46
|
+
}, {
|
|
47
|
+
readonly css: "1.35";
|
|
48
|
+
readonly label: "Tiêu chuẩn · 1.35";
|
|
49
|
+
readonly value: "1.35";
|
|
50
|
+
}, {
|
|
51
|
+
readonly css: "1.5";
|
|
52
|
+
readonly label: "Thoáng · 1.5";
|
|
53
|
+
readonly value: "1.5";
|
|
54
|
+
}, {
|
|
55
|
+
readonly css: "1.7";
|
|
56
|
+
readonly label: "Rộng · 1.7";
|
|
57
|
+
readonly value: "1.7";
|
|
58
|
+
}];
|
|
59
|
+
type TextFontFamily = (typeof TEXT_FONT_OPTIONS)[number]['value'];
|
|
60
|
+
type TextLineHeight = (typeof TEXT_LINE_HEIGHT_OPTIONS)[number]['value'];
|
|
61
|
+
type TextStyleValue = {
|
|
62
|
+
fontFamily?: TextFontFamily;
|
|
63
|
+
lineHeight?: TextLineHeight;
|
|
64
|
+
/** Percentage of the containing block, written by the canvas resize handles. */
|
|
65
|
+
width?: number;
|
|
66
|
+
/** Percentage offset from the containing block's left content edge. */
|
|
67
|
+
widthOffset?: number;
|
|
68
|
+
};
|
|
69
|
+
type TextStyleMap = Record<string, TextStyleValue>;
|
|
70
|
+
declare const EDITABLE_INTERACTIVE_SELECTOR: string;
|
|
71
|
+
declare const EDITABLE_PREVIEW_SELECTOR: string;
|
|
72
|
+
declare const isSyntheticElementStyleKey: (value: string) => boolean;
|
|
73
|
+
declare const getEditableElementStyleKey: (element: HTMLElement) => string;
|
|
74
|
+
declare const normalizeTextStyleValue: (value: unknown) => TextStyleValue;
|
|
75
|
+
declare const normalizeTextStyleMap: (value: unknown) => TextStyleMap;
|
|
76
|
+
declare const getTextStyleCSS: (value: TextStyleValue) => {
|
|
77
|
+
boxSizing?: "border-box";
|
|
78
|
+
fontFamily?: string;
|
|
79
|
+
lineHeight?: string;
|
|
80
|
+
marginLeft?: string;
|
|
81
|
+
marginRight?: string;
|
|
82
|
+
maxWidth?: string;
|
|
83
|
+
width?: string;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export { EDITABLE_INTERACTIVE_SELECTOR, EDITABLE_PREVIEW_SELECTOR, TEXT_FONT_OPTIONS, TEXT_LINE_HEIGHT_OPTIONS, type TextFontFamily, type TextLineHeight, type TextStyleMap, type TextStyleValue, getEditableElementStyleKey, getTextStyleCSS, isSyntheticElementStyleKey, normalizeTextStyleMap, normalizeTextStyleValue };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EDITABLE_INTERACTIVE_SELECTOR,
|
|
3
|
+
EDITABLE_PREVIEW_SELECTOR,
|
|
4
|
+
TEXT_FONT_OPTIONS,
|
|
5
|
+
TEXT_LINE_HEIGHT_OPTIONS,
|
|
6
|
+
getEditableElementStyleKey,
|
|
7
|
+
getTextStyleCSS,
|
|
8
|
+
isSyntheticElementStyleKey,
|
|
9
|
+
normalizeTextStyleMap,
|
|
10
|
+
normalizeTextStyleValue
|
|
11
|
+
} from "./chunk-BUD6BMFV.js";
|
|
12
|
+
export {
|
|
13
|
+
EDITABLE_INTERACTIVE_SELECTOR,
|
|
14
|
+
EDITABLE_PREVIEW_SELECTOR,
|
|
15
|
+
TEXT_FONT_OPTIONS,
|
|
16
|
+
TEXT_LINE_HEIGHT_OPTIONS,
|
|
17
|
+
getEditableElementStyleKey,
|
|
18
|
+
getTextStyleCSS,
|
|
19
|
+
isSyntheticElementStyleKey,
|
|
20
|
+
normalizeTextStyleMap,
|
|
21
|
+
normalizeTextStyleValue
|
|
22
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wikex/admin-kit",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Reusable Payload CMS admin shell, visual editor and typography tools for Wikex projects",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"**/*.scss"
|
|
10
10
|
],
|
|
11
11
|
"files": [
|
|
12
|
-
"
|
|
12
|
+
"dist",
|
|
13
|
+
"src/styles",
|
|
13
14
|
"CHANGELOG.md",
|
|
14
15
|
"README.md",
|
|
15
16
|
"RELEASING.md"
|
|
@@ -19,26 +20,26 @@
|
|
|
19
20
|
"registry": "https://registry.npmjs.org/"
|
|
20
21
|
},
|
|
21
22
|
"dependencies": {
|
|
22
|
-
"@wikex/content-kit": "^0.1.
|
|
23
|
+
"@wikex/content-kit": "^0.1.1"
|
|
23
24
|
},
|
|
24
25
|
"exports": {
|
|
25
|
-
".": "./
|
|
26
|
-
"./admin/before-login": "./
|
|
27
|
-
"./admin/brand": "./
|
|
28
|
-
"./admin/header": "./
|
|
29
|
-
"./admin/logout-button": "./
|
|
30
|
-
"./admin/nav": "./
|
|
31
|
-
"./admin/theme-toggle": "./
|
|
32
|
-
"./admin/view-site": "./
|
|
33
|
-
"./live-preview": "./
|
|
34
|
-
"./project": "./
|
|
35
|
-
"./rich-text": "./
|
|
36
|
-
"./rich-text/client": "./
|
|
37
|
-
"./starter": "./
|
|
38
|
-
"./starter/client": "./
|
|
26
|
+
".": "./dist/index.js",
|
|
27
|
+
"./admin/before-login": "./dist/admin/before-login.js",
|
|
28
|
+
"./admin/brand": "./dist/admin/brand.js",
|
|
29
|
+
"./admin/header": "./dist/admin/header.js",
|
|
30
|
+
"./admin/logout-button": "./dist/admin/logout-button.js",
|
|
31
|
+
"./admin/nav": "./dist/admin/nav.js",
|
|
32
|
+
"./admin/theme-toggle": "./dist/admin/theme-toggle.js",
|
|
33
|
+
"./admin/view-site": "./dist/admin/view-site.js",
|
|
34
|
+
"./live-preview": "./dist/live-preview.js",
|
|
35
|
+
"./project": "./dist/project.js",
|
|
36
|
+
"./rich-text": "./dist/rich-text.js",
|
|
37
|
+
"./rich-text/client": "./dist/rich-text-client.js",
|
|
38
|
+
"./starter": "./dist/starter.js",
|
|
39
|
+
"./starter/client": "./dist/starter-client.js",
|
|
39
40
|
"./styles": "./src/styles/admin.scss",
|
|
40
|
-
"./text-style-runtime": "./
|
|
41
|
-
"./text-styles": "./
|
|
41
|
+
"./text-style-runtime": "./dist/text-style-runtime.js",
|
|
42
|
+
"./text-styles": "./dist/text-styles.js"
|
|
42
43
|
},
|
|
43
44
|
"peerDependencies": {
|
|
44
45
|
"@lexical/react": ">=0.41.0",
|
|
@@ -51,5 +52,8 @@
|
|
|
51
52
|
"payload": ">=3.88.0",
|
|
52
53
|
"react": ">=19.0.0",
|
|
53
54
|
"react-dom": ">=19.0.0"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup"
|
|
54
58
|
}
|
|
55
59
|
}
|
package/src/TextStyleRuntime.tsx
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { useEffect } from 'react'
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
EDITABLE_PREVIEW_SELECTOR,
|
|
7
|
-
getEditableElementStyleKey,
|
|
8
|
-
getTextStyleCSS,
|
|
9
|
-
normalizeTextStyleMap,
|
|
10
|
-
} from './textStyles'
|
|
11
|
-
|
|
12
|
-
type OriginalStyle = {
|
|
13
|
-
boxSizing: string
|
|
14
|
-
fontFamily: string
|
|
15
|
-
lineHeight: string
|
|
16
|
-
marginLeft: string
|
|
17
|
-
marginRight: string
|
|
18
|
-
maxWidth: string
|
|
19
|
-
width: string
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const TextStyleRuntime = ({ styles }: { styles?: unknown }) => {
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
const normalizedStyles = normalizeTextStyleMap(styles)
|
|
25
|
-
const originals = new Map<HTMLElement, OriginalStyle>()
|
|
26
|
-
let applyFrame = 0
|
|
27
|
-
|
|
28
|
-
const applyStyles = () => {
|
|
29
|
-
const fields = new Set(
|
|
30
|
-
document.querySelectorAll<HTMLElement>(`[data-wikex-field],${EDITABLE_PREVIEW_SELECTOR}`),
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
for (const element of fields) {
|
|
34
|
-
const fieldPath = element.dataset.wikexField || getEditableElementStyleKey(element)
|
|
35
|
-
if (!fieldPath || !normalizedStyles[fieldPath]) continue
|
|
36
|
-
|
|
37
|
-
if (!originals.has(element)) {
|
|
38
|
-
originals.set(element, {
|
|
39
|
-
boxSizing: element.style.boxSizing,
|
|
40
|
-
fontFamily: element.style.fontFamily,
|
|
41
|
-
lineHeight: element.style.lineHeight,
|
|
42
|
-
marginLeft: element.style.marginLeft,
|
|
43
|
-
marginRight: element.style.marginRight,
|
|
44
|
-
maxWidth: element.style.maxWidth,
|
|
45
|
-
width: element.style.width,
|
|
46
|
-
})
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const style = getTextStyleCSS(normalizedStyles[fieldPath])
|
|
50
|
-
element.style.boxSizing = style.boxSizing || ''
|
|
51
|
-
element.style.fontFamily = style.fontFamily || ''
|
|
52
|
-
element.style.lineHeight = style.lineHeight || ''
|
|
53
|
-
element.style.marginLeft = style.marginLeft || ''
|
|
54
|
-
element.style.marginRight = style.marginRight || ''
|
|
55
|
-
element.style.maxWidth = style.maxWidth || ''
|
|
56
|
-
element.style.width = style.width || ''
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const scheduleApplyStyles = () => {
|
|
61
|
-
if (applyFrame) return
|
|
62
|
-
|
|
63
|
-
applyFrame = window.requestAnimationFrame(() => {
|
|
64
|
-
applyFrame = 0
|
|
65
|
-
applyStyles()
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
applyStyles()
|
|
70
|
-
const observer = new MutationObserver(scheduleApplyStyles)
|
|
71
|
-
observer.observe(document.body, { childList: true, subtree: true })
|
|
72
|
-
|
|
73
|
-
return () => {
|
|
74
|
-
observer.disconnect()
|
|
75
|
-
window.cancelAnimationFrame(applyFrame)
|
|
76
|
-
for (const [element, original] of originals) {
|
|
77
|
-
if (!element.isConnected) continue
|
|
78
|
-
element.style.boxSizing = original.boxSizing
|
|
79
|
-
element.style.fontFamily = original.fontFamily
|
|
80
|
-
element.style.lineHeight = original.lineHeight
|
|
81
|
-
element.style.marginLeft = original.marginLeft
|
|
82
|
-
element.style.marginRight = original.marginRight
|
|
83
|
-
element.style.maxWidth = original.maxWidth
|
|
84
|
-
element.style.width = original.width
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}, [styles])
|
|
88
|
-
|
|
89
|
-
return null
|
|
90
|
-
}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import React from 'react'
|
|
4
|
-
|
|
5
|
-
import { useAdminBrand } from './useAdminBrand'
|
|
6
|
-
|
|
7
|
-
const BeforeLogin: React.FC = () => {
|
|
8
|
-
const { siteName } = useAdminBrand()
|
|
9
|
-
|
|
10
|
-
return (
|
|
11
|
-
<div className="admin-login-intro">
|
|
12
|
-
<span className="admin-login-intro__eyebrow">{siteName} · Trung tâm nội dung</span>
|
|
13
|
-
<h1>Chào mừng trở lại.</h1>
|
|
14
|
-
<p>Đăng nhập để quản lý nội dung, hình ảnh và xuất bản của {siteName}.</p>
|
|
15
|
-
</div>
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default BeforeLogin
|
package/src/admin/Brand.tsx
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import Image from 'next/image'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
|
|
6
|
-
import { useAdminBrand } from './useAdminBrand'
|
|
7
|
-
|
|
8
|
-
export type AdminBrandAsset = {
|
|
9
|
-
alt: string
|
|
10
|
-
height: number
|
|
11
|
-
url: string
|
|
12
|
-
width: number
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const BrandLogo = ({
|
|
16
|
-
asset,
|
|
17
|
-
className,
|
|
18
|
-
height,
|
|
19
|
-
maxWidth,
|
|
20
|
-
}: {
|
|
21
|
-
asset: AdminBrandAsset
|
|
22
|
-
className?: string
|
|
23
|
-
height: number
|
|
24
|
-
maxWidth: number
|
|
25
|
-
siteName: string
|
|
26
|
-
}) => (
|
|
27
|
-
<span
|
|
28
|
-
className={['brand-logo', className].filter(Boolean).join(' ')}
|
|
29
|
-
style={{ alignItems: 'center', display: 'inline-flex', height, maxWidth }}
|
|
30
|
-
>
|
|
31
|
-
<Image
|
|
32
|
-
alt=""
|
|
33
|
-
height={asset.height}
|
|
34
|
-
src={asset.url}
|
|
35
|
-
style={{ height: '100%', maxWidth: '100%', objectFit: 'contain', width: 'auto' }}
|
|
36
|
-
unoptimized
|
|
37
|
-
width={asset.width}
|
|
38
|
-
/>
|
|
39
|
-
</span>
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
export const AdminIcon: React.FC = () => {
|
|
43
|
-
const brand = useAdminBrand()
|
|
44
|
-
|
|
45
|
-
return (
|
|
46
|
-
<span className="aurea-brand aurea-brand--icon">
|
|
47
|
-
<BrandLogo
|
|
48
|
-
asset={brand.logo}
|
|
49
|
-
className="aurea-brand__image"
|
|
50
|
-
height={32}
|
|
51
|
-
maxWidth={32}
|
|
52
|
-
siteName={brand.siteName}
|
|
53
|
-
/>
|
|
54
|
-
</span>
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export const AdminLogo: React.FC = () => {
|
|
59
|
-
const brand = useAdminBrand()
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<span aria-label={brand.siteName} className="aurea-brand aurea-brand--logo" role="img">
|
|
63
|
-
<BrandLogo
|
|
64
|
-
asset={brand.logo}
|
|
65
|
-
className="aurea-brand__image"
|
|
66
|
-
height={42}
|
|
67
|
-
maxWidth={190}
|
|
68
|
-
siteName={brand.siteName}
|
|
69
|
-
/>
|
|
70
|
-
</span>
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export { configureAdminBrand, useAdminBrand, type AdminBrandSettings } from './useAdminBrand'
|
package/src/admin/Header.tsx
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Link, useAuth, useConfig, useNav } from '@payloadcms/ui'
|
|
4
|
-
import { Menu, Settings2 } from 'lucide-react'
|
|
5
|
-
import { formatAdminURL } from 'payload/shared'
|
|
6
|
-
import React from 'react'
|
|
7
|
-
|
|
8
|
-
import { AdminIcon } from './Brand'
|
|
9
|
-
import AdminThemeToggle from './ThemeToggle'
|
|
10
|
-
import AdminViewSite from './ViewSite'
|
|
11
|
-
|
|
12
|
-
type AdminUser = {
|
|
13
|
-
email?: string
|
|
14
|
-
name?: string
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const getInitials = (name?: string, email?: string) => {
|
|
18
|
-
const source = name?.trim() || email?.split('@')[0] || 'AD'
|
|
19
|
-
|
|
20
|
-
return source
|
|
21
|
-
.split(/\s+/)
|
|
22
|
-
.slice(0, 2)
|
|
23
|
-
.map((part) => part.charAt(0).toUpperCase())
|
|
24
|
-
.join('')
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const AdminHeader = () => {
|
|
28
|
-
const { user } = useAuth<AdminUser>()
|
|
29
|
-
const { setNavOpen } = useNav()
|
|
30
|
-
const {
|
|
31
|
-
config: {
|
|
32
|
-
admin: { routes: adminRoutes },
|
|
33
|
-
routes: { admin: adminRoute },
|
|
34
|
-
},
|
|
35
|
-
} = useConfig()
|
|
36
|
-
|
|
37
|
-
const userLabel = user?.name?.trim() || user?.email?.split('@')[0] || 'Quản trị viên'
|
|
38
|
-
const initials = getInitials(user?.name, user?.email)
|
|
39
|
-
|
|
40
|
-
return (
|
|
41
|
-
<header className="minimal-admin-header">
|
|
42
|
-
<div className="minimal-admin-header__left">
|
|
43
|
-
<button
|
|
44
|
-
aria-label="Mở menu quản trị"
|
|
45
|
-
className="minimal-admin-header__menu"
|
|
46
|
-
onClick={() => setNavOpen(true)}
|
|
47
|
-
type="button"
|
|
48
|
-
>
|
|
49
|
-
<Menu aria-hidden="true" />
|
|
50
|
-
</button>
|
|
51
|
-
<Link
|
|
52
|
-
aria-label="Về dashboard"
|
|
53
|
-
className="minimal-admin-header__mobile-brand"
|
|
54
|
-
href={adminRoute}
|
|
55
|
-
prefetch={false}
|
|
56
|
-
>
|
|
57
|
-
<AdminIcon />
|
|
58
|
-
</Link>
|
|
59
|
-
</div>
|
|
60
|
-
|
|
61
|
-
<div className="minimal-admin-header__actions">
|
|
62
|
-
<AdminViewSite />
|
|
63
|
-
<AdminThemeToggle />
|
|
64
|
-
<Link
|
|
65
|
-
aria-label={`Mở tài khoản ${userLabel}`}
|
|
66
|
-
className="minimal-admin-header__settings"
|
|
67
|
-
href={formatAdminURL({ adminRoute, path: adminRoutes.account })}
|
|
68
|
-
prefetch={false}
|
|
69
|
-
title="Cài đặt tài khoản"
|
|
70
|
-
>
|
|
71
|
-
<Settings2 aria-hidden="true" />
|
|
72
|
-
</Link>
|
|
73
|
-
<Link
|
|
74
|
-
aria-label={`Mở tài khoản ${userLabel}`}
|
|
75
|
-
className="minimal-admin-header__account"
|
|
76
|
-
href={formatAdminURL({ adminRoute, path: adminRoutes.account })}
|
|
77
|
-
prefetch={false}
|
|
78
|
-
title={userLabel}
|
|
79
|
-
>
|
|
80
|
-
<span>{initials}</span>
|
|
81
|
-
</Link>
|
|
82
|
-
</div>
|
|
83
|
-
</header>
|
|
84
|
-
)
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export default AdminHeader
|