@nuskin/nextgen-header 1.0.0-library-setup.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/package-dist/index.css +71 -0
- package/package-dist/index.css.map +1 -0
- package/package-dist/index.d.ts +51 -0
- package/package-dist/index.js +285 -0
- package/package-dist/index.js.map +1 -0
- package/package-dist/index.mjs +253 -0
- package/package-dist/index.mjs.map +1 -0
- package/package.json +132 -0
- package/readme.md +114 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/* src/styles/globals.css */
|
|
2
|
+
* {
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
body {
|
|
8
|
+
font-family:
|
|
9
|
+
-apple-system,
|
|
10
|
+
BlinkMacSystemFont,
|
|
11
|
+
"Segoe UI",
|
|
12
|
+
"Roboto",
|
|
13
|
+
"Oxygen",
|
|
14
|
+
"Ubuntu",
|
|
15
|
+
"Cantarell",
|
|
16
|
+
"Fira Sans",
|
|
17
|
+
"Droid Sans",
|
|
18
|
+
"Helvetica Neue",
|
|
19
|
+
sans-serif;
|
|
20
|
+
-webkit-font-smoothing: antialiased;
|
|
21
|
+
-moz-osx-font-smoothing: grayscale;
|
|
22
|
+
line-height: 1.6;
|
|
23
|
+
color: #333;
|
|
24
|
+
}
|
|
25
|
+
.container {
|
|
26
|
+
max-width: 1200px;
|
|
27
|
+
margin: 0 auto;
|
|
28
|
+
padding: 0 10px;
|
|
29
|
+
}
|
|
30
|
+
h1,
|
|
31
|
+
h2,
|
|
32
|
+
h3,
|
|
33
|
+
h4,
|
|
34
|
+
h5,
|
|
35
|
+
h6 {
|
|
36
|
+
font-weight: 600;
|
|
37
|
+
line-height: 1.2;
|
|
38
|
+
margin-bottom: 1rem;
|
|
39
|
+
}
|
|
40
|
+
p {
|
|
41
|
+
margin-bottom: 1rem;
|
|
42
|
+
}
|
|
43
|
+
button {
|
|
44
|
+
font-family: inherit;
|
|
45
|
+
cursor: pointer;
|
|
46
|
+
border: none;
|
|
47
|
+
outline: none;
|
|
48
|
+
}
|
|
49
|
+
a {
|
|
50
|
+
color: #008ab0;
|
|
51
|
+
text-decoration: none;
|
|
52
|
+
}
|
|
53
|
+
a:link {
|
|
54
|
+
color: #008ab0;
|
|
55
|
+
}
|
|
56
|
+
a:visited {
|
|
57
|
+
color: #008ab0;
|
|
58
|
+
}
|
|
59
|
+
a:hover {
|
|
60
|
+
text-decoration: underline;
|
|
61
|
+
}
|
|
62
|
+
img {
|
|
63
|
+
max-width: 100%;
|
|
64
|
+
height: auto;
|
|
65
|
+
}
|
|
66
|
+
@media (max-width: 768px) {
|
|
67
|
+
.container {
|
|
68
|
+
padding: 0 10px;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/styles/globals.css"],"sourcesContent":["/* Global styles */\n* {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',\n 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n line-height: 1.6;\n color: #333;\n}\n\n.container {\n max-width: 1200px;\n margin: 0 auto;\n padding: 0 10px;\n}\n\n/* Typography */\nh1, h2, h3, h4, h5, h6 {\n font-weight: 600;\n line-height: 1.2;\n margin-bottom: 1rem;\n}\n\np {\n margin-bottom: 1rem;\n}\n\n/* Buttons */\nbutton {\n font-family: inherit;\n cursor: pointer;\n border: none;\n outline: none;\n}\n\n/* Links */\na {\n color: #008ab0;\n text-decoration: none;\n}\n\na:link {\n color: #008ab0;\n}\n\na:visited {\n color: #008ab0;\n}\n\na:hover {\n text-decoration: underline;\n}\n\n/* Images */\nimg {\n max-width: 100%;\n height: auto;\n}\n\n/* Responsive */\n@media (max-width: 768px) {\n .container {\n padding: 0 10px;\n }\n}"],"mappings":";AACA;AACE,UAAQ;AACR,WAAS;AACT,cAAY;AACd;AAEA;AACE;AAAA,IAAa,aAAa;AAAA,IAAE,kBAAkB;AAAA,IAAE,UAAU;AAAA,IAAE,QAAQ;AAAA,IAAE,QAAQ;AAAA,IAC5E,QAAQ;AAAA,IAAE,WAAW;AAAA,IAAE,WAAW;AAAA,IAAE,YAAY;AAAA,IAAE,gBAAgB;AAAA,IAClE;AACF,0BAAwB;AACxB,2BAAyB;AACzB,eAAa;AACb,SAAO;AACT;AAEA,CAAC;AACC,aAAW;AACX,UAAQ,EAAE;AACV,WAAS,EAAE;AACb;AAGA;AAAI;AAAI;AAAI;AAAI;AAAI;AAClB,eAAa;AACb,eAAa;AACb,iBAAe;AACjB;AAEA;AACE,iBAAe;AACjB;AAGA;AACE,eAAa;AACb,UAAQ;AACR,UAAQ;AACR,WAAS;AACX;AAGA;AACE,SAAO;AACP,mBAAiB;AACnB;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,SAAO;AACT;AAEA,CAAC;AACC,mBAAiB;AACnB;AAGA;AACE,aAAW;AACX,UAAQ;AACV;AAGA,QAAO,WAAY;AACjB,GAnDD;AAoDG,aAAS,EAAE;AACb;AACF;","names":[]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Context, FC } from "react";
|
|
2
|
+
|
|
3
|
+
export const HeaderPlaceholder: FC;
|
|
4
|
+
|
|
5
|
+
export interface MainProps {
|
|
6
|
+
isMFE?: boolean;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const Main: FC<MainProps>;
|
|
10
|
+
|
|
11
|
+
export interface HeaderMFEContextValue {
|
|
12
|
+
isMFE: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const HeaderMFEContext: Context<HeaderMFEContextValue>;
|
|
16
|
+
|
|
17
|
+
export function getLocale(options?: { url?: string }): {
|
|
18
|
+
locale: string;
|
|
19
|
+
language: string;
|
|
20
|
+
country: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export function getStackConfig(): {
|
|
24
|
+
contentType: string;
|
|
25
|
+
locale: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const stack: unknown;
|
|
29
|
+
|
|
30
|
+
export function getContent(
|
|
31
|
+
args?: {
|
|
32
|
+
url?: string;
|
|
33
|
+
uid?: string;
|
|
34
|
+
contentType?: string;
|
|
35
|
+
language?: string;
|
|
36
|
+
referenceFields?: string[];
|
|
37
|
+
},
|
|
38
|
+
): Promise<unknown | null>;
|
|
39
|
+
|
|
40
|
+
export function initLivePreview(): void;
|
|
41
|
+
|
|
42
|
+
export const onEntryChange: (...args: unknown[]) => unknown;
|
|
43
|
+
|
|
44
|
+
export function isEditingMode(): boolean;
|
|
45
|
+
|
|
46
|
+
export const CONTENTSTACK_API_KEY: string | undefined;
|
|
47
|
+
export const CONTENTSTACK_DELIVERY_TOKEN: string | undefined;
|
|
48
|
+
export const CONTENTSTACK_ENVIRONMENT: string | undefined;
|
|
49
|
+
export const CONTENTSTACK_PREVIEW_TOKEN: string | undefined;
|
|
50
|
+
export const referenceFields: string[];
|
|
51
|
+
export const VB_EmptyBlockParentClass: string;
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/library/index.js
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
CONTENTSTACK_API_KEY: () => CONTENTSTACK_API_KEY,
|
|
33
|
+
CONTENTSTACK_DELIVERY_TOKEN: () => CONTENTSTACK_DELIVERY_TOKEN,
|
|
34
|
+
CONTENTSTACK_ENVIRONMENT: () => CONTENTSTACK_ENVIRONMENT,
|
|
35
|
+
CONTENTSTACK_PREVIEW_TOKEN: () => CONTENTSTACK_PREVIEW_TOKEN,
|
|
36
|
+
HeaderMFEContext: () => HeaderMFEContext,
|
|
37
|
+
HeaderPlaceholder: () => HeaderPlaceholder,
|
|
38
|
+
Main: () => Main_default,
|
|
39
|
+
VB_EmptyBlockParentClass: () => VB_EmptyBlockParentClass,
|
|
40
|
+
getContent: () => getContent,
|
|
41
|
+
getLocale: () => getLocale,
|
|
42
|
+
getStackConfig: () => getStackConfig,
|
|
43
|
+
initLivePreview: () => initLivePreview,
|
|
44
|
+
isEditingMode: () => isEditingMode,
|
|
45
|
+
onEntryChange: () => onEntryChange,
|
|
46
|
+
referenceFields: () => referenceFields,
|
|
47
|
+
stack: () => stack
|
|
48
|
+
});
|
|
49
|
+
module.exports = __toCommonJS(index_exports);
|
|
50
|
+
|
|
51
|
+
// src/components/HeaderPlaceholder.jsx
|
|
52
|
+
var import_react = __toESM(require("react"));
|
|
53
|
+
function HeaderPlaceholder() {
|
|
54
|
+
return /* @__PURE__ */ import_react.default.createElement("header", { role: "banner", "data-testid": "header-placeholder" }, /* @__PURE__ */ import_react.default.createElement("p", null, "Header MFE \u2014 TODO: implement header content"));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/Main.js
|
|
58
|
+
var import_react2 = __toESM(require("react"));
|
|
59
|
+
var import_prop_types = __toESM(require("prop-types"));
|
|
60
|
+
var import_react_router_dom = require("react-router-dom");
|
|
61
|
+
|
|
62
|
+
// src/styles/Main.styled.js
|
|
63
|
+
var import_styled = __toESM(require("@emotion/styled"));
|
|
64
|
+
var AppContainer = import_styled.default.div`
|
|
65
|
+
font-family: "Inter", sans-serif;
|
|
66
|
+
`;
|
|
67
|
+
|
|
68
|
+
// src/utils/locale.js
|
|
69
|
+
function getLocaleCodeFromUrl(options) {
|
|
70
|
+
var _a, _b;
|
|
71
|
+
const { url = "", defaultLocale = "" } = options ?? {};
|
|
72
|
+
let localeAsArr = [];
|
|
73
|
+
let tempUrl = url || typeof location != "undefined" && location.href;
|
|
74
|
+
if (tempUrl) {
|
|
75
|
+
if (!(tempUrl == null ? void 0 : tempUrl.includes("https://")) && !(tempUrl == null ? void 0 : tempUrl.includes("http://"))) {
|
|
76
|
+
tempUrl = `https://domain.com${tempUrl}`;
|
|
77
|
+
}
|
|
78
|
+
const updatedUrl = new URL(tempUrl);
|
|
79
|
+
const pathParams = updatedUrl.pathname;
|
|
80
|
+
if (pathParams) {
|
|
81
|
+
const pathList = (_a = pathParams == null ? void 0 : pathParams.split("/")) == null ? void 0 : _a.filter(Boolean);
|
|
82
|
+
if (pathList.length > 1) {
|
|
83
|
+
localeAsArr = pathList;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (localeAsArr.length > 2) {
|
|
87
|
+
localeAsArr = localeAsArr.slice(0, 2);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
localeAsArr = localeAsArr.reverse();
|
|
91
|
+
if (localeAsArr.length === 0) {
|
|
92
|
+
localeAsArr = defaultLocale.split("_");
|
|
93
|
+
}
|
|
94
|
+
return `${(_b = localeAsArr[1]) == null ? void 0 : _b.toUpperCase()}-${localeAsArr[0]}`;
|
|
95
|
+
}
|
|
96
|
+
function getLocale({ url } = {}) {
|
|
97
|
+
var _a, _b;
|
|
98
|
+
const currentLocale = getLocaleCodeFromUrl(url ? { url } : null);
|
|
99
|
+
const splitLocale = currentLocale == null ? void 0 : currentLocale.split("-");
|
|
100
|
+
return {
|
|
101
|
+
locale: currentLocale,
|
|
102
|
+
language: (_a = splitLocale == null ? void 0 : splitLocale[1]) == null ? void 0 : _a.toLowerCase(),
|
|
103
|
+
country: (_b = splitLocale == null ? void 0 : splitLocale[0]) == null ? void 0 : _b.toUpperCase()
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// src/Main.js
|
|
108
|
+
var HeaderMFEContext = (0, import_react2.createContext)({ isMFE: true });
|
|
109
|
+
function Main({ isMFE = true }) {
|
|
110
|
+
let { country, language } = getLocale();
|
|
111
|
+
country = country.toLocaleLowerCase();
|
|
112
|
+
language = language.toLocaleLowerCase();
|
|
113
|
+
const baseName = isMFE ? `/${country}/${language}` : `/${country}/${language}/static/header-mfe`;
|
|
114
|
+
return /* @__PURE__ */ import_react2.default.createElement(HeaderMFEContext.Provider, { value: { isMFE } }, /* @__PURE__ */ import_react2.default.createElement(import_react_router_dom.BrowserRouter, { basename: baseName }, /* @__PURE__ */ import_react2.default.createElement(AppContainer, null, /* @__PURE__ */ import_react2.default.createElement(import_react_router_dom.Routes, null, /* @__PURE__ */ import_react2.default.createElement(import_react_router_dom.Route, { path: "*", element: /* @__PURE__ */ import_react2.default.createElement(HeaderPlaceholder, null) })))));
|
|
115
|
+
}
|
|
116
|
+
Main.propTypes = {
|
|
117
|
+
isMFE: import_prop_types.default.bool
|
|
118
|
+
};
|
|
119
|
+
var Main_default = Main;
|
|
120
|
+
|
|
121
|
+
// src/utils/config.js
|
|
122
|
+
function getStackConfig() {
|
|
123
|
+
const { locale } = getLocale();
|
|
124
|
+
return {
|
|
125
|
+
contentType: process.env.CONTENTSTACK_HEADER_CONTENT_TYPE || "",
|
|
126
|
+
locale
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/utils/contentstack.js
|
|
131
|
+
var import_delivery_sdk = __toESM(require("@contentstack/delivery-sdk"));
|
|
132
|
+
var import_live_preview_utils = __toESM(require("@contentstack/live-preview-utils"));
|
|
133
|
+
var import_utils = require("@contentstack/utils");
|
|
134
|
+
|
|
135
|
+
// src/constants.js
|
|
136
|
+
var CONTENTSTACK_API_KEY = process.env.CONTENTSTACK_API_KEY;
|
|
137
|
+
var CONTENTSTACK_DELIVERY_TOKEN = process.env.CONTENTSTACK_DELIVERY_TOKEN;
|
|
138
|
+
var CONTENTSTACK_ENVIRONMENT = process.env.CONTENTSTACK_ENVIRONMENT;
|
|
139
|
+
var CONTENTSTACK_PREVIEW_TOKEN = process.env.CONTENTSTACK_PREVIEW_TOKEN;
|
|
140
|
+
var referenceFields = [];
|
|
141
|
+
var VB_EmptyBlockParentClass = "visual-builder__empty-block-parent";
|
|
142
|
+
|
|
143
|
+
// src/utils/contentstack.js
|
|
144
|
+
var _stack = null;
|
|
145
|
+
function getStack() {
|
|
146
|
+
if (!_stack) {
|
|
147
|
+
_stack = import_delivery_sdk.default.stack({
|
|
148
|
+
apiKey: CONTENTSTACK_API_KEY,
|
|
149
|
+
deliveryToken: CONTENTSTACK_DELIVERY_TOKEN,
|
|
150
|
+
environment: CONTENTSTACK_ENVIRONMENT,
|
|
151
|
+
live_preview: {
|
|
152
|
+
enable: true,
|
|
153
|
+
preview_token: CONTENTSTACK_PREVIEW_TOKEN,
|
|
154
|
+
host: "rest-preview.contentstack.com"
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
return _stack;
|
|
159
|
+
}
|
|
160
|
+
var BRIDGED_CONFIG_KEYS = ["live_preview", "headers", "environment"];
|
|
161
|
+
var stack = new Proxy(
|
|
162
|
+
{},
|
|
163
|
+
{
|
|
164
|
+
get(_, prop) {
|
|
165
|
+
var _a;
|
|
166
|
+
const s = getStack();
|
|
167
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) {
|
|
168
|
+
return (_a = s.config) == null ? void 0 : _a[prop];
|
|
169
|
+
}
|
|
170
|
+
return s[prop];
|
|
171
|
+
},
|
|
172
|
+
set(_, prop, value) {
|
|
173
|
+
const s = getStack();
|
|
174
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) {
|
|
175
|
+
if (!s.config) return false;
|
|
176
|
+
s.config[prop] = value;
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
s[prop] = value;
|
|
180
|
+
return true;
|
|
181
|
+
},
|
|
182
|
+
has(_, prop) {
|
|
183
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) return true;
|
|
184
|
+
return prop in getStack();
|
|
185
|
+
},
|
|
186
|
+
ownKeys() {
|
|
187
|
+
return [
|
|
188
|
+
.../* @__PURE__ */ new Set([...Reflect.ownKeys(getStack()), ...BRIDGED_CONFIG_KEYS])
|
|
189
|
+
];
|
|
190
|
+
},
|
|
191
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
192
|
+
var _a;
|
|
193
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) {
|
|
194
|
+
return {
|
|
195
|
+
configurable: true,
|
|
196
|
+
enumerable: true,
|
|
197
|
+
writable: true,
|
|
198
|
+
value: (_a = getStack().config) == null ? void 0 : _a[prop]
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return Object.getOwnPropertyDescriptor(getStack(), prop);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
var _livePreviewInitialized = false;
|
|
206
|
+
var onEntryChange = import_live_preview_utils.default.onEntryChange.bind(
|
|
207
|
+
import_live_preview_utils.default
|
|
208
|
+
);
|
|
209
|
+
function initLivePreview() {
|
|
210
|
+
if (_livePreviewInitialized) return;
|
|
211
|
+
_livePreviewInitialized = true;
|
|
212
|
+
import_live_preview_utils.default.init({
|
|
213
|
+
ssr: false,
|
|
214
|
+
enable: true,
|
|
215
|
+
mode: "builder",
|
|
216
|
+
stackSdk: stack,
|
|
217
|
+
stackDetails: {
|
|
218
|
+
apiKey: CONTENTSTACK_API_KEY,
|
|
219
|
+
environment: CONTENTSTACK_ENVIRONMENT
|
|
220
|
+
},
|
|
221
|
+
clientUrlParams: {
|
|
222
|
+
host: "app.contentstack.com"
|
|
223
|
+
},
|
|
224
|
+
editButton: {
|
|
225
|
+
enable: false
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
function isEditingMode() {
|
|
230
|
+
if (typeof window === "undefined") {
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
if (window.self !== window.top) {
|
|
234
|
+
return true;
|
|
235
|
+
}
|
|
236
|
+
const params = new URLSearchParams(window.location.search);
|
|
237
|
+
return params.has("visual-builder") || params.has("contentstack") || params.has("live_preview");
|
|
238
|
+
}
|
|
239
|
+
var getContent = async ({
|
|
240
|
+
url,
|
|
241
|
+
uid,
|
|
242
|
+
contentType,
|
|
243
|
+
language,
|
|
244
|
+
referenceFields: referenceFields2 = []
|
|
245
|
+
} = {}) => {
|
|
246
|
+
const tryFetch = async (locale) => {
|
|
247
|
+
var _a;
|
|
248
|
+
const CT = stack.contentType(contentType);
|
|
249
|
+
let fetched = null;
|
|
250
|
+
if (uid) {
|
|
251
|
+
fetched = await CT.entry(uid).locale(locale).includeReference(referenceFields2).fetch();
|
|
252
|
+
} else if (url) {
|
|
253
|
+
const urlWithSlash = url.startsWith("/") ? url : `/${url}`;
|
|
254
|
+
const result = await CT.entry().locale(locale).includeReference(referenceFields2).query({ url: urlWithSlash }).find();
|
|
255
|
+
fetched = (_a = result.entries) == null ? void 0 : _a[0];
|
|
256
|
+
}
|
|
257
|
+
if (isEditingMode() && fetched) {
|
|
258
|
+
(0, import_utils.addEditableTags)(fetched, contentType, true, language, {
|
|
259
|
+
useLowerCaseLocale: false
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return fetched;
|
|
263
|
+
};
|
|
264
|
+
try {
|
|
265
|
+
const result = await tryFetch(language);
|
|
266
|
+
return result;
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.warn(
|
|
269
|
+
"Failed to fetch content with language:",
|
|
270
|
+
language,
|
|
271
|
+
error.message
|
|
272
|
+
);
|
|
273
|
+
try {
|
|
274
|
+
const fallbackResult = await tryFetch("en");
|
|
275
|
+
return fallbackResult;
|
|
276
|
+
} catch (fallbackError) {
|
|
277
|
+
console.warn(
|
|
278
|
+
"Failed to fetch content with fallback language:",
|
|
279
|
+
fallbackError.message
|
|
280
|
+
);
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/library/index.js","../src/components/HeaderPlaceholder.jsx","../src/Main.js","../src/styles/Main.styled.js","../src/utils/locale.js","../src/utils/config.js","../src/utils/contentstack.js","../src/constants.js"],"sourcesContent":["/**\n * Public API for `@nuskin/nextgen-header` npm consumers.\n * Does not include the Module Federation app entry, Express server, or bootstrap.\n */\n\nexport { default as HeaderPlaceholder } from \"../components/HeaderPlaceholder\";\nexport { default as Main, HeaderMFEContext } from \"../Main\";\nexport { getLocale } from \"../utils/locale\";\nexport { getStackConfig } from \"../utils/config\";\nexport {\n stack,\n getContent,\n initLivePreview,\n onEntryChange,\n isEditingMode,\n} from \"../utils/contentstack\";\nexport {\n CONTENTSTACK_API_KEY,\n CONTENTSTACK_DELIVERY_TOKEN,\n CONTENTSTACK_ENVIRONMENT,\n CONTENTSTACK_PREVIEW_TOKEN,\n referenceFields,\n VB_EmptyBlockParentClass,\n} from \"../constants\";\n","import React from \"react\";\n\n/**\n * Stub shell for the future header. Replace with real navigation/branding when\n * Contentstack content types and UX are defined.\n */\nexport default function HeaderPlaceholder() {\n return (\n <header role=\"banner\" data-testid=\"header-placeholder\">\n <p>Header MFE — TODO: implement header content</p>\n </header>\n );\n}\n","import React, { createContext } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { Routes, Route, BrowserRouter } from \"react-router-dom\";\nimport HeaderPlaceholder from \"./components/HeaderPlaceholder\";\nimport { AppContainer } from \"./styles/Main.styled\";\nimport \"./styles/globals.css\";\nimport { getLocale } from \"./utils/locale\";\n\nexport const HeaderMFEContext = createContext({ isMFE: true });\n\nfunction Main({ isMFE = true }) {\n let { country, language } = getLocale();\n country = country.toLocaleLowerCase();\n language = language.toLocaleLowerCase();\n\n const baseName = isMFE\n ? `/${country}/${language}`\n : `/${country}/${language}/static/header-mfe`;\n\n return (\n <HeaderMFEContext.Provider value={{ isMFE }}>\n <BrowserRouter basename={baseName}>\n <AppContainer>\n <Routes>\n <Route path=\"*\" element={<HeaderPlaceholder />} />\n </Routes>\n </AppContainer>\n </BrowserRouter>\n </HeaderMFEContext.Provider>\n );\n}\n\nMain.propTypes = {\n isMFE: PropTypes.bool,\n};\n\nexport default Main;\n","import styled from \"@emotion/styled\";\n\nexport const AppContainer = styled.div`\n font-family: \"Inter\", sans-serif;\n`;\n","/**\n * Extracts the locale code from the provided URL or the current URL.\n *\n * @param options - An object with the following properties:\n * @param options.url - The URL to extract the locale code from. If not provided, the current URL will be used.\n * @param options.defaultLocale - The default locale code to use if the locale cannot be extracted from the URL.\n * @returns The locale code in the format \"language_COUNTRY\".\n */\nfunction getLocaleCodeFromUrl(options) {\n const { url = \"\", defaultLocale = \"\" } = options ?? {};\n\n let localeAsArr = [];\n\n let tempUrl = url || (typeof location != \"undefined\" && location.href);\n\n if (tempUrl) {\n /* adding dummy domain since express originalUrl will not have request domain */\n if (!tempUrl?.includes(\"https://\") && !tempUrl?.includes(\"http://\")) {\n tempUrl = `https://domain.com${tempUrl}`;\n }\n const updatedUrl = new URL(tempUrl);\n\n const pathParams = updatedUrl.pathname;\n if (pathParams) {\n const pathList = pathParams?.split(\"/\")?.filter(Boolean);\n if (pathList.length > 1) {\n localeAsArr = pathList;\n }\n }\n\n if (localeAsArr.length > 2) {\n localeAsArr = localeAsArr.slice(0, 2);\n }\n }\n localeAsArr = localeAsArr.reverse();\n\n if (localeAsArr.length === 0) {\n localeAsArr = defaultLocale.split(\"_\");\n }\n\n return `${localeAsArr[1]?.toUpperCase()}-${localeAsArr[0]}`;\n}\n\nfunction getLocale({ url } = {}) {\n const currentLocale = getLocaleCodeFromUrl(url ? { url } : null);\n const splitLocale = currentLocale?.split(\"-\");\n\n return {\n locale: currentLocale,\n language: splitLocale?.[1]?.toLowerCase(),\n country: splitLocale?.[0]?.toUpperCase(),\n };\n}\nexport { getLocale };\n","import { getLocale } from \"./locale\";\n\n/**\n * Stack-related config for Contentstack calls (e.g. getContent).\n * Set CONTENTSTACK_HEADER_CONTENT_TYPE in env when the header content type exists.\n */\nfunction getStackConfig() {\n const { locale } = getLocale();\n return {\n contentType: process.env.CONTENTSTACK_HEADER_CONTENT_TYPE || \"\",\n locale,\n };\n}\n\nexport { getStackConfig };\n","import contentstack from \"@contentstack/delivery-sdk\";\nimport ContentstackLivePreview from \"@contentstack/live-preview-utils\";\nimport { addEditableTags } from \"@contentstack/utils\";\nimport {\n CONTENTSTACK_API_KEY,\n CONTENTSTACK_DELIVERY_TOKEN,\n CONTENTSTACK_ENVIRONMENT,\n CONTENTSTACK_PREVIEW_TOKEN,\n} from \"../constants\";\n\n/**\n * Contentstack delivery stack, live preview, and entry fetch.\n * TODO: Call getContent from header UI once CONTENTSTACK_HEADER_CONTENT_TYPE and\n * URL/slug strategy are defined; wire initLivePreview / onEntryChange in Visual Builder.\n */\n\n// Lazy-initialize the stack to avoid \"API key is required\" errors\n// when this module is loaded via Module Federation on the host server\n// (where env vars may not be available).\nlet _stack = null;\nfunction getStack() {\n if (!_stack) {\n _stack = contentstack.stack({\n apiKey: CONTENTSTACK_API_KEY,\n deliveryToken: CONTENTSTACK_DELIVERY_TOKEN,\n environment: CONTENTSTACK_ENVIRONMENT,\n live_preview: {\n enable: true,\n preview_token: CONTENTSTACK_PREVIEW_TOKEN,\n host: \"rest-preview.contentstack.com\",\n },\n });\n }\n return _stack;\n}\n\nconst BRIDGED_CONFIG_KEYS = [\"live_preview\", \"headers\", \"environment\"];\n\nexport const stack = new Proxy(\n {},\n {\n get(_, prop) {\n const s = getStack();\n if (BRIDGED_CONFIG_KEYS.includes(prop)) {\n return s.config?.[prop];\n }\n return s[prop];\n },\n set(_, prop, value) {\n const s = getStack();\n if (BRIDGED_CONFIG_KEYS.includes(prop)) {\n if (!s.config) return false;\n s.config[prop] = value;\n return true;\n }\n s[prop] = value;\n return true;\n },\n has(_, prop) {\n if (BRIDGED_CONFIG_KEYS.includes(prop)) return true;\n return prop in getStack();\n },\n ownKeys() {\n return [\n ...new Set([...Reflect.ownKeys(getStack()), ...BRIDGED_CONFIG_KEYS]),\n ];\n },\n getOwnPropertyDescriptor(_, prop) {\n if (BRIDGED_CONFIG_KEYS.includes(prop)) {\n return {\n configurable: true,\n enumerable: true,\n writable: true,\n value: getStack().config?.[prop],\n };\n }\n return Object.getOwnPropertyDescriptor(getStack(), prop);\n },\n },\n);\n\nlet _livePreviewInitialized = false;\n\nexport const onEntryChange = ContentstackLivePreview.onEntryChange.bind(\n ContentstackLivePreview,\n);\n\nexport function initLivePreview() {\n if (_livePreviewInitialized) return;\n _livePreviewInitialized = true;\n\n ContentstackLivePreview.init({\n ssr: false,\n enable: true,\n mode: \"builder\",\n stackSdk: stack,\n stackDetails: {\n apiKey: CONTENTSTACK_API_KEY,\n environment: CONTENTSTACK_ENVIRONMENT,\n },\n clientUrlParams: {\n host: \"app.contentstack.com\",\n },\n editButton: {\n enable: false,\n },\n });\n}\n\nexport function isEditingMode() {\n if (typeof window === \"undefined\") {\n return false;\n }\n if (window.self !== window.top) {\n return true;\n }\n\n const params = new URLSearchParams(window.location.search);\n return (\n params.has(\"visual-builder\") ||\n params.has(\"contentstack\") ||\n params.has(\"live_preview\")\n );\n}\n\nexport const getContent = async ({\n url,\n uid,\n contentType,\n language,\n referenceFields = [],\n} = {}) => {\n const tryFetch = async (locale) => {\n const CT = stack.contentType(contentType);\n let fetched = null;\n\n if (uid) {\n fetched = await CT.entry(uid)\n .locale(locale)\n .includeReference(referenceFields)\n .fetch();\n } else if (url) {\n const urlWithSlash = url.startsWith(\"/\") ? url : `/${url}`;\n const result = await CT.entry()\n .locale(locale)\n .includeReference(referenceFields)\n .query({ url: urlWithSlash })\n .find();\n fetched = result.entries?.[0];\n }\n if (isEditingMode() && fetched) {\n addEditableTags(fetched, contentType, true, language, {\n useLowerCaseLocale: false,\n });\n }\n\n return fetched;\n };\n\n try {\n const result = await tryFetch(language);\n return result;\n } catch (error) {\n console.warn(\n \"Failed to fetch content with language:\",\n language,\n error.message,\n );\n try {\n const fallbackResult = await tryFetch(\"en\");\n return fallbackResult;\n } catch (fallbackError) {\n console.warn(\n \"Failed to fetch content with fallback language:\",\n fallbackError.message,\n );\n return null;\n }\n }\n};\n","const CONTENTSTACK_API_KEY = process.env.CONTENTSTACK_API_KEY;\nconst CONTENTSTACK_DELIVERY_TOKEN = process.env.CONTENTSTACK_DELIVERY_TOKEN;\nconst CONTENTSTACK_ENVIRONMENT = process.env.CONTENTSTACK_ENVIRONMENT;\nconst CONTENTSTACK_PREVIEW_TOKEN = process.env.CONTENTSTACK_PREVIEW_TOKEN;\n\n/**\n * Reference field UIDs for `includeReference` when fetching header entries.\n * TODO: populate when the header content model uses references.\n */\nconst referenceFields = [];\n\n// SSR-safe constant — avoids importing @contentstack/live-preview-utils\n// which accesses `window` at module load time.\nconst VB_EmptyBlockParentClass = \"visual-builder__empty-block-parent\";\n\nexport {\n CONTENTSTACK_API_KEY,\n CONTENTSTACK_DELIVERY_TOKEN,\n CONTENTSTACK_ENVIRONMENT,\n CONTENTSTACK_PREVIEW_TOKEN,\n referenceFields,\n VB_EmptyBlockParentClass,\n};\n"],"mappings":"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","names":["React","import_react","styled","React","PropTypes","contentstack","ContentstackLivePreview","referenceFields"]}
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// src/components/HeaderPlaceholder.jsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
function HeaderPlaceholder() {
|
|
4
|
+
return /* @__PURE__ */ React.createElement("header", { role: "banner", "data-testid": "header-placeholder" }, /* @__PURE__ */ React.createElement("p", null, "Header MFE \u2014 TODO: implement header content"));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
// src/Main.js
|
|
8
|
+
import React2, { createContext } from "react";
|
|
9
|
+
import PropTypes from "prop-types";
|
|
10
|
+
import { Routes, Route, BrowserRouter } from "react-router-dom";
|
|
11
|
+
|
|
12
|
+
// src/styles/Main.styled.js
|
|
13
|
+
import styled from "@emotion/styled";
|
|
14
|
+
var AppContainer = styled.div`
|
|
15
|
+
font-family: "Inter", sans-serif;
|
|
16
|
+
`;
|
|
17
|
+
|
|
18
|
+
// src/utils/locale.js
|
|
19
|
+
function getLocaleCodeFromUrl(options) {
|
|
20
|
+
var _a, _b;
|
|
21
|
+
const { url = "", defaultLocale = "" } = options ?? {};
|
|
22
|
+
let localeAsArr = [];
|
|
23
|
+
let tempUrl = url || typeof location != "undefined" && location.href;
|
|
24
|
+
if (tempUrl) {
|
|
25
|
+
if (!(tempUrl == null ? void 0 : tempUrl.includes("https://")) && !(tempUrl == null ? void 0 : tempUrl.includes("http://"))) {
|
|
26
|
+
tempUrl = `https://domain.com${tempUrl}`;
|
|
27
|
+
}
|
|
28
|
+
const updatedUrl = new URL(tempUrl);
|
|
29
|
+
const pathParams = updatedUrl.pathname;
|
|
30
|
+
if (pathParams) {
|
|
31
|
+
const pathList = (_a = pathParams == null ? void 0 : pathParams.split("/")) == null ? void 0 : _a.filter(Boolean);
|
|
32
|
+
if (pathList.length > 1) {
|
|
33
|
+
localeAsArr = pathList;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (localeAsArr.length > 2) {
|
|
37
|
+
localeAsArr = localeAsArr.slice(0, 2);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
localeAsArr = localeAsArr.reverse();
|
|
41
|
+
if (localeAsArr.length === 0) {
|
|
42
|
+
localeAsArr = defaultLocale.split("_");
|
|
43
|
+
}
|
|
44
|
+
return `${(_b = localeAsArr[1]) == null ? void 0 : _b.toUpperCase()}-${localeAsArr[0]}`;
|
|
45
|
+
}
|
|
46
|
+
function getLocale({ url } = {}) {
|
|
47
|
+
var _a, _b;
|
|
48
|
+
const currentLocale = getLocaleCodeFromUrl(url ? { url } : null);
|
|
49
|
+
const splitLocale = currentLocale == null ? void 0 : currentLocale.split("-");
|
|
50
|
+
return {
|
|
51
|
+
locale: currentLocale,
|
|
52
|
+
language: (_a = splitLocale == null ? void 0 : splitLocale[1]) == null ? void 0 : _a.toLowerCase(),
|
|
53
|
+
country: (_b = splitLocale == null ? void 0 : splitLocale[0]) == null ? void 0 : _b.toUpperCase()
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/Main.js
|
|
58
|
+
var HeaderMFEContext = createContext({ isMFE: true });
|
|
59
|
+
function Main({ isMFE = true }) {
|
|
60
|
+
let { country, language } = getLocale();
|
|
61
|
+
country = country.toLocaleLowerCase();
|
|
62
|
+
language = language.toLocaleLowerCase();
|
|
63
|
+
const baseName = isMFE ? `/${country}/${language}` : `/${country}/${language}/static/header-mfe`;
|
|
64
|
+
return /* @__PURE__ */ React2.createElement(HeaderMFEContext.Provider, { value: { isMFE } }, /* @__PURE__ */ React2.createElement(BrowserRouter, { basename: baseName }, /* @__PURE__ */ React2.createElement(AppContainer, null, /* @__PURE__ */ React2.createElement(Routes, null, /* @__PURE__ */ React2.createElement(Route, { path: "*", element: /* @__PURE__ */ React2.createElement(HeaderPlaceholder, null) })))));
|
|
65
|
+
}
|
|
66
|
+
Main.propTypes = {
|
|
67
|
+
isMFE: PropTypes.bool
|
|
68
|
+
};
|
|
69
|
+
var Main_default = Main;
|
|
70
|
+
|
|
71
|
+
// src/utils/config.js
|
|
72
|
+
function getStackConfig() {
|
|
73
|
+
const { locale } = getLocale();
|
|
74
|
+
return {
|
|
75
|
+
contentType: process.env.CONTENTSTACK_HEADER_CONTENT_TYPE || "",
|
|
76
|
+
locale
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/utils/contentstack.js
|
|
81
|
+
import contentstack from "@contentstack/delivery-sdk";
|
|
82
|
+
import ContentstackLivePreview from "@contentstack/live-preview-utils";
|
|
83
|
+
import { addEditableTags } from "@contentstack/utils";
|
|
84
|
+
|
|
85
|
+
// src/constants.js
|
|
86
|
+
var CONTENTSTACK_API_KEY = process.env.CONTENTSTACK_API_KEY;
|
|
87
|
+
var CONTENTSTACK_DELIVERY_TOKEN = process.env.CONTENTSTACK_DELIVERY_TOKEN;
|
|
88
|
+
var CONTENTSTACK_ENVIRONMENT = process.env.CONTENTSTACK_ENVIRONMENT;
|
|
89
|
+
var CONTENTSTACK_PREVIEW_TOKEN = process.env.CONTENTSTACK_PREVIEW_TOKEN;
|
|
90
|
+
var referenceFields = [];
|
|
91
|
+
var VB_EmptyBlockParentClass = "visual-builder__empty-block-parent";
|
|
92
|
+
|
|
93
|
+
// src/utils/contentstack.js
|
|
94
|
+
var _stack = null;
|
|
95
|
+
function getStack() {
|
|
96
|
+
if (!_stack) {
|
|
97
|
+
_stack = contentstack.stack({
|
|
98
|
+
apiKey: CONTENTSTACK_API_KEY,
|
|
99
|
+
deliveryToken: CONTENTSTACK_DELIVERY_TOKEN,
|
|
100
|
+
environment: CONTENTSTACK_ENVIRONMENT,
|
|
101
|
+
live_preview: {
|
|
102
|
+
enable: true,
|
|
103
|
+
preview_token: CONTENTSTACK_PREVIEW_TOKEN,
|
|
104
|
+
host: "rest-preview.contentstack.com"
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return _stack;
|
|
109
|
+
}
|
|
110
|
+
var BRIDGED_CONFIG_KEYS = ["live_preview", "headers", "environment"];
|
|
111
|
+
var stack = new Proxy(
|
|
112
|
+
{},
|
|
113
|
+
{
|
|
114
|
+
get(_, prop) {
|
|
115
|
+
var _a;
|
|
116
|
+
const s = getStack();
|
|
117
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) {
|
|
118
|
+
return (_a = s.config) == null ? void 0 : _a[prop];
|
|
119
|
+
}
|
|
120
|
+
return s[prop];
|
|
121
|
+
},
|
|
122
|
+
set(_, prop, value) {
|
|
123
|
+
const s = getStack();
|
|
124
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) {
|
|
125
|
+
if (!s.config) return false;
|
|
126
|
+
s.config[prop] = value;
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
s[prop] = value;
|
|
130
|
+
return true;
|
|
131
|
+
},
|
|
132
|
+
has(_, prop) {
|
|
133
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) return true;
|
|
134
|
+
return prop in getStack();
|
|
135
|
+
},
|
|
136
|
+
ownKeys() {
|
|
137
|
+
return [
|
|
138
|
+
.../* @__PURE__ */ new Set([...Reflect.ownKeys(getStack()), ...BRIDGED_CONFIG_KEYS])
|
|
139
|
+
];
|
|
140
|
+
},
|
|
141
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
142
|
+
var _a;
|
|
143
|
+
if (BRIDGED_CONFIG_KEYS.includes(prop)) {
|
|
144
|
+
return {
|
|
145
|
+
configurable: true,
|
|
146
|
+
enumerable: true,
|
|
147
|
+
writable: true,
|
|
148
|
+
value: (_a = getStack().config) == null ? void 0 : _a[prop]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return Object.getOwnPropertyDescriptor(getStack(), prop);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
);
|
|
155
|
+
var _livePreviewInitialized = false;
|
|
156
|
+
var onEntryChange = ContentstackLivePreview.onEntryChange.bind(
|
|
157
|
+
ContentstackLivePreview
|
|
158
|
+
);
|
|
159
|
+
function initLivePreview() {
|
|
160
|
+
if (_livePreviewInitialized) return;
|
|
161
|
+
_livePreviewInitialized = true;
|
|
162
|
+
ContentstackLivePreview.init({
|
|
163
|
+
ssr: false,
|
|
164
|
+
enable: true,
|
|
165
|
+
mode: "builder",
|
|
166
|
+
stackSdk: stack,
|
|
167
|
+
stackDetails: {
|
|
168
|
+
apiKey: CONTENTSTACK_API_KEY,
|
|
169
|
+
environment: CONTENTSTACK_ENVIRONMENT
|
|
170
|
+
},
|
|
171
|
+
clientUrlParams: {
|
|
172
|
+
host: "app.contentstack.com"
|
|
173
|
+
},
|
|
174
|
+
editButton: {
|
|
175
|
+
enable: false
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
function isEditingMode() {
|
|
180
|
+
if (typeof window === "undefined") {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
if (window.self !== window.top) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
const params = new URLSearchParams(window.location.search);
|
|
187
|
+
return params.has("visual-builder") || params.has("contentstack") || params.has("live_preview");
|
|
188
|
+
}
|
|
189
|
+
var getContent = async ({
|
|
190
|
+
url,
|
|
191
|
+
uid,
|
|
192
|
+
contentType,
|
|
193
|
+
language,
|
|
194
|
+
referenceFields: referenceFields2 = []
|
|
195
|
+
} = {}) => {
|
|
196
|
+
const tryFetch = async (locale) => {
|
|
197
|
+
var _a;
|
|
198
|
+
const CT = stack.contentType(contentType);
|
|
199
|
+
let fetched = null;
|
|
200
|
+
if (uid) {
|
|
201
|
+
fetched = await CT.entry(uid).locale(locale).includeReference(referenceFields2).fetch();
|
|
202
|
+
} else if (url) {
|
|
203
|
+
const urlWithSlash = url.startsWith("/") ? url : `/${url}`;
|
|
204
|
+
const result = await CT.entry().locale(locale).includeReference(referenceFields2).query({ url: urlWithSlash }).find();
|
|
205
|
+
fetched = (_a = result.entries) == null ? void 0 : _a[0];
|
|
206
|
+
}
|
|
207
|
+
if (isEditingMode() && fetched) {
|
|
208
|
+
addEditableTags(fetched, contentType, true, language, {
|
|
209
|
+
useLowerCaseLocale: false
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return fetched;
|
|
213
|
+
};
|
|
214
|
+
try {
|
|
215
|
+
const result = await tryFetch(language);
|
|
216
|
+
return result;
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.warn(
|
|
219
|
+
"Failed to fetch content with language:",
|
|
220
|
+
language,
|
|
221
|
+
error.message
|
|
222
|
+
);
|
|
223
|
+
try {
|
|
224
|
+
const fallbackResult = await tryFetch("en");
|
|
225
|
+
return fallbackResult;
|
|
226
|
+
} catch (fallbackError) {
|
|
227
|
+
console.warn(
|
|
228
|
+
"Failed to fetch content with fallback language:",
|
|
229
|
+
fallbackError.message
|
|
230
|
+
);
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
export {
|
|
236
|
+
CONTENTSTACK_API_KEY,
|
|
237
|
+
CONTENTSTACK_DELIVERY_TOKEN,
|
|
238
|
+
CONTENTSTACK_ENVIRONMENT,
|
|
239
|
+
CONTENTSTACK_PREVIEW_TOKEN,
|
|
240
|
+
HeaderMFEContext,
|
|
241
|
+
HeaderPlaceholder,
|
|
242
|
+
Main_default as Main,
|
|
243
|
+
VB_EmptyBlockParentClass,
|
|
244
|
+
getContent,
|
|
245
|
+
getLocale,
|
|
246
|
+
getStackConfig,
|
|
247
|
+
initLivePreview,
|
|
248
|
+
isEditingMode,
|
|
249
|
+
onEntryChange,
|
|
250
|
+
referenceFields,
|
|
251
|
+
stack
|
|
252
|
+
};
|
|
253
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/HeaderPlaceholder.jsx","../src/Main.js","../src/styles/Main.styled.js","../src/utils/locale.js","../src/utils/config.js","../src/utils/contentstack.js","../src/constants.js"],"sourcesContent":["import React from \"react\";\n\n/**\n * Stub shell for the future header. Replace with real navigation/branding when\n * Contentstack content types and UX are defined.\n */\nexport default function HeaderPlaceholder() {\n return (\n <header role=\"banner\" data-testid=\"header-placeholder\">\n <p>Header MFE — TODO: implement header content</p>\n </header>\n );\n}\n","import React, { createContext } from \"react\";\nimport PropTypes from \"prop-types\";\nimport { Routes, Route, BrowserRouter } from \"react-router-dom\";\nimport HeaderPlaceholder from \"./components/HeaderPlaceholder\";\nimport { AppContainer } from \"./styles/Main.styled\";\nimport \"./styles/globals.css\";\nimport { getLocale } from \"./utils/locale\";\n\nexport const HeaderMFEContext = createContext({ isMFE: true });\n\nfunction Main({ isMFE = true }) {\n let { country, language } = getLocale();\n country = country.toLocaleLowerCase();\n language = language.toLocaleLowerCase();\n\n const baseName = isMFE\n ? `/${country}/${language}`\n : `/${country}/${language}/static/header-mfe`;\n\n return (\n <HeaderMFEContext.Provider value={{ isMFE }}>\n <BrowserRouter basename={baseName}>\n <AppContainer>\n <Routes>\n <Route path=\"*\" element={<HeaderPlaceholder />} />\n </Routes>\n </AppContainer>\n </BrowserRouter>\n </HeaderMFEContext.Provider>\n );\n}\n\nMain.propTypes = {\n isMFE: PropTypes.bool,\n};\n\nexport default Main;\n","import styled from \"@emotion/styled\";\n\nexport const AppContainer = styled.div`\n font-family: \"Inter\", sans-serif;\n`;\n","/**\n * Extracts the locale code from the provided URL or the current URL.\n *\n * @param options - An object with the following properties:\n * @param options.url - The URL to extract the locale code from. If not provided, the current URL will be used.\n * @param options.defaultLocale - The default locale code to use if the locale cannot be extracted from the URL.\n * @returns The locale code in the format \"language_COUNTRY\".\n */\nfunction getLocaleCodeFromUrl(options) {\n const { url = \"\", defaultLocale = \"\" } = options ?? {};\n\n let localeAsArr = [];\n\n let tempUrl = url || (typeof location != \"undefined\" && location.href);\n\n if (tempUrl) {\n /* adding dummy domain since express originalUrl will not have request domain */\n if (!tempUrl?.includes(\"https://\") && !tempUrl?.includes(\"http://\")) {\n tempUrl = `https://domain.com${tempUrl}`;\n }\n const updatedUrl = new URL(tempUrl);\n\n const pathParams = updatedUrl.pathname;\n if (pathParams) {\n const pathList = pathParams?.split(\"/\")?.filter(Boolean);\n if (pathList.length > 1) {\n localeAsArr = pathList;\n }\n }\n\n if (localeAsArr.length > 2) {\n localeAsArr = localeAsArr.slice(0, 2);\n }\n }\n localeAsArr = localeAsArr.reverse();\n\n if (localeAsArr.length === 0) {\n localeAsArr = defaultLocale.split(\"_\");\n }\n\n return `${localeAsArr[1]?.toUpperCase()}-${localeAsArr[0]}`;\n}\n\nfunction getLocale({ url } = {}) {\n const currentLocale = getLocaleCodeFromUrl(url ? { url } : null);\n const splitLocale = currentLocale?.split(\"-\");\n\n return {\n locale: currentLocale,\n language: splitLocale?.[1]?.toLowerCase(),\n country: splitLocale?.[0]?.toUpperCase(),\n };\n}\nexport { getLocale };\n","import { getLocale } from \"./locale\";\n\n/**\n * Stack-related config for Contentstack calls (e.g. getContent).\n * Set CONTENTSTACK_HEADER_CONTENT_TYPE in env when the header content type exists.\n */\nfunction getStackConfig() {\n const { locale } = getLocale();\n return {\n contentType: process.env.CONTENTSTACK_HEADER_CONTENT_TYPE || \"\",\n locale,\n };\n}\n\nexport { getStackConfig };\n","import contentstack from \"@contentstack/delivery-sdk\";\nimport ContentstackLivePreview from \"@contentstack/live-preview-utils\";\nimport { addEditableTags } from \"@contentstack/utils\";\nimport {\n CONTENTSTACK_API_KEY,\n CONTENTSTACK_DELIVERY_TOKEN,\n CONTENTSTACK_ENVIRONMENT,\n CONTENTSTACK_PREVIEW_TOKEN,\n} from \"../constants\";\n\n/**\n * Contentstack delivery stack, live preview, and entry fetch.\n * TODO: Call getContent from header UI once CONTENTSTACK_HEADER_CONTENT_TYPE and\n * URL/slug strategy are defined; wire initLivePreview / onEntryChange in Visual Builder.\n */\n\n// Lazy-initialize the stack to avoid \"API key is required\" errors\n// when this module is loaded via Module Federation on the host server\n// (where env vars may not be available).\nlet _stack = null;\nfunction getStack() {\n if (!_stack) {\n _stack = contentstack.stack({\n apiKey: CONTENTSTACK_API_KEY,\n deliveryToken: CONTENTSTACK_DELIVERY_TOKEN,\n environment: CONTENTSTACK_ENVIRONMENT,\n live_preview: {\n enable: true,\n preview_token: CONTENTSTACK_PREVIEW_TOKEN,\n host: \"rest-preview.contentstack.com\",\n },\n });\n }\n return _stack;\n}\n\nconst BRIDGED_CONFIG_KEYS = [\"live_preview\", \"headers\", \"environment\"];\n\nexport const stack = new Proxy(\n {},\n {\n get(_, prop) {\n const s = getStack();\n if (BRIDGED_CONFIG_KEYS.includes(prop)) {\n return s.config?.[prop];\n }\n return s[prop];\n },\n set(_, prop, value) {\n const s = getStack();\n if (BRIDGED_CONFIG_KEYS.includes(prop)) {\n if (!s.config) return false;\n s.config[prop] = value;\n return true;\n }\n s[prop] = value;\n return true;\n },\n has(_, prop) {\n if (BRIDGED_CONFIG_KEYS.includes(prop)) return true;\n return prop in getStack();\n },\n ownKeys() {\n return [\n ...new Set([...Reflect.ownKeys(getStack()), ...BRIDGED_CONFIG_KEYS]),\n ];\n },\n getOwnPropertyDescriptor(_, prop) {\n if (BRIDGED_CONFIG_KEYS.includes(prop)) {\n return {\n configurable: true,\n enumerable: true,\n writable: true,\n value: getStack().config?.[prop],\n };\n }\n return Object.getOwnPropertyDescriptor(getStack(), prop);\n },\n },\n);\n\nlet _livePreviewInitialized = false;\n\nexport const onEntryChange = ContentstackLivePreview.onEntryChange.bind(\n ContentstackLivePreview,\n);\n\nexport function initLivePreview() {\n if (_livePreviewInitialized) return;\n _livePreviewInitialized = true;\n\n ContentstackLivePreview.init({\n ssr: false,\n enable: true,\n mode: \"builder\",\n stackSdk: stack,\n stackDetails: {\n apiKey: CONTENTSTACK_API_KEY,\n environment: CONTENTSTACK_ENVIRONMENT,\n },\n clientUrlParams: {\n host: \"app.contentstack.com\",\n },\n editButton: {\n enable: false,\n },\n });\n}\n\nexport function isEditingMode() {\n if (typeof window === \"undefined\") {\n return false;\n }\n if (window.self !== window.top) {\n return true;\n }\n\n const params = new URLSearchParams(window.location.search);\n return (\n params.has(\"visual-builder\") ||\n params.has(\"contentstack\") ||\n params.has(\"live_preview\")\n );\n}\n\nexport const getContent = async ({\n url,\n uid,\n contentType,\n language,\n referenceFields = [],\n} = {}) => {\n const tryFetch = async (locale) => {\n const CT = stack.contentType(contentType);\n let fetched = null;\n\n if (uid) {\n fetched = await CT.entry(uid)\n .locale(locale)\n .includeReference(referenceFields)\n .fetch();\n } else if (url) {\n const urlWithSlash = url.startsWith(\"/\") ? url : `/${url}`;\n const result = await CT.entry()\n .locale(locale)\n .includeReference(referenceFields)\n .query({ url: urlWithSlash })\n .find();\n fetched = result.entries?.[0];\n }\n if (isEditingMode() && fetched) {\n addEditableTags(fetched, contentType, true, language, {\n useLowerCaseLocale: false,\n });\n }\n\n return fetched;\n };\n\n try {\n const result = await tryFetch(language);\n return result;\n } catch (error) {\n console.warn(\n \"Failed to fetch content with language:\",\n language,\n error.message,\n );\n try {\n const fallbackResult = await tryFetch(\"en\");\n return fallbackResult;\n } catch (fallbackError) {\n console.warn(\n \"Failed to fetch content with fallback language:\",\n fallbackError.message,\n );\n return null;\n }\n }\n};\n","const CONTENTSTACK_API_KEY = process.env.CONTENTSTACK_API_KEY;\nconst CONTENTSTACK_DELIVERY_TOKEN = process.env.CONTENTSTACK_DELIVERY_TOKEN;\nconst CONTENTSTACK_ENVIRONMENT = process.env.CONTENTSTACK_ENVIRONMENT;\nconst CONTENTSTACK_PREVIEW_TOKEN = process.env.CONTENTSTACK_PREVIEW_TOKEN;\n\n/**\n * Reference field UIDs for `includeReference` when fetching header entries.\n * TODO: populate when the header content model uses references.\n */\nconst referenceFields = [];\n\n// SSR-safe constant — avoids importing @contentstack/live-preview-utils\n// which accesses `window` at module load time.\nconst VB_EmptyBlockParentClass = \"visual-builder__empty-block-parent\";\n\nexport {\n CONTENTSTACK_API_KEY,\n CONTENTSTACK_DELIVERY_TOKEN,\n CONTENTSTACK_ENVIRONMENT,\n CONTENTSTACK_PREVIEW_TOKEN,\n referenceFields,\n VB_EmptyBlockParentClass,\n};\n"],"mappings":"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","names":["React","React","referenceFields"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuskin/nextgen-header",
|
|
3
|
+
"version": "1.0.0-library-setup.1",
|
|
4
|
+
"description": "Header micro-frontend and npm component library",
|
|
5
|
+
"main": "package-dist/index.js",
|
|
6
|
+
"module": "package-dist/index.mjs",
|
|
7
|
+
"types": "package-dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"start": "nodemon --watch src --ext js,jsx,css --delay 2 --exec \"yarn serve\"",
|
|
10
|
+
"serve": "yarn build && node server-launcher.js",
|
|
11
|
+
"build": "cross-env CMS_ENV=local NODE_ENV=production yarn build:server:dev && yarn build:client:dev",
|
|
12
|
+
"build-dev": "cross-env CMS_ENV=dev NODE_ENV=production yarn build:server:dev && cross-env CMS_ENV=dev NODE_ENV=production yarn build:client:dev",
|
|
13
|
+
"build-test": "cross-env CMS_ENV=test NODE_ENV=production yarn build:server:dev && cross-env CMS_ENV=test NODE_ENV=production yarn build:client:dev",
|
|
14
|
+
"build-prod": "cross-env CMS_ENV=prod NODE_ENV=production yarn build:server:prod && cross-env CMS_ENV=prod NODE_ENV=production yarn build:client:prod",
|
|
15
|
+
"build:client:dev": "rimraf --glob dist/*.js dist/*.js.map dist/loadable-stats.json dist/index.html && yarn webpack --mode development --progress --config config/webpack.client.js",
|
|
16
|
+
"build:client:prod": "rimraf --glob dist/*.js dist/*.js.map dist/loadable-stats.json dist/index.html && yarn webpack --mode production --progress --config config/webpack.client.js",
|
|
17
|
+
"build:server:dev": "rimraf dist/server && yarn webpack --mode development --progress --config config/webpack.server.js",
|
|
18
|
+
"build:server:prod": "rimraf dist/server && yarn webpack --mode production --progress --config config/webpack.server.js",
|
|
19
|
+
"test": "jest",
|
|
20
|
+
"integration-test": "echo 'Integration test not yet implemented'",
|
|
21
|
+
"lint": "eslint src/ --ext .js,.jsx",
|
|
22
|
+
"build:package": "rimraf package-dist && tsup && shx cp src/library/index.d.ts package-dist/index.d.ts",
|
|
23
|
+
"prepublishOnly": "yarn build:package"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"react",
|
|
27
|
+
"header",
|
|
28
|
+
"micro-frontend",
|
|
29
|
+
"contentstack"
|
|
30
|
+
],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "ISC",
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"package-dist",
|
|
38
|
+
"readme.md"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": [
|
|
41
|
+
"**/*.css",
|
|
42
|
+
"package-dist/**/*.css"
|
|
43
|
+
],
|
|
44
|
+
"exports": {
|
|
45
|
+
".": {
|
|
46
|
+
"types": "./package-dist/index.d.ts",
|
|
47
|
+
"import": "./package-dist/index.mjs",
|
|
48
|
+
"require": "./package-dist/index.js"
|
|
49
|
+
},
|
|
50
|
+
"./index.css": "./package-dist/index.css"
|
|
51
|
+
},
|
|
52
|
+
"peerDependencies": {
|
|
53
|
+
"@contentstack/delivery-sdk": "^4.10.0",
|
|
54
|
+
"@contentstack/live-preview-utils": "^4.1.0",
|
|
55
|
+
"@contentstack/utils": "1.7.0",
|
|
56
|
+
"@emotion/react": "^11.14.0",
|
|
57
|
+
"@emotion/styled": "^11.14.0",
|
|
58
|
+
"contentstack": "^3.26.0",
|
|
59
|
+
"prop-types": "^15.8.0",
|
|
60
|
+
"react": "^18.2.0",
|
|
61
|
+
"react-dom": "^18.2.0",
|
|
62
|
+
"react-router-dom": "^7.7.0"
|
|
63
|
+
},
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=24.0.0"
|
|
66
|
+
},
|
|
67
|
+
"dependencies": {
|
|
68
|
+
"@contentstack/delivery-sdk": "^4.10.3",
|
|
69
|
+
"@contentstack/live-preview-utils": "^4.1.2",
|
|
70
|
+
"@contentstack/utils": "1.7.0",
|
|
71
|
+
"@emotion/react": "^11.14.0",
|
|
72
|
+
"@emotion/styled": "^11.14.1",
|
|
73
|
+
"@loadable/babel-plugin": "^5.13.2",
|
|
74
|
+
"@loadable/component": "^5.16.4",
|
|
75
|
+
"@loadable/server": "^5.16.5",
|
|
76
|
+
"contentstack": "^3.26.2",
|
|
77
|
+
"core-js": "^3.39.0",
|
|
78
|
+
"cross-env": "7.0.3",
|
|
79
|
+
"dotenv": "^17.2.1",
|
|
80
|
+
"eslint": "^8",
|
|
81
|
+
"eslint-config-next": "14.0.4",
|
|
82
|
+
"eslint-plugin-prettier": "^5.2.4",
|
|
83
|
+
"eslint-plugin-spellcheck": "^0.0.20",
|
|
84
|
+
"eslint-plugin-unused-imports": "^3.1.0",
|
|
85
|
+
"express": "^4.21.2",
|
|
86
|
+
"jest": "29.7.0",
|
|
87
|
+
"jest-environment-jsdom": "29.7.0",
|
|
88
|
+
"prettier": "^3.5.3",
|
|
89
|
+
"prop-types": "^15.8.1",
|
|
90
|
+
"react": "^18.2.0",
|
|
91
|
+
"react-dom": "^18.2.0",
|
|
92
|
+
"react-gtm-module": "^2.0.11",
|
|
93
|
+
"react-router-dom": "^7.7.1",
|
|
94
|
+
"regenerator-runtime": "0.14.1"
|
|
95
|
+
},
|
|
96
|
+
"devDependencies": {
|
|
97
|
+
"@babel/core": "^7.22.0",
|
|
98
|
+
"@babel/node": "7.24.7",
|
|
99
|
+
"@babel/plugin-proposal-class-properties": "7.18.6",
|
|
100
|
+
"@babel/preset-env": "^7.22.0",
|
|
101
|
+
"@babel/preset-react": "^7.22.0",
|
|
102
|
+
"@emotion/babel-plugin": "^11.13.5",
|
|
103
|
+
"@loadable/webpack-plugin": "5.15.2",
|
|
104
|
+
"@module-federation/enhanced": "0.15.0",
|
|
105
|
+
"@module-federation/node": "2.7.7",
|
|
106
|
+
"@testing-library/jest-dom": "^6.1.5",
|
|
107
|
+
"@testing-library/react": "^14.1.2",
|
|
108
|
+
"babel-jest": "^29.7.0",
|
|
109
|
+
"babel-loader": "^9.1.0",
|
|
110
|
+
"css-loader": "^6.8.0",
|
|
111
|
+
"dotenv-webpack": "^8.1.1",
|
|
112
|
+
"eslint-config-prettier": "^9.1.0",
|
|
113
|
+
"eslint-plugin-react": "^7.37.5",
|
|
114
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
115
|
+
"file-loader": "^6.2.0",
|
|
116
|
+
"html-webpack-plugin": "^5.5.0",
|
|
117
|
+
"identity-obj-proxy": "^3.0.0",
|
|
118
|
+
"nodemon": "^3.1.14",
|
|
119
|
+
"process": "^0.11.10",
|
|
120
|
+
"rimraf": "5.0.8",
|
|
121
|
+
"shx": "^0.4.0",
|
|
122
|
+
"style-loader": "^3.3.0",
|
|
123
|
+
"tsup": "^8.5.1",
|
|
124
|
+
"typescript": "^5.9.3",
|
|
125
|
+
"webpack": "^5.88.0",
|
|
126
|
+
"webpack-cli": "^5.1.0",
|
|
127
|
+
"webpack-dev-server": "^4.15.0",
|
|
128
|
+
"webpack-federation-stats-plugin": "1.1.0",
|
|
129
|
+
"webpack-manifest-plugin": "^5.0.1",
|
|
130
|
+
"webpack-merge": "6.0.1"
|
|
131
|
+
}
|
|
132
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# Header MFE (`@nuskin/nextgen-header`)
|
|
2
|
+
|
|
3
|
+
This repository produces **two** deployables:
|
|
4
|
+
|
|
5
|
+
1. **Module Federation app** — Webpack builds `remoteEntry` and static assets for CDN/S3 (via GitLab `static-client-app` pipeline). Host apps load the remote as `header_mfe` / `./App`.
|
|
6
|
+
2. **npm package** — `yarn build:package` emits `package-dist/` for **`@nuskin/nextgen-header`** on npmjs (via GitLab `npm-module-ci` release / pre-release jobs).
|
|
7
|
+
|
|
8
|
+
The UI is intentionally minimal (`HeaderPlaceholder`). Replace it when navigation, Contentstack types, and analytics are defined.
|
|
9
|
+
|
|
10
|
+
## Prerequisites
|
|
11
|
+
|
|
12
|
+
- **Node.js 24+** (see `engines` in `package.json` and `.nvmrc` for `nvm` / `fnm`)
|
|
13
|
+
- Yarn
|
|
14
|
+
- Contentstack stack credentials (for real API calls)
|
|
15
|
+
|
|
16
|
+
## Install (monorepo / local development)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
yarn install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## NPM library (`@nuskin/nextgen-header`)
|
|
23
|
+
|
|
24
|
+
Install in a host application that already provides the peer dependencies (React 18, Emotion, React Router 7, Contentstack SDKs):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
yarn add @nuskin/nextgen-header
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**Example**
|
|
31
|
+
|
|
32
|
+
```jsx
|
|
33
|
+
import {
|
|
34
|
+
HeaderPlaceholder,
|
|
35
|
+
Main,
|
|
36
|
+
getLocale,
|
|
37
|
+
getStackConfig,
|
|
38
|
+
} from "@nuskin/nextgen-header";
|
|
39
|
+
import "@nuskin/nextgen-header/index.css";
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **Exports** are defined in [`src/library/index.js`](src/library/index.js) (barrel for the published API).
|
|
43
|
+
- **Types** ship as [`src/library/index.d.ts`](src/library/index.d.ts) (copied to `package-dist/index.d.ts` on build).
|
|
44
|
+
- **Styles**: the library build emits Emotion-related CSS under `package-dist/index.css`; import `@nuskin/nextgen-header/index.css` (see `package.json` `exports["./index.css"]`).
|
|
45
|
+
|
|
46
|
+
**Build the tarball locally**
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
yarn build:package
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Publish** (CI runs `yarn build:package` before `npm publish` via `prepublishOnly`; align with your org’s versioning and `yarn npm publish` / tags.)
|
|
53
|
+
|
|
54
|
+
### Peer dependencies
|
|
55
|
+
|
|
56
|
+
Declared in `package.json` under `peerDependencies`: `react`, `react-dom`, `prop-types`, `react-router-dom`, `@emotion/react`, `@emotion/styled`, Contentstack packages, and `contentstack`. Your app must install compatible versions.
|
|
57
|
+
|
|
58
|
+
## Environment variables
|
|
59
|
+
|
|
60
|
+
Dotenv files are loaded per **webpack** build via `CMS_ENV` (see `package.json` scripts): `.env.local`, `.env.dev`, `.env.test`, `.env.prod`.
|
|
61
|
+
|
|
62
|
+
| Variable | Purpose |
|
|
63
|
+
|----------|---------|
|
|
64
|
+
| `CONTENTSTACK_API_KEY` | Stack API key |
|
|
65
|
+
| `CONTENTSTACK_DELIVERY_TOKEN` | Delivery token |
|
|
66
|
+
| `CONTENTSTACK_ENVIRONMENT` | Environment name |
|
|
67
|
+
| `CONTENTSTACK_PREVIEW_TOKEN` | Preview token (Visual Builder / live preview) |
|
|
68
|
+
| `CONTENTSTACK_HEADER_CONTENT_TYPE` | Content type UID for header entries (set when the model exists) |
|
|
69
|
+
| `REACT_APP_GTM_KEY_DEV` / `REACT_APP_GTM_KEY_TEST` | Optional; used by `src/utils/datalayer.js` if present |
|
|
70
|
+
|
|
71
|
+
`REACT_APP_BASENAME` is injected at build time from the client webpack config (static asset path segment).
|
|
72
|
+
|
|
73
|
+
## Scripts
|
|
74
|
+
|
|
75
|
+
| Command | Description |
|
|
76
|
+
|---------|-------------|
|
|
77
|
+
| `yarn start` | Rebuild and run the Express server (see `server-launcher.js`) |
|
|
78
|
+
| `yarn build` | Production-oriented client + server **webpack** build (`CMS_ENV=local`) |
|
|
79
|
+
| `yarn build:package` | **Library** build to `package-dist/` (tsup + types); required before `npm publish` |
|
|
80
|
+
| `yarn test` | Jest + coverage |
|
|
81
|
+
| `yarn lint` | ESLint on `src/` |
|
|
82
|
+
|
|
83
|
+
## Host integration (Module Federation)
|
|
84
|
+
|
|
85
|
+
| Item | Value |
|
|
86
|
+
|------|--------|
|
|
87
|
+
| Remote / global name | `header_mfe` (`globalThis['header_mfe']` on the server remote) |
|
|
88
|
+
| Static public path | `/static/header-mfe/` |
|
|
89
|
+
| Exposed module | `./App` only |
|
|
90
|
+
|
|
91
|
+
The host must load `remoteEntry.js` and consume the `./App` expose.
|
|
92
|
+
|
|
93
|
+
Router **basename** in MFE mode follows `/:country/:language` from the URL (see `src/utils/locale.js`). Standalone dev uses the same; non-MFE basename includes `/static/header-mfe` for static hosting scenarios.
|
|
94
|
+
|
|
95
|
+
## Contentstack
|
|
96
|
+
|
|
97
|
+
- `src/utils/contentstack.js` — stack proxy, `getContent`, `initLivePreview`, `onEntryChange`, `isEditingMode`
|
|
98
|
+
- `src/utils/config.js` — `getStackConfig()` reads `CONTENTSTACK_HEADER_CONTENT_TYPE` and locale from the URL
|
|
99
|
+
- `src/constants.js` — `referenceFields` (empty; TODO when the header model uses references), `VB_EmptyBlockParentClass` for Visual Builder empty blocks
|
|
100
|
+
|
|
101
|
+
No header entry is fetched in the UI yet; wire `getContent` when the slug/UID strategy is decided.
|
|
102
|
+
|
|
103
|
+
## GitLab CI
|
|
104
|
+
|
|
105
|
+
- **`npm-module-ci.yml`** — release / pre-release publish to npmjs (`PRIVATE_NPM: "false"`); runs `yarn build:package` before publish.
|
|
106
|
+
- **`static-client-app.yml`** — static MFE deploy; `APP_NAME` / `CONTENT_TYPE_UID` are set for that pipeline.
|
|
107
|
+
|
|
108
|
+
## Local HTTPS / Storefront
|
|
109
|
+
|
|
110
|
+
If your team still integrates with Storefront UI over HTTPS and a hosts file entry (e.g. `local.nuskin.com`), align URLs and micro-frontend resolution with that app’s documentation. This repo does not ship Storefront config.
|
|
111
|
+
|
|
112
|
+
## License
|
|
113
|
+
|
|
114
|
+
ISC
|