@ecomcx/nexus-theme-sdk 0.0.0-stage → 1.24.0

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.
Files changed (52) hide show
  1. package/dist/api.d.ts +92 -0
  2. package/dist/api.js +149 -0
  3. package/dist/auth-forms.d.ts +83 -0
  4. package/dist/auth-forms.js +206 -0
  5. package/dist/auth-pages.d.ts +6 -0
  6. package/dist/auth-pages.js +33 -0
  7. package/dist/auth-shared.d.ts +14 -0
  8. package/dist/auth-shared.js +7 -0
  9. package/dist/auth.d.ts +16 -0
  10. package/dist/auth.js +48 -0
  11. package/dist/client.d.ts +102 -0
  12. package/dist/client.js +191 -0
  13. package/dist/components.d.ts +68 -0
  14. package/dist/components.js +154 -0
  15. package/dist/content.d.ts +25 -0
  16. package/dist/content.js +59 -0
  17. package/dist/dynamic.d.ts +9 -0
  18. package/dist/dynamic.js +128 -0
  19. package/dist/i18n.d.ts +11 -0
  20. package/dist/i18n.js +104 -0
  21. package/dist/image.d.ts +24 -0
  22. package/dist/image.js +37 -0
  23. package/dist/index.d.ts +19 -0
  24. package/dist/index.js +21 -0
  25. package/dist/locale.d.ts +9 -0
  26. package/dist/locale.js +20 -0
  27. package/dist/metadata.d.ts +3 -0
  28. package/dist/metadata.js +26 -0
  29. package/dist/page-canvas.d.ts +4 -0
  30. package/dist/page-canvas.js +7 -0
  31. package/dist/page-full-width.d.ts +3 -0
  32. package/dist/page-full-width.js +6 -0
  33. package/dist/plugin-form-client.d.ts +27 -0
  34. package/dist/plugin-form-client.js +55 -0
  35. package/dist/plugin-form.d.ts +15 -0
  36. package/dist/plugin-form.js +25 -0
  37. package/dist/preferences.d.ts +9 -0
  38. package/dist/preferences.js +17 -0
  39. package/dist/rich.d.ts +66 -0
  40. package/dist/rich.js +388 -0
  41. package/dist/runtime.d.ts +58 -0
  42. package/dist/runtime.js +238 -0
  43. package/dist/social-icons.d.ts +5 -0
  44. package/dist/social-icons.js +21 -0
  45. package/dist/template-blocks.d.ts +3 -0
  46. package/dist/template-blocks.js +11 -0
  47. package/dist/types.d.ts +475 -0
  48. package/dist/types.js +1 -0
  49. package/dist/utils.d.ts +8 -0
  50. package/dist/utils.js +29 -0
  51. package/package.json +62 -4
  52. package/README.md +0 -3
