@infuro/cms-core 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/index.ts","../src/theme/registry.ts","../src/theme/renderer.ts"],"sourcesContent":["export type {\n PropType,\n PropDefinition,\n ComponentMeta,\n ThemeComponent,\n ThemeConfig,\n LayoutConfig,\n NavItem,\n NavbarConfig,\n FooterConfig,\n} from './types';\n\nexport { createTheme, buildResolver, getCatalog } from './registry';\nexport type { CatalogGroup } from './registry';\n\nexport { PageRenderer } from './renderer';\n","import type { ThemeConfig, ThemeComponent, ComponentMeta } from './types';\n\nexport function createTheme(config: ThemeConfig): ThemeConfig {\n const names = config.components.map((c) => c.meta.name);\n const duplicates = names.filter((n, i) => names.indexOf(n) !== i);\n if (duplicates.length) {\n throw new Error(`Duplicate component names in theme \"${config.name}\": ${duplicates.join(', ')}`);\n }\n return Object.freeze(config) as ThemeConfig;\n}\n\nexport function buildResolver(theme: ThemeConfig): Record<string, React.ComponentType<any>> {\n const resolver: Record<string, React.ComponentType<any>> = {};\n for (const { meta, component } of theme.components) {\n resolver[meta.name] = component;\n }\n return resolver;\n}\n\nexport interface CatalogGroup {\n category: string;\n components: ComponentMeta[];\n}\n\nexport function getCatalog(theme: ThemeConfig): CatalogGroup[] {\n const groups = new Map<string, ComponentMeta[]>();\n for (const { meta } of theme.components) {\n const list = groups.get(meta.category) || [];\n list.push(meta);\n groups.set(meta.category, list);\n }\n return Array.from(groups.entries()).map(([category, components]) => ({\n category,\n components,\n }));\n}\n","import React from 'react';\nimport type { ThemeConfig, NavbarConfig, FooterConfig } from './types';\nimport { buildResolver } from './registry';\n\ninterface CraftNode {\n type: string | { resolvedName: string };\n props: Record<string, any>;\n nodes?: string[];\n linkedNodes?: Record<string, string>;\n}\n\ntype CraftJson = Record<string, CraftNode>;\n\ninterface PageRendererProps {\n content: CraftJson;\n theme: ThemeConfig;\n navbarConfig?: NavbarConfig;\n footerConfig?: FooterConfig;\n}\n\nexport function PageRenderer({ content, theme, navbarConfig, footerConfig }: PageRendererProps) {\n const resolver = buildResolver(theme);\n const NavbarComponent = theme.layout?.navbar?.component;\n const FooterComponent = theme.layout?.footer?.component;\n\n return React.createElement(\n React.Fragment,\n null,\n NavbarComponent && navbarConfig\n ? React.createElement(NavbarComponent, navbarConfig)\n : null,\n React.createElement('main', null, renderNode(content, 'ROOT', resolver)),\n FooterComponent && footerConfig\n ? React.createElement(FooterComponent, footerConfig)\n : null,\n );\n}\n\nfunction getChildIds(node: CraftNode): string[] {\n const fromNodes = node.nodes ?? [];\n const fromLinked = Object.values(node.linkedNodes ?? {});\n return [...fromNodes, ...fromLinked];\n}\n\nfunction renderNode(\n json: CraftJson,\n nodeId: string,\n resolver: Record<string, React.ComponentType<any>>,\n): React.ReactNode {\n const node = json[nodeId];\n if (!node) return null;\n\n const resolvedName =\n typeof node.type === 'string' ? node.type : (node.type?.resolvedName ?? '');\n const Component = resolver[resolvedName];\n const childIds = getChildIds(node);\n const children = childIds.map((childId) => renderNode(json, childId, resolver));\n\n if (Component) {\n return React.createElement(Component, { key: nodeId, ...node.props }, children);\n }\n\n const tag = node.props?.is ?? 'div';\n const props = node.props ?? {};\n const safeProps: Record<string, unknown> = { key: nodeId };\n if (props.className != null) safeProps.className = props.className;\n if (props.style != null) safeProps.style = props.style;\n if (props.id != null) safeProps.id = props.id;\n return React.createElement(tag, safeProps, children);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,SAAS,YAAY,QAAkC;AAC5D,QAAM,QAAQ,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI;AACtD,QAAM,aAAa,MAAM,OAAO,CAAC,GAAG,MAAM,MAAM,QAAQ,CAAC,MAAM,CAAC;AAChE,MAAI,WAAW,QAAQ;AACrB,UAAM,IAAI,MAAM,uCAAuC,OAAO,IAAI,MAAM,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EACjG;AACA,SAAO,OAAO,OAAO,MAAM;AAC7B;AAEO,SAAS,cAAc,OAA8D;AAC1F,QAAM,WAAqD,CAAC;AAC5D,aAAW,EAAE,MAAM,UAAU,KAAK,MAAM,YAAY;AAClD,aAAS,KAAK,IAAI,IAAI;AAAA,EACxB;AACA,SAAO;AACT;AAOO,SAAS,WAAW,OAAoC;AAC7D,QAAM,SAAS,oBAAI,IAA6B;AAChD,aAAW,EAAE,KAAK,KAAK,MAAM,YAAY;AACvC,UAAM,OAAO,OAAO,IAAI,KAAK,QAAQ,KAAK,CAAC;AAC3C,SAAK,KAAK,IAAI;AACd,WAAO,IAAI,KAAK,UAAU,IAAI;AAAA,EAChC;AACA,SAAO,MAAM,KAAK,OAAO,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,UAAU,OAAO;AAAA,IACnE;AAAA,IACA;AAAA,EACF,EAAE;AACJ;;;ACnCA,mBAAkB;AAoBX,SAAS,aAAa,EAAE,SAAS,OAAO,cAAc,aAAa,GAAsB;AAC9F,QAAM,WAAW,cAAc,KAAK;AACpC,QAAM,kBAAkB,MAAM,QAAQ,QAAQ;AAC9C,QAAM,kBAAkB,MAAM,QAAQ,QAAQ;AAE9C,SAAO,aAAAA,QAAM;AAAA,IACX,aAAAA,QAAM;AAAA,IACN;AAAA,IACA,mBAAmB,eACf,aAAAA,QAAM,cAAc,iBAAiB,YAAY,IACjD;AAAA,IACJ,aAAAA,QAAM,cAAc,QAAQ,MAAM,WAAW,SAAS,QAAQ,QAAQ,CAAC;AAAA,IACvE,mBAAmB,eACf,aAAAA,QAAM,cAAc,iBAAiB,YAAY,IACjD;AAAA,EACN;AACF;AAEA,SAAS,YAAY,MAA2B;AAC9C,QAAM,YAAY,KAAK,SAAS,CAAC;AACjC,QAAM,aAAa,OAAO,OAAO,KAAK,eAAe,CAAC,CAAC;AACvD,SAAO,CAAC,GAAG,WAAW,GAAG,UAAU;AACrC;AAEA,SAAS,WACP,MACA,QACA,UACiB;AACjB,QAAM,OAAO,KAAK,MAAM;AACxB,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,eACJ,OAAO,KAAK,SAAS,WAAW,KAAK,OAAQ,KAAK,MAAM,gBAAgB;AAC1E,QAAM,YAAY,SAAS,YAAY;AACvC,QAAM,WAAW,YAAY,IAAI;AACjC,QAAM,WAAW,SAAS,IAAI,CAAC,YAAY,WAAW,MAAM,SAAS,QAAQ,CAAC;AAE9E,MAAI,WAAW;AACb,WAAO,aAAAA,QAAM,cAAc,WAAW,EAAE,KAAK,QAAQ,GAAG,KAAK,MAAM,GAAG,QAAQ;AAAA,EAChF;AAEA,QAAM,MAAM,KAAK,OAAO,MAAM;AAC9B,QAAM,QAAQ,KAAK,SAAS,CAAC;AAC7B,QAAM,YAAqC,EAAE,KAAK,OAAO;AACzD,MAAI,MAAM,aAAa,KAAM,WAAU,YAAY,MAAM;AACzD,MAAI,MAAM,SAAS,KAAM,WAAU,QAAQ,MAAM;AACjD,MAAI,MAAM,MAAM,KAAM,WAAU,KAAK,MAAM;AAC3C,SAAO,aAAAA,QAAM,cAAc,KAAK,WAAW,QAAQ;AACrD;","names":["React"]}
@@ -0,0 +1,32 @@
1
+ import { C as ComponentMeta, T as ThemeConfig, N as NavbarConfig, F as FooterConfig } from './types-D34wmivy.cjs';
2
+ export { L as LayoutConfig, a as NavItem, P as PropDefinition, b as PropType, c as ThemeComponent } from './types-D34wmivy.cjs';
3
+ import React$1 from 'react';
4
+
5
+ declare function createTheme(config: ThemeConfig): ThemeConfig;
6
+ declare function buildResolver(theme: ThemeConfig): Record<string, React.ComponentType<any>>;
7
+ interface CatalogGroup {
8
+ category: string;
9
+ components: ComponentMeta[];
10
+ }
11
+ declare function getCatalog(theme: ThemeConfig): CatalogGroup[];
12
+
13
+ interface CraftNode {
14
+ type: string | {
15
+ resolvedName: string;
16
+ };
17
+ props: Record<string, any>;
18
+ nodes?: string[];
19
+ linkedNodes?: Record<string, string>;
20
+ }
21
+ type CraftJson = Record<string, CraftNode>;
22
+ interface PageRendererProps {
23
+ content: CraftJson;
24
+ theme: ThemeConfig;
25
+ navbarConfig?: NavbarConfig;
26
+ footerConfig?: FooterConfig;
27
+ }
28
+ declare function PageRenderer({ content, theme, navbarConfig, footerConfig }: PageRendererProps): React$1.FunctionComponentElement<{
29
+ children?: React$1.ReactNode | undefined;
30
+ }>;
31
+
32
+ export { type CatalogGroup, ComponentMeta, FooterConfig, NavbarConfig, PageRenderer, ThemeConfig, buildResolver, createTheme, getCatalog };
@@ -0,0 +1,32 @@
1
+ import { C as ComponentMeta, T as ThemeConfig, N as NavbarConfig, F as FooterConfig } from './types-D34wmivy.js';
2
+ export { L as LayoutConfig, a as NavItem, P as PropDefinition, b as PropType, c as ThemeComponent } from './types-D34wmivy.js';
3
+ import React$1 from 'react';
4
+
5
+ declare function createTheme(config: ThemeConfig): ThemeConfig;
6
+ declare function buildResolver(theme: ThemeConfig): Record<string, React.ComponentType<any>>;
7
+ interface CatalogGroup {
8
+ category: string;
9
+ components: ComponentMeta[];
10
+ }
11
+ declare function getCatalog(theme: ThemeConfig): CatalogGroup[];
12
+
13
+ interface CraftNode {
14
+ type: string | {
15
+ resolvedName: string;
16
+ };
17
+ props: Record<string, any>;
18
+ nodes?: string[];
19
+ linkedNodes?: Record<string, string>;
20
+ }
21
+ type CraftJson = Record<string, CraftNode>;
22
+ interface PageRendererProps {
23
+ content: CraftJson;
24
+ theme: ThemeConfig;
25
+ navbarConfig?: NavbarConfig;
26
+ footerConfig?: FooterConfig;
27
+ }
28
+ declare function PageRenderer({ content, theme, navbarConfig, footerConfig }: PageRendererProps): React$1.FunctionComponentElement<{
29
+ children?: React$1.ReactNode | undefined;
30
+ }>;
31
+
32
+ export { type CatalogGroup, ComponentMeta, FooterConfig, NavbarConfig, PageRenderer, ThemeConfig, buildResolver, createTheme, getCatalog };
package/dist/theme.js ADDED
@@ -0,0 +1,73 @@
1
+ // src/theme/registry.ts
2
+ function createTheme(config) {
3
+ const names = config.components.map((c) => c.meta.name);
4
+ const duplicates = names.filter((n, i) => names.indexOf(n) !== i);
5
+ if (duplicates.length) {
6
+ throw new Error(`Duplicate component names in theme "${config.name}": ${duplicates.join(", ")}`);
7
+ }
8
+ return Object.freeze(config);
9
+ }
10
+ function buildResolver(theme) {
11
+ const resolver = {};
12
+ for (const { meta, component } of theme.components) {
13
+ resolver[meta.name] = component;
14
+ }
15
+ return resolver;
16
+ }
17
+ function getCatalog(theme) {
18
+ const groups = /* @__PURE__ */ new Map();
19
+ for (const { meta } of theme.components) {
20
+ const list = groups.get(meta.category) || [];
21
+ list.push(meta);
22
+ groups.set(meta.category, list);
23
+ }
24
+ return Array.from(groups.entries()).map(([category, components]) => ({
25
+ category,
26
+ components
27
+ }));
28
+ }
29
+
30
+ // src/theme/renderer.ts
31
+ import React from "react";
32
+ function PageRenderer({ content, theme, navbarConfig, footerConfig }) {
33
+ const resolver = buildResolver(theme);
34
+ const NavbarComponent = theme.layout?.navbar?.component;
35
+ const FooterComponent = theme.layout?.footer?.component;
36
+ return React.createElement(
37
+ React.Fragment,
38
+ null,
39
+ NavbarComponent && navbarConfig ? React.createElement(NavbarComponent, navbarConfig) : null,
40
+ React.createElement("main", null, renderNode(content, "ROOT", resolver)),
41
+ FooterComponent && footerConfig ? React.createElement(FooterComponent, footerConfig) : null
42
+ );
43
+ }
44
+ function getChildIds(node) {
45
+ const fromNodes = node.nodes ?? [];
46
+ const fromLinked = Object.values(node.linkedNodes ?? {});
47
+ return [...fromNodes, ...fromLinked];
48
+ }
49
+ function renderNode(json, nodeId, resolver) {
50
+ const node = json[nodeId];
51
+ if (!node) return null;
52
+ const resolvedName = typeof node.type === "string" ? node.type : node.type?.resolvedName ?? "";
53
+ const Component = resolver[resolvedName];
54
+ const childIds = getChildIds(node);
55
+ const children = childIds.map((childId) => renderNode(json, childId, resolver));
56
+ if (Component) {
57
+ return React.createElement(Component, { key: nodeId, ...node.props }, children);
58
+ }
59
+ const tag = node.props?.is ?? "div";
60
+ const props = node.props ?? {};
61
+ const safeProps = { key: nodeId };
62
+ if (props.className != null) safeProps.className = props.className;
63
+ if (props.style != null) safeProps.style = props.style;
64
+ if (props.id != null) safeProps.id = props.id;
65
+ return React.createElement(tag, safeProps, children);
66
+ }
67
+ export {
68
+ PageRenderer,
69
+ buildResolver,
70
+ createTheme,
71
+ getCatalog
72
+ };
73
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/theme/registry.ts","../src/theme/renderer.ts"],"sourcesContent":["import type { ThemeConfig, ThemeComponent, ComponentMeta } from './types';\n\nexport function createTheme(config: ThemeConfig): ThemeConfig {\n const names = config.components.map((c) => c.meta.name);\n const duplicates = names.filter((n, i) => names.indexOf(n) !== i);\n if (duplicates.length) {\n throw new Error(`Duplicate component names in theme \"${config.name}\": ${duplicates.join(', ')}`);\n }\n return Object.freeze(config) as ThemeConfig;\n}\n\nexport function buildResolver(theme: ThemeConfig): Record<string, React.ComponentType<any>> {\n const resolver: Record<string, React.ComponentType<any>> = {};\n for (const { meta, component } of theme.components) {\n resolver[meta.name] = component;\n }\n return resolver;\n}\n\nexport interface CatalogGroup {\n category: string;\n components: ComponentMeta[];\n}\n\nexport function getCatalog(theme: ThemeConfig): CatalogGroup[] {\n const groups = new Map<string, ComponentMeta[]>();\n for (const { meta } of theme.components) {\n const list = groups.get(meta.category) || [];\n list.push(meta);\n groups.set(meta.category, list);\n }\n return Array.from(groups.entries()).map(([category, components]) => ({\n category,\n components,\n }));\n}\n","import React from 'react';\nimport type { ThemeConfig, NavbarConfig, FooterConfig } from './types';\nimport { buildResolver } from './registry';\n\ninterface CraftNode {\n type: string | { resolvedName: string };\n props: Record<string, any>;\n nodes?: string[];\n linkedNodes?: Record<string, string>;\n}\n\ntype CraftJson = Record<string, CraftNode>;\n\ninterface PageRendererProps {\n content: CraftJson;\n theme: ThemeConfig;\n navbarConfig?: NavbarConfig;\n footerConfig?: FooterConfig;\n}\n\nexport function PageRenderer({ content, theme, navbarConfig, footerConfig }: PageRendererProps) {\n const resolver = buildResolver(theme);\n const NavbarComponent = theme.layout?.navbar?.component;\n const FooterComponent = theme.layout?.footer?.component;\n\n return React.createElement(\n React.Fragment,\n null,\n NavbarComponent && navbarConfig\n ? React.createElement(NavbarComponent, navbarConfig)\n : null,\n React.createElement('main', null, renderNode(content, 'ROOT', resolver)),\n FooterComponent && footerConfig\n ? React.createElement(FooterComponent, footerConfig)\n : null,\n );\n}\n\nfunction getChildIds(node: CraftNode): string[] {\n const fromNodes = node.nodes ?? [];\n const fromLinked = Object.values(node.linkedNodes ?? {});\n return [...fromNodes, ...fromLinked];\n}\n\nfunction renderNode(\n json: CraftJson,\n nodeId: string,\n resolver: Record<string, React.ComponentType<any>>,\n): React.ReactNode {\n const node = json[nodeId];\n if (!node) return null;\n\n const resolvedName =\n typeof node.type === 'string' ? node.type : (node.type?.resolvedName ?? '');\n const Component = resolver[resolvedName];\n const childIds = getChildIds(node);\n const children = childIds.map((childId) => renderNode(json, childId, resolver));\n\n if (Component) {\n return React.createElement(Component, { key: nodeId, ...node.props }, children);\n }\n\n const tag = node.props?.is ?? 'div';\n const props = node.props ?? {};\n const safeProps: Record<string, unknown> = { key: nodeId };\n if (props.className != null) safeProps.className = props.className;\n if (props.style != null) safeProps.style = props.style;\n if (props.id != null) safeProps.id = props.id;\n return React.createElement(tag, safeProps, children);\n}\n"],"mappings":";AAEO,SAAS,YAAY,QAAkC;AAC5D,QAAM,QAAQ,OAAO,WAAW,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI;AACtD,QAAM,aAAa,MAAM,OAAO,CAAC,GAAG,MAAM,MAAM,QAAQ,CAAC,MAAM,CAAC;AAChE,MAAI,WAAW,QAAQ;AACrB,UAAM,IAAI,MAAM,uCAAuC,OAAO,IAAI,MAAM,WAAW,KAAK,IAAI,CAAC,EAAE;AAAA,EACjG;AACA,SAAO,OAAO,OAAO,MAAM;AAC7B;AAEO,SAAS,cAAc,OAA8D;AAC1F,QAAM,WAAqD,CAAC;AAC5D,aAAW,EAAE,MAAM,UAAU,KAAK,MAAM,YAAY;AAClD,aAAS,KAAK,IAAI,IAAI;AAAA,EACxB;AACA,SAAO;AACT;AAOO,SAAS,WAAW,OAAoC;AAC7D,QAAM,SAAS,oBAAI,IAA6B;AAChD,aAAW,EAAE,KAAK,KAAK,MAAM,YAAY;AACvC,UAAM,OAAO,OAAO,IAAI,KAAK,QAAQ,KAAK,CAAC;AAC3C,SAAK,KAAK,IAAI;AACd,WAAO,IAAI,KAAK,UAAU,IAAI;AAAA,EAChC;AACA,SAAO,MAAM,KAAK,OAAO,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,UAAU,OAAO;AAAA,IACnE;AAAA,IACA;AAAA,EACF,EAAE;AACJ;;;ACnCA,OAAO,WAAW;AAoBX,SAAS,aAAa,EAAE,SAAS,OAAO,cAAc,aAAa,GAAsB;AAC9F,QAAM,WAAW,cAAc,KAAK;AACpC,QAAM,kBAAkB,MAAM,QAAQ,QAAQ;AAC9C,QAAM,kBAAkB,MAAM,QAAQ,QAAQ;AAE9C,SAAO,MAAM;AAAA,IACX,MAAM;AAAA,IACN;AAAA,IACA,mBAAmB,eACf,MAAM,cAAc,iBAAiB,YAAY,IACjD;AAAA,IACJ,MAAM,cAAc,QAAQ,MAAM,WAAW,SAAS,QAAQ,QAAQ,CAAC;AAAA,IACvE,mBAAmB,eACf,MAAM,cAAc,iBAAiB,YAAY,IACjD;AAAA,EACN;AACF;AAEA,SAAS,YAAY,MAA2B;AAC9C,QAAM,YAAY,KAAK,SAAS,CAAC;AACjC,QAAM,aAAa,OAAO,OAAO,KAAK,eAAe,CAAC,CAAC;AACvD,SAAO,CAAC,GAAG,WAAW,GAAG,UAAU;AACrC;AAEA,SAAS,WACP,MACA,QACA,UACiB;AACjB,QAAM,OAAO,KAAK,MAAM;AACxB,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,eACJ,OAAO,KAAK,SAAS,WAAW,KAAK,OAAQ,KAAK,MAAM,gBAAgB;AAC1E,QAAM,YAAY,SAAS,YAAY;AACvC,QAAM,WAAW,YAAY,IAAI;AACjC,QAAM,WAAW,SAAS,IAAI,CAAC,YAAY,WAAW,MAAM,SAAS,QAAQ,CAAC;AAE9E,MAAI,WAAW;AACb,WAAO,MAAM,cAAc,WAAW,EAAE,KAAK,QAAQ,GAAG,KAAK,MAAM,GAAG,QAAQ;AAAA,EAChF;AAEA,QAAM,MAAM,KAAK,OAAO,MAAM;AAC9B,QAAM,QAAQ,KAAK,SAAS,CAAC;AAC7B,QAAM,YAAqC,EAAE,KAAK,OAAO;AACzD,MAAI,MAAM,aAAa,KAAM,WAAU,YAAY,MAAM;AACzD,MAAI,MAAM,SAAS,KAAM,WAAU,QAAQ,MAAM;AACjD,MAAI,MAAM,MAAM,KAAM,WAAU,KAAK,MAAM;AAC3C,SAAO,MAAM,cAAc,KAAK,WAAW,QAAQ;AACrD;","names":[]}
@@ -0,0 +1,78 @@
1
+ type PropType = 'text' | 'textarea' | 'richtext' | 'image' | 'color' | 'select' | 'number' | 'boolean' | 'url' | 'entity';
2
+ interface PropDefinition {
3
+ name: string;
4
+ label: string;
5
+ type: PropType;
6
+ options?: {
7
+ label: string;
8
+ value: string;
9
+ }[];
10
+ entity?: string;
11
+ displayField?: string;
12
+ required?: boolean;
13
+ }
14
+ interface ComponentMeta {
15
+ name: string;
16
+ label: string;
17
+ category: string;
18
+ icon: string;
19
+ description: string;
20
+ defaultProps: Record<string, any>;
21
+ props?: PropDefinition[];
22
+ canContainChildren?: boolean;
23
+ }
24
+ interface ThemeComponent {
25
+ meta: ComponentMeta;
26
+ component: React.ComponentType<any>;
27
+ }
28
+ interface NavItem {
29
+ id: string;
30
+ label: string;
31
+ url: string;
32
+ openInNewTab?: boolean;
33
+ /** When set, url is derived from the linked page slug. */
34
+ pageId?: number;
35
+ children?: NavItem[];
36
+ }
37
+ interface NavbarConfig {
38
+ logo: string;
39
+ items: NavItem[];
40
+ ctaLabel?: string;
41
+ ctaUrl?: string;
42
+ /** Optional variant for theme-specific layout (e.g. "page2"). */
43
+ variant?: string;
44
+ }
45
+ interface FooterConfig {
46
+ copyright: string;
47
+ columns: {
48
+ title: string;
49
+ links: {
50
+ label: string;
51
+ url: string;
52
+ }[];
53
+ }[];
54
+ socialLinks: {
55
+ icon: string;
56
+ url: string;
57
+ }[];
58
+ /** When set, footer shows this logo (e.g. same as navbar). */
59
+ logo?: string;
60
+ }
61
+ interface LayoutConfig {
62
+ navbar?: {
63
+ component: React.ComponentType<NavbarConfig>;
64
+ };
65
+ footer?: {
66
+ component: React.ComponentType<FooterConfig>;
67
+ fields: PropDefinition[];
68
+ defaults: Record<string, any>;
69
+ };
70
+ }
71
+ interface ThemeConfig {
72
+ name: string;
73
+ label: string;
74
+ components: ThemeComponent[];
75
+ layout?: LayoutConfig;
76
+ }
77
+
78
+ export type { ComponentMeta as C, FooterConfig as F, LayoutConfig as L, NavbarConfig as N, PropDefinition as P, ThemeConfig as T, NavItem as a, PropType as b, ThemeComponent as c };
@@ -0,0 +1,78 @@
1
+ type PropType = 'text' | 'textarea' | 'richtext' | 'image' | 'color' | 'select' | 'number' | 'boolean' | 'url' | 'entity';
2
+ interface PropDefinition {
3
+ name: string;
4
+ label: string;
5
+ type: PropType;
6
+ options?: {
7
+ label: string;
8
+ value: string;
9
+ }[];
10
+ entity?: string;
11
+ displayField?: string;
12
+ required?: boolean;
13
+ }
14
+ interface ComponentMeta {
15
+ name: string;
16
+ label: string;
17
+ category: string;
18
+ icon: string;
19
+ description: string;
20
+ defaultProps: Record<string, any>;
21
+ props?: PropDefinition[];
22
+ canContainChildren?: boolean;
23
+ }
24
+ interface ThemeComponent {
25
+ meta: ComponentMeta;
26
+ component: React.ComponentType<any>;
27
+ }
28
+ interface NavItem {
29
+ id: string;
30
+ label: string;
31
+ url: string;
32
+ openInNewTab?: boolean;
33
+ /** When set, url is derived from the linked page slug. */
34
+ pageId?: number;
35
+ children?: NavItem[];
36
+ }
37
+ interface NavbarConfig {
38
+ logo: string;
39
+ items: NavItem[];
40
+ ctaLabel?: string;
41
+ ctaUrl?: string;
42
+ /** Optional variant for theme-specific layout (e.g. "page2"). */
43
+ variant?: string;
44
+ }
45
+ interface FooterConfig {
46
+ copyright: string;
47
+ columns: {
48
+ title: string;
49
+ links: {
50
+ label: string;
51
+ url: string;
52
+ }[];
53
+ }[];
54
+ socialLinks: {
55
+ icon: string;
56
+ url: string;
57
+ }[];
58
+ /** When set, footer shows this logo (e.g. same as navbar). */
59
+ logo?: string;
60
+ }
61
+ interface LayoutConfig {
62
+ navbar?: {
63
+ component: React.ComponentType<NavbarConfig>;
64
+ };
65
+ footer?: {
66
+ component: React.ComponentType<FooterConfig>;
67
+ fields: PropDefinition[];
68
+ defaults: Record<string, any>;
69
+ };
70
+ }
71
+ interface ThemeConfig {
72
+ name: string;
73
+ label: string;
74
+ components: ThemeComponent[];
75
+ layout?: LayoutConfig;
76
+ }
77
+
78
+ export type { ComponentMeta as C, FooterConfig as F, LayoutConfig as L, NavbarConfig as N, PropDefinition as P, ThemeConfig as T, NavItem as a, PropType as b, ThemeComponent as c };
package/package.json ADDED
@@ -0,0 +1,106 @@
1
+ {
2
+ "name": "@infuro/cms-core",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "description": "Infuro CMS core - headless CMS library for Next.js",
10
+ "license": "AGPL-3.0",
11
+ "files": ["dist"],
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ },
18
+ "./hooks": {
19
+ "types": "./dist/hooks.d.ts",
20
+ "import": "./dist/hooks.js",
21
+ "require": "./dist/hooks.cjs"
22
+ },
23
+ "./api": {
24
+ "types": "./dist/api.d.ts",
25
+ "import": "./dist/api.js",
26
+ "require": "./dist/api.cjs"
27
+ },
28
+ "./auth": {
29
+ "types": "./dist/auth.d.ts",
30
+ "import": "./dist/auth.js",
31
+ "require": "./dist/auth.cjs"
32
+ },
33
+ "./auth/middleware": {
34
+ "types": "./dist/auth-middleware.d.ts",
35
+ "import": "./dist/auth-middleware.js",
36
+ "require": "./dist/auth-middleware.cjs"
37
+ },
38
+ "./admin": {
39
+ "types": "./dist/admin.d.ts",
40
+ "import": "./dist/admin.js",
41
+ "require": "./dist/admin.cjs"
42
+ },
43
+ "./theme": {
44
+ "types": "./dist/theme.d.ts",
45
+ "import": "./dist/theme.js",
46
+ "require": "./dist/theme.cjs"
47
+ },
48
+ "./admin.css": "./dist/admin.css"
49
+ },
50
+ "scripts": {
51
+ "build": "tsup && cp src/admin/admin.css dist/admin.css",
52
+ "dev": "tsup --watch",
53
+ "link": "npm run build && npm link",
54
+ "prepublishOnly": "npm run build"
55
+ },
56
+ "peerDependencies": {
57
+ "@craftjs/core": ">=0.2.0",
58
+ "next": ">=14.0.0",
59
+ "next-auth": "^4.24.11",
60
+ "react": ">=18.0.0",
61
+ "react-dom": ">=18.0.0",
62
+ "typeorm": ">=0.3.20"
63
+ },
64
+ "devDependencies": {
65
+ "@craftjs/core": "^0.2.12",
66
+ "@types/node": "^22",
67
+ "@types/nodemailer": "^6.4.0",
68
+ "@types/react": "19.0.8",
69
+ "next": "15.1.9",
70
+ "next-auth": "^4.24.11",
71
+ "react": "19.0.1",
72
+ "react-dom": "19.0.1",
73
+ "tsup": "^8.0.0",
74
+ "typeorm": "^0.3.20",
75
+ "typescript": "^5.3.3"
76
+ },
77
+ "dependencies": {
78
+ "@aws-sdk/client-s3": "^3.858.0",
79
+ "@aws-sdk/client-ses": "^3.858.0",
80
+ "@radix-ui/react-avatar": "^1.1.10",
81
+ "@radix-ui/react-checkbox": "^1.3.2",
82
+ "@radix-ui/react-dialog": "^1.1.6",
83
+ "@radix-ui/react-dropdown-menu": "^2.1.6",
84
+ "@radix-ui/react-label": "^2.1.2",
85
+ "@radix-ui/react-progress": "^1.1.2",
86
+ "@radix-ui/react-radio-group": "^1.3.7",
87
+ "@radix-ui/react-select": "^2.1.6",
88
+ "@radix-ui/react-separator": "^1.1.2",
89
+ "@radix-ui/react-slot": "^1.1.2",
90
+ "@radix-ui/react-switch": "^1.1.3",
91
+ "@radix-ui/react-tooltip": "^1.1.8",
92
+ "chart.js": "^4.5.0",
93
+ "class-variance-authority": "^0.7.1",
94
+ "clsx": "^2.1.1",
95
+ "googleapis": "^154.1.0",
96
+ "lucide-react": "^0.476.0",
97
+ "next-themes": "^0.2.1",
98
+ "nodemailer": "^6.9.0",
99
+ "react-chartjs-2": "^5.3.0",
100
+ "react-quill-new": "^3.3.3",
101
+ "reflect-metadata": "^0.2.2",
102
+ "sonner": "^2.0.6",
103
+ "tailwind-merge": "^3.0.2",
104
+ "tslib": "^2.8.1"
105
+ }
106
+ }