@@ -0,0 +1,475 @@
1
+ import type { ComponentType, ReactNode } from "react";
2
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
3
+ [k: string]: JsonValue;
4
+ };
5
+ export type JsonObject = {
6
+ [k: string]: JsonValue;
7
+ };
8
+ export interface Author {
9
+ id: number;
10
+ name: string;
11
+ slug: string;
12
+ avatarUrl?: string | null;
13
+ bio?: string | null;
14
+ }
15
+ export interface MediaSize {
16
+ url: string;
17
+ width: number;
18
+ height: number;
19
+ webpUrl?: string | null;
20
+ }
21
+ export interface Media {
22
+ id: number;
23
+ url: string;
24
+ fileName: string;
25
+ mimeType: string;
26
+ size: number;
27
+ width?: number | null;
28
+ height?: number | null;
29
+ alt: string;
30
+ caption: string;
31
+ sizes: Record<string, MediaSize>;
32
+ /** Bản WebP của ảnh gốc. */
33
+ webpUrl?: string | null;
34
+ /** Điểm lấy nét 0–1 (object-position). */
35
+ focalX?: number | null;
36
+ focalY?: number | null;
37
+ }
38
+ export interface Term {
39
+ id: number;
40
+ taxonomy: string;
41
+ name: string;
42
+ slug: string;
43
+ locale: string;
44
+ description: string;
45
+ parentId?: number | null;
46
+ count: number;
47
+ link: string;
48
+ meta: JsonObject;
49
+ /** Dữ liệu plugin thêm vào qua filter api.term.response (vd extra.seo). */
50
+ extra?: JsonObject;
51
+ }
52
+ /** Một block nội dung. Hiện tại core có: richtext (TipTap JSON) và html. */
53
+ /** Định dạng nội dung của CMS — xem @ecomcx/nexus-content. */
54
+ export type { Block, ContentDoc as PostContentDoc, RichNode, RichMark } from "@ecomcx/nexus-content";
55
+ import type { Block, ContentDoc as PostContentDoc } from "@ecomcx/nexus-content";
56
+ export interface TranslationRef {
57
+ locale: string;
58
+ id: number;
59
+ title: string;
60
+ status: string;
61
+ link: string;
62
+ }
63
+ export interface Post {
64
+ id: number;
65
+ type: string;
66
+ title: string;
67
+ slug: string;
68
+ status: string;
69
+ /** Mã ngôn ngữ của bài, vd "vi". */
70
+ locale: string;
71
+ /** Bản dịch đã đăng ở ngôn ngữ khác. */
72
+ translations: TranslationRef[];
73
+ content?: PostContentDoc | null;
74
+ excerpt: string;
75
+ authorId?: number | null;
76
+ author?: Author | null;
77
+ parentId?: number | null;
78
+ menuOrder: number;
79
+ template?: string | null;
80
+ featuredMedia?: Media | null;
81
+ commentStatus: string;
82
+ commentCount: number;
83
+ /** Bài ghim / nổi bật. */
84
+ sticky: boolean;
85
+ /** Bài có mật khẩu: chưa mở khoá thì content = null, excerpt rỗng — PostContent tự hiện form nhập mật khẩu. */
86
+ passwordProtected?: boolean;
87
+ publishedAt?: string | null;
88
+ createdAt: string;
89
+ updatedAt: string;
90
+ link: string;
91
+ meta: JsonObject;
92
+ terms: Record<string, Term[]>;
93
+ /** Dữ liệu plugin thêm vào qua filter api.post.response (vd extra.seo). */
94
+ extra: JsonObject;
95
+ }
96
+ export interface Language {
97
+ code: string;
98
+ name: string;
99
+ isDefault: boolean;
100
+ flag?: string | null;
101
+ }
102
+ export interface Site {
103
+ title: string;
104
+ tagline: string;
105
+ url: string;
106
+ language: string;
107
+ timezone: string;
108
+ dateFormat: string;
109
+ /** Ngôn ngữ của request hiện tại. */
110
+ locale: string;
111
+ defaultLocale: string;
112
+ languages: Language[];
113
+ postsPerPage: number;
114
+ showOnFront: "posts" | "page";
115
+ pageOnFront?: number | null;
116
+ pageForPosts?: number | null;
117
+ activeTheme: string;
118
+ themeSettings: JsonObject;
119
+ activePlugins: string[];
120
+ menuLocations: Record<string, number>;
121
+ extra: JsonObject;
122
+ /** Preset kiểu dáng đã gộp (theme.json › styles + bản sửa trong Giao diện › Kiểu dáng) — core sinh biến CSS --ecx-*. */
123
+ themeStyles?: {
124
+ colors?: Record<string, string>;
125
+ fontSizes?: Record<string, string>;
126
+ spacing?: Record<string, string>;
127
+ fonts?: Record<string, string>;
128
+ };
129
+ /** false = website yêu cầu máy tìm kiếm không index. */
130
+ indexable?: boolean;
131
+ /** Website chưa qua màn hình cài đặt lần đầu. */
132
+ setupRequired?: boolean;
133
+ }
134
+ export interface MenuItem {
135
+ id: number;
136
+ parentId?: number | null;
137
+ title: string;
138
+ url: string;
139
+ kind: string;
140
+ objectId?: number | null;
141
+ target?: string | null;
142
+ cssClass?: string | null;
143
+ order: number;
144
+ children: MenuItem[];
145
+ }
146
+ export interface Menu {
147
+ id: number;
148
+ name: string;
149
+ slug: string;
150
+ items: MenuItem[];
151
+ locations: string[];
152
+ }
153
+ export interface WidgetInstance {
154
+ id: number;
155
+ area: string;
156
+ type: string;
157
+ title: string;
158
+ settings: any;
159
+ order: number;
160
+ }
161
+ export interface Comment {
162
+ id: number;
163
+ postId: number;
164
+ parentId?: number | null;
165
+ authorName: string;
166
+ authorUrl?: string | null;
167
+ content: string;
168
+ status: string;
169
+ createdAt: string;
170
+ replies: Comment[];
171
+ /** Ảnh đại diện (ảnh của thành viên hoặc Gravatar); null khi site tắt hiển thị avatar. */
172
+ avatarUrl?: string | null;
173
+ }
174
+ /** Một trang bình luận gốc (kèm trả lời). total = số bình luận gốc, count = tổng kể cả trả lời. */
175
+ export interface CommentPage {
176
+ items: Comment[];
177
+ total: number;
178
+ count: number;
179
+ page: number;
180
+ totalPages: number;
181
+ }
182
+ export type ResolveKind = "front-page" | "home" | "single" | "page" | "category" | "tag" | "taxonomy" | "author" | "date" | "archive" | "search" | "route" | "404" | "redirect";
183
+ export interface ResolveResult {
184
+ kind: ResolveKind;
185
+ templates: string[];
186
+ title: string;
187
+ locale: string;
188
+ /** Trang tương ứng ở các ngôn ngữ (dùng cho hreflang, nút chuyển ngôn ngữ). */
189
+ alternates: Array<{
190
+ locale: string;
191
+ link: string;
192
+ }>;
193
+ post?: Post | null;
194
+ posts?: Post[] | null;
195
+ term?: Term | null;
196
+ author?: Author | null;
197
+ postType?: string | null;
198
+ search?: string | null;
199
+ page: number;
200
+ totalPages: number;
201
+ total: number;
202
+ basePath: string;
203
+ redirect?: {
204
+ location: string;
205
+ statusCode: number;
206
+ } | null;
207
+ isPreview?: boolean;
208
+ /** Trang ảo (kind = "route") do core/plugin đăng ký: /login, /account/orders/12 → { name: "account", rest: "orders/12" }. */
209
+ route?: {
210
+ name: string;
211
+ path: string;
212
+ rest: string;
213
+ owner: string;
214
+ } | null;
215
+ /** Không cho máy tìm kiếm index. */
216
+ noIndex?: boolean;
217
+ }
218
+ /** Props mà mọi template của theme nhận được. */
219
+ export interface TemplateProps {
220
+ data: ResolveResult;
221
+ site: Site;
222
+ settings: JsonObject;
223
+ /** Tên template đã được chọn (vd "single"). */
224
+ template: string;
225
+ }
226
+ export interface LayoutProps {
227
+ site: Site;
228
+ settings: JsonObject;
229
+ children: ReactNode;
230
+ /** Trang đang xem — truyền cho <EditableRegion data={data}> để vùng (và plugin thay vùng) biết trang nào. */
231
+ data?: ResolveResult;
232
+ }
233
+ export interface ThemeManifest {
234
+ name: string;
235
+ slug: string;
236
+ version: string;
237
+ author?: string;
238
+ description?: string;
239
+ parent?: string | null;
240
+ menuLocations?: Record<string, string>;
241
+ widgetAreas?: Record<string, string>;
242
+ supports?: string[];
243
+ settings?: Array<{
244
+ key: string;
245
+ type: string;
246
+ label: string;
247
+ default?: JsonValue;
248
+ options?: string[];
249
+ section?: string;
250
+ help?: string;
251
+ }>;
252
+ /** Cỡ ảnh riêng của theme: { "card": { "width": 600, "height": 400, "crop": true } }. */
253
+ imageSizes?: Record<string, {
254
+ width: number;
255
+ height?: number;
256
+ crop?: boolean;
257
+ }>;
258
+ pageTemplates?: Record<string, string>;
259
+ /** Cách dựng giao diện: "code" (mặc định, .tsx), "hybrid" (code + vùng sửa được), "blocks" (template/phần dựng bằng khối, sửa trong Trình dựng). */
260
+ editing?: "code" | "hybrid" | "blocks";
261
+ /** Vùng sửa được của theme hybrid: { header: "Đầu trang" } — vẽ bằng <EditableRegion name="header">, sửa trong Trình dựng. */
262
+ regions?: Record<string, string>;
263
+ /** Preset kiểu dáng: { colors: { primary: { label, value } | "#hex" }, fontSizes, spacing, fonts }. */
264
+ styles?: Record<string, Record<string, string | {
265
+ label?: string;
266
+ value: string;
267
+ }>>;
268
+ /** Biến thể kiểu theo loại khối: { table: [{ name: "bordered", label: "%…%" }] } → class .ecx-is-<name>. */
269
+ blockStyles?: Record<string, Array<{
270
+ name: string;
271
+ label: string;
272
+ }>>;
273
+ /** Trang theme cần có: kích hoạt theme thì CMS tạo trang còn thiếu. locked = theme vẽ toàn bộ, trình soạn chỉ sửa tiêu đề/đường dẫn/SEO. */
274
+ pages?: Array<{
275
+ slug: string;
276
+ title: string;
277
+ template?: string;
278
+ locked?: boolean;
279
+ }>;
280
+ [key: string]: unknown;
281
+ }
282
+ type Loader<T> = () => Promise<{
283
+ default: T;
284
+ }>;
285
+ export interface ThemeEntry {
286
+ manifest: ThemeManifest;
287
+ layout?: Loader<ComponentType<LayoutProps>>;
288
+ templates: Record<string, Loader<ComponentType<TemplateProps>>>;
289
+ /** Theme cũng có thể đăng ký shortcode, widget, slot, filter. */
290
+ extend?: Loader<PluginDefinition>;
291
+ /** Bản dịch chữ của theme: locales/{code}.json */
292
+ locales?: Record<string, Loader<Record<string, string>>>;
293
+ }
294
+ export type PluginLoader = Loader<PluginDefinition>;
295
+ export interface ShortcodeProps {
296
+ attrs: Record<string, string>;
297
+ content?: string;
298
+ site: Site;
299
+ post?: Post | null;
300
+ }
301
+ export interface WidgetProps<S = any> {
302
+ widget: WidgetInstance;
303
+ settings: S;
304
+ site: Site;
305
+ }
306
+ export interface SlotProps {
307
+ site: Site;
308
+ data?: ResolveResult | null;
309
+ }
310
+ /**
311
+ * Renderer khối của plugin. Dùng cho cả khối cấp cao nhất (`data` = dữ liệu khối) và nút trong nội dung soạn thảo
312
+ * (`data` = thuộc tính của nút, `children` = nội dung bên trong đã vẽ — vd hộp lưu ý chứa đoạn văn).
313
+ */
314
+ export interface BlockProps<D = any> {
315
+ block: Block;
316
+ data: D;
317
+ site: Site;
318
+ post?: Post | null;
319
+ children?: ReactNode;
320
+ }
321
+ export interface DocumentMetadata {
322
+ title: string;
323
+ description?: string;
324
+ canonical?: string;
325
+ /** Bản dịch của trang: { vi: "/chao-mung", en: "/en/welcome" } → thẻ hreflang. */
326
+ alternates?: Record<string, string>;
327
+ robots?: string;
328
+ openGraph?: {
329
+ title?: string;
330
+ description?: string;
331
+ image?: string;
332
+ type?: string;
333
+ url?: string;
334
+ /** Nhiều ảnh kèm kích thước (ưu tiên hơn `image`). */
335
+ images?: Array<{
336
+ url: string;
337
+ width?: number;
338
+ height?: number;
339
+ alt?: string;
340
+ }>;
341
+ siteName?: string;
342
+ locale?: string;
343
+ /** Bài viết (type = article). */
344
+ publishedTime?: string;
345
+ modifiedTime?: string;
346
+ section?: string;
347
+ tags?: string[];
348
+ authors?: string[];
349
+ };
350
+ twitter?: {
351
+ card?: "summary" | "summary_large_image";
352
+ title?: string;
353
+ description?: string;
354
+ image?: string;
355
+ site?: string;
356
+ creator?: string;
357
+ };
358
+ /** Mã xác minh chủ sở hữu (Google Search Console, Bing, Yandex…): { google: "...", other: { "msvalidate.01": "..." } }. */
359
+ verification?: {
360
+ google?: string;
361
+ yandex?: string;
362
+ yahoo?: string;
363
+ other?: Record<string, string>;
364
+ };
365
+ /** Thẻ meta khác: { name: content }. */
366
+ extra?: Record<string, string>;
367
+ }
368
+ /** Một URL trong sitemap.xml (filter "sitemap.entries"). */
369
+ export interface SitemapEntry {
370
+ url: string;
371
+ lastModified?: string | Date;
372
+ changeFrequency?: "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
373
+ priority?: number;
374
+ images?: string[];
375
+ alternates?: {
376
+ languages?: Record<string, string>;
377
+ };
378
+ }
379
+ /** Route gốc do plugin cung cấp (vd /news-sitemap.xml): nhận Request, trả Response. Khai báo đường dẫn trong plugin.json → frontend.routes. */
380
+ export type PluginRoute = (req: Request, ctx: {
381
+ site: Site;
382
+ path: string;
383
+ }) => Response | Promise<Response>;
384
+ /**
385
+ * Slot chuẩn. Core: head, body.start, body.end, footer. Theme: before.content, after.content.
386
+ * Component của SDK: comments.before / comments.after (khu bình luận), comment_form.fields (ô thêm trong form bình luận),
387
+ * auth.login.fields, auth.register.fields, auth.forgot_password.fields (ô thêm trong form tài khoản, vd captcha).
388
+ * Ô thêm có name="extra.*" được gửi kèm trong "extra" — backend đọc ở action auth.attempt / filter comment.data.
389
+ */
390
+ export type CoreSlotName = "head" | "body.start" | "body.end" | "before.content" | "after.content" | "footer" | "comments.before" | "comments.after" | "comment_form.fields" | "auth.login.fields" | "auth.register.fields" | "auth.forgot_password.fields";
391
+ export type SlotName = CoreSlotName | (string & {});
392
+ /**
393
+ * Vùng chuẩn của core: theme bọc đầu trang / chân trang trong <EditableRegion name="header|footer">
394
+ * (theme khối: khối templatePart cùng slug) → plugin thay được bằng definePlugin({ regions }) với mọi theme.
395
+ */
396
+ export type RegionName = "header" | "footer" | (string & {});
397
+ /** Component thay vùng của plugin. `children` = bản vùng sẽ vẽ nếu không có plugin (Trình dựng / theme) — trả lại `children` để giữ nguyên. */
398
+ export interface RegionProps {
399
+ name: string;
400
+ site: Site;
401
+ data?: ResolveResult | null;
402
+ children?: ReactNode;
403
+ }
404
+ /** Một handler gắn vào Slot, kèm priority (mặc định 10, số nhỏ chạy trước). */
405
+ export interface SlotHandler<P = any> {
406
+ component: ComponentType<P>;
407
+ priority?: number;
408
+ }
409
+ export type SlotComponent<P = any> = ComponentType<P> | SlotHandler<P>;
410
+ export type SlotRegistration<P = any> = SlotComponent<P> | Array<SlotComponent<P>>;
411
+ export interface FilterMap {
412
+ /** Sửa metadata của trang (title, description, og…). */
413
+ "document.metadata": (meta: DocumentMetadata, ctx: {
414
+ site: Site;
415
+ data: ResolveResult;
416
+ }) => DocumentMetadata | Promise<DocumentMetadata>;
417
+ /** Sửa danh sách block trước khi render nội dung bài viết. */
418
+ "post.blocks": (blocks: Block[], ctx: {
419
+ site: Site;
420
+ post?: Post | null;
421
+ }) => Block[] | Promise<Block[]>;
422
+ /** Sửa nội dung robots.txt (văn bản). */
423
+ "robots.txt": (content: string, ctx: {
424
+ site: Site;
425
+ }) => string | Promise<string>;
426
+ /** Sửa danh sách URL của sitemap.xml. */
427
+ "sitemap.entries": (entries: SitemapEntry[], ctx: {
428
+ site: Site;
429
+ }) => SitemapEntry[] | Promise<SitemapEntry[]>;
430
+ /** Thêm/bớt class của thẻ <body> (vd "logged-in", "has-promo-bar") */
431
+ "body.class": (classes: string[], ctx: {
432
+ site: Site;
433
+ }) => string[] | Promise<string[]>;
434
+ /** Cho phép các filter tùy biến bất kỳ của plugin/theme */
435
+ [customFilter: string]: ((val: any, ctx?: any) => any) | undefined;
436
+ }
437
+ export interface PluginDefinition {
438
+ /** [contact-form id="1"] trong nội dung → component. */
439
+ shortcodes?: Record<string, ComponentType<ShortcodeProps>>;
440
+ /** Renderer cho loại widget đã khai báo ở backend (IWidgetRegistry). */
441
+ widgets?: Record<string, ComponentType<WidgetProps>>;
442
+ /** Chèn component vào vị trí cố định của trang (hỗ trợ tên tự do, ưu tiên priority). */
443
+ slots?: Record<string, SlotRegistration<any>>;
444
+ /**
445
+ * Thay cả một vùng của theme (header, footer hoặc vùng theme khai báo): { header: MyHeader }.
446
+ * Nhiều plugin cùng thay một vùng → priority nhỏ nhất thắng (mặc định 10; bằng nhau thì plugin trước theme).
447
+ */
448
+ regions?: Record<string, ComponentType<RegionProps> | SlotHandler<RegionProps>>;
449
+ /** Biến đổi dữ liệu qua chuỗi filter (applyFilters). */
450
+ filters?: {
451
+ [K in keyof FilterMap]?: FilterMap[K];
452
+ };
453
+ /** Lắng nghe action phát ra từ theme/plugin (doAction). */
454
+ actions?: Record<string, ((...args: any[]) => void | Promise<void>) | Array<{
455
+ handler: (...args: any[]) => void | Promise<void>;
456
+ priority?: number;
457
+ }>>;
458
+ /** Renderer khối của plugin (theo tên khối) — khối cấp cao nhất và khối trong nội dung soạn thảo (defineBlock). */
459
+ blocks?: Record<string, ComponentType<BlockProps>>;
460
+ /** Định nghĩa khối (defineBlock, file dùng chung với phần admin) — website chuẩn hoá thuộc tính + nâng phiên bản trước khi vẽ. */
461
+ blockTypes?: import("@ecomcx/nexus-content").BlockDefinition[];
462
+ /** File ở gốc website: { "/news-sitemap.xml": handler }. Đường dẫn phải khai báo trong plugin.json → frontend.routes. */
463
+ routes?: Record<string, PluginRoute>;
464
+ /**
465
+ * Hàm công bố cho theme và plugin khác dùng (chạy phía server):
466
+ * definePlugin({ exports: { getCart, formatPrice } })
467
+ * const shop = await getPlugin<ShopApi>("shop"); await shop?.getCart();
468
+ */
469
+ exports?: Record<string, unknown>;
470
+ /**
471
+ * Template của plugin (trang sản phẩm, giỏ hàng, tài khoản…). Gán `Component.layout = false` để không bọc trong layout của theme. Theme có template cùng tên thì dùng của theme.
472
+ * Ưu tiên theo danh sách template của trang: tên cụ thể hơn thắng.
473
+ */
474
+ templates?: Record<string, ComponentType<TemplateProps>>;
475
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import type { Site } from "./types.js";
2
+ /** Định dạng ngày theo date_format của site (dd/MM/yyyy, yyyy-MM-dd, d MMMM, yyyy…). */
3
+ export declare function formatDate(value: string | null | undefined, site?: Pick<Site, "dateFormat" | "timezone"> & {
4
+ locale?: string;
5
+ }): string;
6
+ export declare function setting<T = string>(settings: Record<string, unknown>, key: string, fallback: T): T;
7
+ export declare function pageLink(basePath: string, page: number, search?: string | null): string;
8
+ export declare function cx(...classes: Array<string | false | null | undefined>): string;
package/dist/utils.js ADDED
@@ -0,0 +1,29 @@
1
+ /** Định dạng ngày theo date_format của site (dd/MM/yyyy, yyyy-MM-dd, d MMMM, yyyy…). */
2
+ export function formatDate(value, site) {
3
+ if (!value)
4
+ return "";
5
+ const d = new Date(value);
6
+ const tz = site?.timezone || "Asia/Ho_Chi_Minh";
7
+ const parts = Object.fromEntries(new Intl.DateTimeFormat("en-GB", { timeZone: tz, day: "2-digit", month: "2-digit", year: "numeric" })
8
+ .formatToParts(d).map((p) => [p.type, p.value]));
9
+ const monthLong = new Intl.DateTimeFormat(site?.locale ?? "vi", { timeZone: tz, month: "long" }).format(d);
10
+ const fmt = site?.dateFormat || "dd/MM/yyyy";
11
+ return fmt
12
+ .replace("yyyy", parts.year)
13
+ .replace("MMMM", monthLong)
14
+ .replace("MM", parts.month)
15
+ .replace("dd", parts.day)
16
+ .replace(/\bd\b/, String(Number(parts.day)));
17
+ }
18
+ export function setting(settings, key, fallback) {
19
+ const v = settings?.[key];
20
+ return (v === undefined || v === null || v === "" ? fallback : v);
21
+ }
22
+ export function pageLink(basePath, page, search) {
23
+ const base = basePath === "/" ? "" : basePath.replace(/\/$/, "");
24
+ const path = page <= 1 ? base || "/" : `${base}/page/${page}`;
25
+ return search ? `${path}${path.includes("?") ? "&" : "?"}s=${encodeURIComponent(search)}` : path;
26
+ }
27
+ export function cx(...classes) {
28
+ return classes.filter(Boolean).join(" ");
29
+ }
package/package.json CHANGED
@@ -1,6 +1,64 @@
1
1
  {
2
2
  "name": "@ecomcx/nexus-theme-sdk",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.24.0",
4
+ "description": "SDK để viết theme và phần frontend của plugin cho CMS",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./client": {
15
+ "types": "./dist/client.d.ts",
16
+ "import": "./dist/client.js",
17
+ "default": "./dist/client.js"
18
+ },
19
+ "./runtime": {
20
+ "types": "./dist/runtime.d.ts",
21
+ "import": "./dist/runtime.js",
22
+ "default": "./dist/runtime.js"
23
+ },
24
+ "./auth-shared": {
25
+ "types": "./dist/auth-shared.d.ts",
26
+ "import": "./dist/auth-shared.js",
27
+ "default": "./dist/auth-shared.js"
28
+ },
29
+ "./package.json": "./package.json"
30
+ },
31
+ "files": [
32
+ "dist",
33
+ "README.md"
34
+ ],
35
+ "dependencies": {
36
+ "@ecomcx/nexus-content": "^1.13.0",
37
+ "intl-messageformat": "12.1.3"
38
+ },
39
+ "peerDependencies": {
40
+ "next": ">=16",
41
+ "next-fetch-kit": ">=0.5.0",
42
+ "react": ">=19"
43
+ },
44
+ "peerDependenciesMeta": {
45
+ "next": {
46
+ "optional": true
47
+ },
48
+ "next-fetch-kit": {
49
+ "optional": true
50
+ }
51
+ },
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/Ecomcx-Jsc/ecomcx-sdk.git",
55
+ "directory": "packages/theme-sdk"
56
+ },
57
+ "homepage": "https://github.com/Ecomcx-Jsc/ecomcx-sdk#readme",
58
+ "license": "MIT",
59
+ "publishConfig": {
60
+ "access": "public",
61
+ "provenance": true
62
+ },
63
+ "sideEffects": false
64
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.