@otl-core/next-footer 1.1.19 → 1.1.20
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/dist/components/blocks/block-renderer.d.ts +15 -0
- package/dist/components/blocks/block-renderer.js +69 -0
- package/dist/components/blocks/block-renderer.js.map +1 -0
- package/dist/components/footer/footer-section.d.ts +15 -0
- package/dist/components/footer/footer-section.js +87 -0
- package/dist/components/footer/footer-section.js.map +1 -0
- package/dist/components/footer.d.ts +14 -0
- package/dist/components/footer.js +54 -0
- package/dist/components/footer.js.map +1 -0
- package/dist/components/ui/button.d.ts +14 -0
- package/dist/components/ui/button.js +50 -0
- package/dist/components/ui/button.js.map +1 -0
- package/dist/index.d.ts +4 -14
- package/dist/index.js +3 -312
- package/dist/index.js.map +1 -1
- package/dist/lib/footer.utils.d.ts +20 -0
- package/dist/lib/footer.utils.js +126 -0
- package/dist/lib/footer.utils.js.map +1 -0
- package/dist/lib/navigation.utils.d.ts +19 -0
- package/dist/lib/navigation.utils.js +239 -0
- package/dist/lib/navigation.utils.js.map +1 -0
- package/package.json +6 -6
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BlockInstance } from '@otl-core/cms-types';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Block Renderer for Footer Components
|
|
6
|
+
* Renders blocks within the footer context
|
|
7
|
+
* This is a minimal implementation that supports the blocks commonly used in footers
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface BlockRendererProps {
|
|
11
|
+
block: BlockInstance;
|
|
12
|
+
}
|
|
13
|
+
declare const BlockRenderer: React__default.FC<BlockRendererProps>;
|
|
14
|
+
|
|
15
|
+
export { BlockRenderer };
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import ReactMarkdown from "react-markdown";
|
|
3
|
+
const BlockRenderer = ({ block }) => {
|
|
4
|
+
const { type, config } = block;
|
|
5
|
+
if (type === "markdown") {
|
|
6
|
+
const content = config.content || "";
|
|
7
|
+
return /* @__PURE__ */ jsx("div", { className: "footer-block footer-markdown", children: /* @__PURE__ */ jsx(ReactMarkdown, { children: content }) });
|
|
8
|
+
}
|
|
9
|
+
if (type === "link") {
|
|
10
|
+
const linkConfig = config;
|
|
11
|
+
const target = linkConfig.external ? "_blank" : void 0;
|
|
12
|
+
const rel = linkConfig.external ? "noopener noreferrer" : void 0;
|
|
13
|
+
const variantClasses = {
|
|
14
|
+
default: "footer-link hover:underline transition-colors",
|
|
15
|
+
underline: "footer-link underline",
|
|
16
|
+
"no-underline": "footer-link no-underline",
|
|
17
|
+
"button-primary": "footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90",
|
|
18
|
+
"button-secondary": "footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
19
|
+
"button-outline": "footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors border border-gray-200 text-surface-foreground hover:bg-accent hover:text-accent-foreground"
|
|
20
|
+
};
|
|
21
|
+
const className = variantClasses[linkConfig.variant || "default"];
|
|
22
|
+
return /* @__PURE__ */ jsx(
|
|
23
|
+
"a",
|
|
24
|
+
{
|
|
25
|
+
href: linkConfig.href,
|
|
26
|
+
target,
|
|
27
|
+
rel,
|
|
28
|
+
className,
|
|
29
|
+
"aria-label": linkConfig.ariaLabel || linkConfig.text,
|
|
30
|
+
children: linkConfig.text
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (type === "button") {
|
|
35
|
+
const buttonConfig = config;
|
|
36
|
+
const target = buttonConfig.newTab ? "_blank" : void 0;
|
|
37
|
+
const rel = buttonConfig.newTab ? "noopener noreferrer" : void 0;
|
|
38
|
+
return /* @__PURE__ */ jsx(
|
|
39
|
+
"a",
|
|
40
|
+
{
|
|
41
|
+
href: buttonConfig.url,
|
|
42
|
+
target,
|
|
43
|
+
rel,
|
|
44
|
+
className: "footer-block footer-button inline-flex items-center justify-center px-4 py-2 rounded-md transition-colors",
|
|
45
|
+
children: buttonConfig.text
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
if (type === "image") {
|
|
50
|
+
const imageConfig = config;
|
|
51
|
+
return /* @__PURE__ */ jsx("div", { className: "footer-block footer-image", children: /* @__PURE__ */ jsx(
|
|
52
|
+
"img",
|
|
53
|
+
{
|
|
54
|
+
src: imageConfig.src,
|
|
55
|
+
alt: imageConfig.alt || "",
|
|
56
|
+
width: imageConfig.width,
|
|
57
|
+
height: imageConfig.height
|
|
58
|
+
}
|
|
59
|
+
) });
|
|
60
|
+
}
|
|
61
|
+
if (type === "divider") {
|
|
62
|
+
return /* @__PURE__ */ jsx("hr", { className: "footer-block footer-divider" });
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
};
|
|
66
|
+
export {
|
|
67
|
+
BlockRenderer
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=block-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/blocks/block-renderer.tsx"],"sourcesContent":["/**\n * Block Renderer for Footer Components\n * Renders blocks within the footer context\n * This is a minimal implementation that supports the blocks commonly used in footers\n */\n\nimport { BlockInstance } from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport ReactMarkdown from \"react-markdown\";\n\ninterface BlockRendererProps {\n block: BlockInstance;\n}\n\nexport const BlockRenderer: React.FC<BlockRendererProps> = ({ block }) => {\n const { type, config } = block;\n\n // Markdown block\n if (type === \"markdown\") {\n const content = (config as { content?: string }).content || \"\";\n return (\n <div className=\"footer-block footer-markdown\">\n <ReactMarkdown>{content}</ReactMarkdown>\n </div>\n );\n }\n\n // Link block\n if (type === \"link\") {\n const linkConfig = config as {\n text?: string;\n href?: string;\n external?: boolean;\n variant?: string;\n ariaLabel?: string;\n };\n\n const target = linkConfig.external ? \"_blank\" : undefined;\n const rel = linkConfig.external ? \"noopener noreferrer\" : undefined;\n\n const variantClasses = {\n default: \"footer-link hover:underline transition-colors\",\n underline: \"footer-link underline\",\n \"no-underline\": \"footer-link no-underline\",\n \"button-primary\":\n \"footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90\",\n \"button-secondary\":\n \"footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n \"button-outline\":\n \"footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors border border-gray-200 text-surface-foreground hover:bg-accent hover:text-accent-foreground\",\n };\n\n const className =\n variantClasses[\n (linkConfig.variant as keyof typeof variantClasses) || \"default\"\n ];\n\n return (\n <a\n href={linkConfig.href}\n target={target}\n rel={rel}\n className={className}\n aria-label={linkConfig.ariaLabel || linkConfig.text}\n >\n {linkConfig.text}\n </a>\n );\n }\n\n // Button block (existing button rendering logic)\n if (type === \"button\") {\n const buttonConfig = config as {\n text?: string;\n url?: string;\n variant?: string;\n size?: string;\n newTab?: boolean;\n };\n\n const target = buttonConfig.newTab ? \"_blank\" : undefined;\n const rel = buttonConfig.newTab ? \"noopener noreferrer\" : undefined;\n\n return (\n <a\n href={buttonConfig.url}\n target={target}\n rel={rel}\n className=\"footer-block footer-button inline-flex items-center justify-center px-4 py-2 rounded-md transition-colors\"\n >\n {buttonConfig.text}\n </a>\n );\n }\n\n // Image block\n if (type === \"image\") {\n const imageConfig = config as {\n src?: string;\n alt?: string;\n width?: number;\n height?: number;\n };\n\n return (\n <div className=\"footer-block footer-image\">\n <img\n src={imageConfig.src}\n alt={imageConfig.alt || \"\"}\n width={imageConfig.width}\n height={imageConfig.height}\n />\n </div>\n );\n }\n\n // Divider block\n if (type === \"divider\") {\n return <hr className=\"footer-block footer-divider\" />;\n }\n\n // Fallback for unknown block types\n return null;\n};\n"],"mappings":"AAsBQ;AAdR,OAAO,mBAAmB;AAMnB,MAAM,gBAA8C,CAAC,EAAE,MAAM,MAAM;AACxE,QAAM,EAAE,MAAM,OAAO,IAAI;AAGzB,MAAI,SAAS,YAAY;AACvB,UAAM,UAAW,OAAgC,WAAW;AAC5D,WACE,oBAAC,SAAI,WAAU,gCACb,8BAAC,iBAAe,mBAAQ,GAC1B;AAAA,EAEJ;AAGA,MAAI,SAAS,QAAQ;AACnB,UAAM,aAAa;AAQnB,UAAM,SAAS,WAAW,WAAW,WAAW;AAChD,UAAM,MAAM,WAAW,WAAW,wBAAwB;AAE1D,UAAM,iBAAiB;AAAA,MACrB,SAAS;AAAA,MACT,WAAW;AAAA,MACX,gBAAgB;AAAA,MAChB,kBACE;AAAA,MACF,oBACE;AAAA,MACF,kBACE;AAAA,IACJ;AAEA,UAAM,YACJ,eACG,WAAW,WAA2C,SACzD;AAEF,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,WAAW;AAAA,QACjB;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAY,WAAW,aAAa,WAAW;AAAA,QAE9C,qBAAW;AAAA;AAAA,IACd;AAAA,EAEJ;AAGA,MAAI,SAAS,UAAU;AACrB,UAAM,eAAe;AAQrB,UAAM,SAAS,aAAa,SAAS,WAAW;AAChD,UAAM,MAAM,aAAa,SAAS,wBAAwB;AAE1D,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,aAAa;AAAA,QACnB;AAAA,QACA;AAAA,QACA,WAAU;AAAA,QAET,uBAAa;AAAA;AAAA,IAChB;AAAA,EAEJ;AAGA,MAAI,SAAS,SAAS;AACpB,UAAM,cAAc;AAOpB,WACE,oBAAC,SAAI,WAAU,6BACb;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,YAAY;AAAA,QACjB,KAAK,YAAY,OAAO;AAAA,QACxB,OAAO,YAAY;AAAA,QACnB,QAAQ,YAAY;AAAA;AAAA,IACtB,GACF;AAAA,EAEJ;AAGA,MAAI,SAAS,WAAW;AACtB,WAAO,oBAAC,QAAG,WAAU,+BAA8B;AAAA,EACrD;AAGA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FooterSection, FooterContentSection, FooterConfig, Site } from '@otl-core/cms-types';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
import { BlockRegistry } from '@otl-core/block-registry';
|
|
4
|
+
|
|
5
|
+
interface FooterSectionProps {
|
|
6
|
+
section: FooterSection | FooterContentSection;
|
|
7
|
+
footer: FooterConfig;
|
|
8
|
+
site: Site;
|
|
9
|
+
resolvedColors: Record<string, string | undefined>;
|
|
10
|
+
level?: number;
|
|
11
|
+
blockRegistry?: BlockRegistry;
|
|
12
|
+
}
|
|
13
|
+
declare const FooterSectionComponent: React__default.FC<FooterSectionProps>;
|
|
14
|
+
|
|
15
|
+
export { FooterSectionComponent };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { resolveColorToCSS } from "@otl-core/style-utils";
|
|
3
|
+
import { isContentSection } from "../../lib/footer.utils";
|
|
4
|
+
import { BlockRenderer as LocalBlockRenderer } from "../blocks/block-renderer";
|
|
5
|
+
import { BlockRenderer as RegistryBlockRenderer } from "@otl-core/block-registry";
|
|
6
|
+
const FooterSectionComponent = ({
|
|
7
|
+
section,
|
|
8
|
+
footer,
|
|
9
|
+
site,
|
|
10
|
+
resolvedColors,
|
|
11
|
+
level = 0,
|
|
12
|
+
blockRegistry
|
|
13
|
+
}) => {
|
|
14
|
+
const sectionStyle = (() => {
|
|
15
|
+
const style = {
|
|
16
|
+
display: "flex",
|
|
17
|
+
flexDirection: section.type === "row" ? "row" : "column",
|
|
18
|
+
alignItems: section.style.align || "flex-start",
|
|
19
|
+
justifyContent: section.style.justify || "flex-start",
|
|
20
|
+
gap: section.style.gap || "0"
|
|
21
|
+
};
|
|
22
|
+
if (section.style.flex) {
|
|
23
|
+
style.flex = section.style.flex;
|
|
24
|
+
}
|
|
25
|
+
if (section.style.background) {
|
|
26
|
+
style.backgroundColor = resolveColorToCSS(section.style.background);
|
|
27
|
+
}
|
|
28
|
+
if (section.style.padding) {
|
|
29
|
+
const padding = typeof section.style.padding === "object" && "base" in section.style.padding ? section.style.padding.base : section.style.padding;
|
|
30
|
+
style.padding = padding;
|
|
31
|
+
}
|
|
32
|
+
if (section.style.border) {
|
|
33
|
+
const border = typeof section.style.border === "object" && "base" in section.style.border ? section.style.border.base : section.style.border;
|
|
34
|
+
if (border) {
|
|
35
|
+
style.border = `${border.width || "0"} ${border.style || "solid"} ${border.color ? resolveColorToCSS(border.color) : "transparent"}`;
|
|
36
|
+
if (border.radius) {
|
|
37
|
+
style.borderRadius = border.radius;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return style;
|
|
42
|
+
})();
|
|
43
|
+
if (isContentSection(section)) {
|
|
44
|
+
return /* @__PURE__ */ jsx(
|
|
45
|
+
"div",
|
|
46
|
+
{
|
|
47
|
+
className: "footer-section footer-content-section",
|
|
48
|
+
style: sectionStyle,
|
|
49
|
+
"data-section-id": section.id,
|
|
50
|
+
children: section?.blocks?.map(
|
|
51
|
+
(block) => blockRegistry ? /* @__PURE__ */ jsx(
|
|
52
|
+
RegistryBlockRenderer,
|
|
53
|
+
{
|
|
54
|
+
block,
|
|
55
|
+
blockRegistry
|
|
56
|
+
},
|
|
57
|
+
block.id
|
|
58
|
+
) : /* @__PURE__ */ jsx(LocalBlockRenderer, { block }, block.id)
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return /* @__PURE__ */ jsx(
|
|
64
|
+
"div",
|
|
65
|
+
{
|
|
66
|
+
className: "footer-section footer-container-section",
|
|
67
|
+
style: sectionStyle,
|
|
68
|
+
"data-section-id": section.id,
|
|
69
|
+
children: section?.sections?.sort((a, b) => a.order - b.order)?.map((childSection) => /* @__PURE__ */ jsx(
|
|
70
|
+
FooterSectionComponent,
|
|
71
|
+
{
|
|
72
|
+
section: childSection,
|
|
73
|
+
footer,
|
|
74
|
+
site,
|
|
75
|
+
resolvedColors,
|
|
76
|
+
level: level + 1,
|
|
77
|
+
blockRegistry
|
|
78
|
+
},
|
|
79
|
+
childSection.id
|
|
80
|
+
))
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
};
|
|
84
|
+
export {
|
|
85
|
+
FooterSectionComponent
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=footer-section.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/footer/footer-section.tsx"],"sourcesContent":["import {\n Site,\n FooterConfig,\n FooterContentSection,\n FooterSection,\n} from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport { resolveColorToCSS } from \"@otl-core/style-utils\";\nimport { isContentSection } from \"../../lib/footer.utils\";\nimport { BlockRenderer as LocalBlockRenderer } from \"../blocks/block-renderer\";\nimport type { BlockRegistry } from \"@otl-core/block-registry\";\nimport { BlockRenderer as RegistryBlockRenderer } from \"@otl-core/block-registry\";\n\ninterface FooterSectionProps {\n section: FooterSection | FooterContentSection;\n footer: FooterConfig;\n site: Site;\n resolvedColors: Record<string, string | undefined>;\n level?: number;\n blockRegistry?: BlockRegistry;\n}\n\nexport const FooterSectionComponent: React.FC<FooterSectionProps> = ({\n section,\n footer,\n site,\n resolvedColors,\n level = 0,\n blockRegistry,\n}) => {\n const sectionStyle: React.CSSProperties = (() => {\n const style: React.CSSProperties = {\n display: \"flex\",\n flexDirection: section.type === \"row\" ? \"row\" : \"column\",\n alignItems: section.style.align || \"flex-start\",\n justifyContent: section.style.justify || \"flex-start\",\n gap: section.style.gap || \"0\",\n };\n\n if (section.style.flex) {\n style.flex = section.style.flex;\n }\n\n // Apply section-specific background\n if (section.style.background) {\n style.backgroundColor = resolveColorToCSS(section.style.background);\n }\n\n // Apply section-specific padding\n if (section.style.padding) {\n const padding =\n typeof section.style.padding === \"object\" &&\n \"base\" in section.style.padding\n ? section.style.padding.base\n : section.style.padding;\n style.padding = padding;\n }\n\n // Apply section-specific border\n if (section.style.border) {\n const border =\n typeof section.style.border === \"object\" &&\n \"base\" in section.style.border\n ? section.style.border.base\n : section.style.border;\n\n if (border) {\n style.border = `${border.width || \"0\"} ${border.style || \"solid\"} ${\n border.color ? resolveColorToCSS(border.color) : \"transparent\"\n }`;\n if (border.radius) {\n style.borderRadius = border.radius;\n }\n }\n }\n\n return style;\n })();\n\n // Content section - render blocks\n if (isContentSection(section)) {\n return (\n <div\n className=\"footer-section footer-content-section\"\n style={sectionStyle}\n data-section-id={section.id}\n >\n {section?.blocks?.map((block) =>\n blockRegistry ? (\n <RegistryBlockRenderer\n key={block.id}\n block={block}\n blockRegistry={blockRegistry}\n />\n ) : (\n <LocalBlockRenderer key={block.id} block={block} />\n ),\n )}\n </div>\n );\n }\n\n // Container section - render nested sections recursively\n return (\n <div\n className=\"footer-section footer-container-section\"\n style={sectionStyle}\n data-section-id={section.id}\n >\n {section?.sections\n ?.sort((a, b) => a.order - b.order)\n ?.map((childSection) => (\n <FooterSectionComponent\n key={childSection.id}\n section={childSection}\n footer={footer}\n site={site}\n resolvedColors={resolvedColors}\n level={level + 1}\n blockRegistry={blockRegistry}\n />\n ))}\n </div>\n );\n};\n"],"mappings":"AAyFY;AAlFZ,SAAS,yBAAyB;AAClC,SAAS,wBAAwB;AACjC,SAAS,iBAAiB,0BAA0B;AAEpD,SAAS,iBAAiB,6BAA6B;AAWhD,MAAM,yBAAuD,CAAC;AAAA,EACnE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR;AACF,MAAM;AACJ,QAAM,gBAAqC,MAAM;AAC/C,UAAM,QAA6B;AAAA,MACjC,SAAS;AAAA,MACT,eAAe,QAAQ,SAAS,QAAQ,QAAQ;AAAA,MAChD,YAAY,QAAQ,MAAM,SAAS;AAAA,MACnC,gBAAgB,QAAQ,MAAM,WAAW;AAAA,MACzC,KAAK,QAAQ,MAAM,OAAO;AAAA,IAC5B;AAEA,QAAI,QAAQ,MAAM,MAAM;AACtB,YAAM,OAAO,QAAQ,MAAM;AAAA,IAC7B;AAGA,QAAI,QAAQ,MAAM,YAAY;AAC5B,YAAM,kBAAkB,kBAAkB,QAAQ,MAAM,UAAU;AAAA,IACpE;AAGA,QAAI,QAAQ,MAAM,SAAS;AACzB,YAAM,UACJ,OAAO,QAAQ,MAAM,YAAY,YACjC,UAAU,QAAQ,MAAM,UACpB,QAAQ,MAAM,QAAQ,OACtB,QAAQ,MAAM;AACpB,YAAM,UAAU;AAAA,IAClB;AAGA,QAAI,QAAQ,MAAM,QAAQ;AACxB,YAAM,SACJ,OAAO,QAAQ,MAAM,WAAW,YAChC,UAAU,QAAQ,MAAM,SACpB,QAAQ,MAAM,OAAO,OACrB,QAAQ,MAAM;AAEpB,UAAI,QAAQ;AACV,cAAM,SAAS,GAAG,OAAO,SAAS,GAAG,IAAI,OAAO,SAAS,OAAO,IAC9D,OAAO,QAAQ,kBAAkB,OAAO,KAAK,IAAI,aACnD;AACA,YAAI,OAAO,QAAQ;AACjB,gBAAM,eAAe,OAAO;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT,GAAG;AAGH,MAAI,iBAAiB,OAAO,GAAG;AAC7B,WACE;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,OAAO;AAAA,QACP,mBAAiB,QAAQ;AAAA,QAExB,mBAAS,QAAQ;AAAA,UAAI,CAAC,UACrB,gBACE;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA;AAAA;AAAA,YAFK,MAAM;AAAA,UAGb,IAEA,oBAAC,sBAAkC,SAAV,MAAM,EAAkB;AAAA,QAErD;AAAA;AAAA,IACF;AAAA,EAEJ;AAGA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,MACP,mBAAiB,QAAQ;AAAA,MAExB,mBAAS,UACN,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,GAChC,IAAI,CAAC,iBACL;AAAA,QAAC;AAAA;AAAA,UAEC,SAAS;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,UACA,OAAO,QAAQ;AAAA,UACf;AAAA;AAAA,QANK,aAAa;AAAA,MAOpB,CACD;AAAA;AAAA,EACL;AAEJ;","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FooterConfig, Site } from '@otl-core/cms-types';
|
|
2
|
+
import { BlockRegistry } from '@otl-core/block-registry';
|
|
3
|
+
import React__default from 'react';
|
|
4
|
+
|
|
5
|
+
interface FooterProps {
|
|
6
|
+
footer: FooterConfig;
|
|
7
|
+
site: Site;
|
|
8
|
+
className?: string;
|
|
9
|
+
id?: string;
|
|
10
|
+
blockRegistry?: BlockRegistry;
|
|
11
|
+
}
|
|
12
|
+
declare const Footer: React__default.FC<FooterProps>;
|
|
13
|
+
|
|
14
|
+
export { Footer, type FooterProps };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { generateFooterCSS, resolveFooterColors } from "../lib/footer.utils";
|
|
3
|
+
import { cn } from "@otl-core/style-utils";
|
|
4
|
+
import { FooterSectionComponent } from "./footer/footer-section";
|
|
5
|
+
const Footer = ({
|
|
6
|
+
footer,
|
|
7
|
+
site,
|
|
8
|
+
className = "",
|
|
9
|
+
id = "default",
|
|
10
|
+
blockRegistry
|
|
11
|
+
}) => {
|
|
12
|
+
const resolvedColors = resolveFooterColors(footer.style);
|
|
13
|
+
const styles = generateFooterCSS(id, footer, resolvedColors);
|
|
14
|
+
const sortedSections = [...footer.sections].sort((a, b) => a.order - b.order);
|
|
15
|
+
const containerBehavior = footer.style.container || "edged";
|
|
16
|
+
const sectionsContent = sortedSections.map((section) => {
|
|
17
|
+
const sectionElement = /* @__PURE__ */ jsx(
|
|
18
|
+
FooterSectionComponent,
|
|
19
|
+
{
|
|
20
|
+
section,
|
|
21
|
+
footer,
|
|
22
|
+
site,
|
|
23
|
+
resolvedColors,
|
|
24
|
+
blockRegistry
|
|
25
|
+
},
|
|
26
|
+
section.id
|
|
27
|
+
);
|
|
28
|
+
if (containerBehavior === "edged") {
|
|
29
|
+
return /* @__PURE__ */ jsx("div", { className: "container mx-auto", children: sectionElement }, section.id);
|
|
30
|
+
}
|
|
31
|
+
return sectionElement;
|
|
32
|
+
});
|
|
33
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
34
|
+
styles && /* @__PURE__ */ jsx("style", { children: styles }),
|
|
35
|
+
/* @__PURE__ */ jsx(
|
|
36
|
+
"footer",
|
|
37
|
+
{
|
|
38
|
+
className: cn(
|
|
39
|
+
{
|
|
40
|
+
"container mx-auto": containerBehavior === "boxed"
|
|
41
|
+
},
|
|
42
|
+
className
|
|
43
|
+
),
|
|
44
|
+
"data-footer-id": id,
|
|
45
|
+
"data-container": containerBehavior,
|
|
46
|
+
children: /* @__PURE__ */ jsx("div", { className: `footer-${id} footer-container`, children: sectionsContent })
|
|
47
|
+
}
|
|
48
|
+
)
|
|
49
|
+
] });
|
|
50
|
+
};
|
|
51
|
+
export {
|
|
52
|
+
Footer
|
|
53
|
+
};
|
|
54
|
+
//# sourceMappingURL=footer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/footer.tsx"],"sourcesContent":["import { Site, FooterConfig } from \"@otl-core/cms-types\";\nimport type { BlockRegistry } from \"@otl-core/block-registry\";\nimport React from \"react\";\nimport { generateFooterCSS, resolveFooterColors } from \"../lib/footer.utils\";\nimport { cn } from \"@otl-core/style-utils\";\nimport { FooterSectionComponent } from \"./footer/footer-section\";\n\nexport interface FooterProps {\n footer: FooterConfig;\n site: Site;\n className?: string;\n id?: string;\n blockRegistry?: BlockRegistry;\n}\n\nexport const Footer: React.FC<FooterProps> = ({\n footer,\n site,\n className = \"\",\n id = \"default\",\n blockRegistry,\n}) => {\n const resolvedColors = resolveFooterColors(footer.style);\n const styles = generateFooterCSS(id, footer, resolvedColors);\n const sortedSections = [...footer.sections].sort((a, b) => a.order - b.order);\n const containerBehavior = footer.style.container || \"edged\";\n\n // Render sections with container wrapping per section for \"edged\" mode\n const sectionsContent = sortedSections.map((section) => {\n const sectionElement = (\n <FooterSectionComponent\n key={section.id}\n section={section}\n footer={footer}\n site={site}\n resolvedColors={resolvedColors}\n blockRegistry={blockRegistry}\n />\n );\n\n // In \"edged\" mode, wrap each top-level section in its own container\n if (containerBehavior === \"edged\") {\n return (\n <div key={section.id} className=\"container mx-auto\">\n {sectionElement}\n </div>\n );\n }\n\n return sectionElement;\n });\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <footer\n className={cn(\n {\n \"container mx-auto\": containerBehavior === \"boxed\",\n },\n className,\n )}\n data-footer-id={id}\n data-container={containerBehavior}\n >\n <div className={`footer-${id} footer-container`}>{sectionsContent}</div>\n </footer>\n </>\n );\n};\n"],"mappings":"AA8BM,SAuBF,UAvBE,KAuBF,YAvBE;AA3BN,SAAS,mBAAmB,2BAA2B;AACvD,SAAS,UAAU;AACnB,SAAS,8BAA8B;AAUhC,MAAM,SAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA,YAAY;AAAA,EACZ,KAAK;AAAA,EACL;AACF,MAAM;AACJ,QAAM,iBAAiB,oBAAoB,OAAO,KAAK;AACvD,QAAM,SAAS,kBAAkB,IAAI,QAAQ,cAAc;AAC3D,QAAM,iBAAiB,CAAC,GAAG,OAAO,QAAQ,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAC5E,QAAM,oBAAoB,OAAO,MAAM,aAAa;AAGpD,QAAM,kBAAkB,eAAe,IAAI,CAAC,YAAY;AACtD,UAAM,iBACJ;AAAA,MAAC;AAAA;AAAA,QAEC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA;AAAA,MALK,QAAQ;AAAA,IAMf;AAIF,QAAI,sBAAsB,SAAS;AACjC,aACE,oBAAC,SAAqB,WAAU,qBAC7B,4BADO,QAAQ,EAElB;AAAA,IAEJ;AAEA,WAAO;AAAA,EACT,CAAC;AAED,SACE,iCACG;AAAA,cAAU,oBAAC,WAAO,kBAAO;AAAA,IAC1B;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,YACE,qBAAqB,sBAAsB;AAAA,UAC7C;AAAA,UACA;AAAA,QACF;AAAA,QACA,kBAAgB;AAAA,QAChB,kBAAgB;AAAA,QAEhB,8BAAC,SAAI,WAAW,UAAU,EAAE,qBAAsB,2BAAgB;AAAA;AAAA,IACpE;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { VariantProps } from 'class-variance-authority';
|
|
5
|
+
|
|
6
|
+
declare const buttonVariants: (props?: ({
|
|
7
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
8
|
+
size?: "sm" | "md" | "lg" | null | undefined;
|
|
9
|
+
} & class_variance_authority_types.ClassProp) | undefined) => string;
|
|
10
|
+
declare function Button({ className, variant, size, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
|
|
11
|
+
asChild?: boolean;
|
|
12
|
+
}): react_jsx_runtime.JSX.Element;
|
|
13
|
+
|
|
14
|
+
export { Button, buttonVariants };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import { cva } from "class-variance-authority";
|
|
4
|
+
import { cn } from "@otl-core/style-utils";
|
|
5
|
+
const buttonVariants = cva(
|
|
6
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
|
|
11
|
+
destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
|
|
12
|
+
outline: "border bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-gray-200 dark:hover:bg-input/50",
|
|
13
|
+
secondary: "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
|
|
14
|
+
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
|
|
15
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
16
|
+
},
|
|
17
|
+
size: {
|
|
18
|
+
sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
|
|
19
|
+
md: "h-9 px-4 py-2 has-[>svg]:px-3",
|
|
20
|
+
lg: "h-10 rounded-md px-6 has-[>svg]:px-4"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
size: "md"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
);
|
|
29
|
+
function Button({
|
|
30
|
+
className,
|
|
31
|
+
variant,
|
|
32
|
+
size,
|
|
33
|
+
asChild = false,
|
|
34
|
+
...props
|
|
35
|
+
}) {
|
|
36
|
+
const Comp = asChild ? Slot : "button";
|
|
37
|
+
return /* @__PURE__ */ jsx(
|
|
38
|
+
Comp,
|
|
39
|
+
{
|
|
40
|
+
"data-slot": "button",
|
|
41
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
42
|
+
...props
|
|
43
|
+
}
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
Button,
|
|
48
|
+
buttonVariants
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=button.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/ui/button.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@otl-core/style-utils\";\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default:\n \"bg-primary text-primary-foreground shadow-xs hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-gray-200 dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n md: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n },\n);\n\nfunction Button({\n className,\n variant,\n size,\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean;\n }) {\n const Comp = asChild ? Slot : \"button\";\n\n return (\n <Comp\n data-slot=\"button\"\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n );\n}\n\nexport { Button, buttonVariants };\n"],"mappings":"AAiDI;AAhDJ,SAAS,YAAY;AACrB,SAAS,WAA8B;AAEvC,SAAS,UAAU;AAEnB,MAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SACE;AAAA,QACF,aACE;AAAA,QACF,SACE;AAAA,QACF,WACE;AAAA,QACF,OACE;AAAA,QACF,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,MACN;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAEA,SAAS,OAAO;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,GAAG;AACL,GAGK;AACH,QAAM,OAAO,UAAU,OAAO;AAE9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC,aAAU;AAAA,MACV,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,UAAU,CAAC,CAAC;AAAA,MACzD,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
interface FooterProps {
|
|
6
|
-
footer: FooterConfig;
|
|
7
|
-
site: Site;
|
|
8
|
-
className?: string;
|
|
9
|
-
id?: string;
|
|
10
|
-
blockRegistry?: BlockRegistry;
|
|
11
|
-
}
|
|
12
|
-
declare const Footer: React.FC<FooterProps>;
|
|
13
|
-
|
|
14
|
-
export { Footer };
|
|
1
|
+
export { Footer } from './components/footer.js';
|
|
2
|
+
import '@otl-core/cms-types';
|
|
3
|
+
import '@otl-core/block-registry';
|
|
4
|
+
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -1,314 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import { useMemo } from 'react';
|
|
5
|
-
import ReactMarkdown from 'react-markdown';
|
|
6
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
7
|
-
import { BlockRenderer as BlockRenderer$1 } from '@otl-core/block-registry';
|
|
8
|
-
|
|
9
|
-
// src/lib/footer.utils.ts
|
|
10
|
-
function resolveFooterColors(style) {
|
|
11
|
-
const resolved = {
|
|
12
|
-
background: resolveColorToCSS(style.background),
|
|
13
|
-
text: resolveColorToCSS(style.text),
|
|
14
|
-
linkColor: resolveColorToCSS(style.link.color),
|
|
15
|
-
linkHoverColor: resolveColorToCSS(style.link.hoverColor)
|
|
16
|
-
};
|
|
17
|
-
return resolved;
|
|
18
|
-
}
|
|
19
|
-
function getResponsiveBase(value) {
|
|
20
|
-
if (typeof value === "object" && value !== null && "base" in value) {
|
|
21
|
-
return value.base;
|
|
22
|
-
}
|
|
23
|
-
return value;
|
|
24
|
-
}
|
|
25
|
-
function resolveBorder(border) {
|
|
26
|
-
if (!border) return "";
|
|
27
|
-
const base = getResponsiveBase(border);
|
|
28
|
-
if (!base) return "";
|
|
29
|
-
const width = base.width || "0";
|
|
30
|
-
const style = base.style || "solid";
|
|
31
|
-
const color = base.color ? resolveColorToCSS(base.color) : "transparent";
|
|
32
|
-
return `${width} ${style} ${color}`;
|
|
33
|
-
}
|
|
34
|
-
function generateFooterCSS(id, footer, resolvedColors) {
|
|
35
|
-
const cssBlocks = [];
|
|
36
|
-
const containerBehavior = footer.style.container || "edged";
|
|
37
|
-
const baseMargin = getResponsiveBase(footer.style.layout.margin);
|
|
38
|
-
const basePadding = getResponsiveBase(footer.style.layout.padding);
|
|
39
|
-
const baseSectionGap = getResponsiveBase(footer.style.layout.sectionGap);
|
|
40
|
-
const borderCSS = resolveBorder(footer.style.border);
|
|
41
|
-
const baseStyles = `
|
|
42
|
-
.footer-${id} {
|
|
43
|
-
display: flex;
|
|
44
|
-
flex-direction: column;
|
|
45
|
-
${resolvedColors.background ? `background-color: ${resolvedColors.background};` : ""}
|
|
46
|
-
${resolvedColors.text ? `color: ${resolvedColors.text};` : ""}
|
|
47
|
-
${baseMargin ? `margin: ${baseMargin};` : ""}
|
|
48
|
-
${basePadding ? `padding: ${basePadding};` : ""}
|
|
49
|
-
${borderCSS ? `border: ${borderCSS};` : ""}
|
|
50
|
-
${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : ""}
|
|
51
|
-
${baseSectionGap ? `gap: ${baseSectionGap};` : ""}
|
|
52
|
-
}
|
|
53
|
-
`;
|
|
54
|
-
cssBlocks.push(baseStyles);
|
|
55
|
-
if (containerBehavior === "edged") {
|
|
56
|
-
cssBlocks.push(`
|
|
57
|
-
.footer-${id} > div.container {
|
|
58
|
-
width: 100%;
|
|
59
|
-
}
|
|
60
|
-
`);
|
|
61
|
-
}
|
|
62
|
-
cssBlocks.push(`
|
|
63
|
-
.footer-${id} .footer-section {
|
|
64
|
-
width: 100%;
|
|
65
|
-
}
|
|
66
|
-
`);
|
|
67
|
-
cssBlocks.push(`
|
|
68
|
-
@media (max-width: 767px) {
|
|
69
|
-
.footer-${id} .footer-container-section {
|
|
70
|
-
flex-wrap: wrap;
|
|
71
|
-
}
|
|
72
|
-
.footer-${id} .footer-container-section > .footer-content-section {
|
|
73
|
-
flex: 1 1 100%;
|
|
74
|
-
width: 100%;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
`);
|
|
78
|
-
cssBlocks.push(`
|
|
79
|
-
@media (min-width: 768px) and (max-width: 1023px) {
|
|
80
|
-
.footer-${id} .footer-container-section {
|
|
81
|
-
flex-wrap: wrap;
|
|
82
|
-
}
|
|
83
|
-
.footer-${id} .footer-container-section > .footer-content-section {
|
|
84
|
-
flex: 1 1 calc(50% - ${baseSectionGap || "0px"} / 2);
|
|
85
|
-
min-width: 0;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
`);
|
|
89
|
-
cssBlocks.push(`
|
|
90
|
-
@media (min-width: 1024px) {
|
|
91
|
-
.footer-${id} .footer-container-section {
|
|
92
|
-
flex-wrap: nowrap;
|
|
93
|
-
}
|
|
94
|
-
.footer-${id} .footer-container-section > .footer-content-section {
|
|
95
|
-
flex: 1 1 auto;
|
|
96
|
-
min-width: 0;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
`);
|
|
100
|
-
if (resolvedColors.linkColor || resolvedColors.linkHoverColor) {
|
|
101
|
-
cssBlocks.push(`
|
|
102
|
-
.footer-${id} a {
|
|
103
|
-
${resolvedColors.linkColor ? `color: ${resolvedColors.linkColor};` : ""}
|
|
104
|
-
text-decoration: none;
|
|
105
|
-
transition: color 0.2s;
|
|
106
|
-
}
|
|
107
|
-
.footer-${id} a:hover {
|
|
108
|
-
${resolvedColors.linkHoverColor ? `color: ${resolvedColors.linkHoverColor};` : ""}
|
|
109
|
-
}
|
|
110
|
-
`);
|
|
111
|
-
}
|
|
112
|
-
return minifyCSS(cssBlocks.filter(Boolean).join(""));
|
|
113
|
-
}
|
|
114
|
-
function formatShadow(shadow) {
|
|
115
|
-
const insetStr = shadow.inset ? "inset " : "";
|
|
116
|
-
return `${insetStr}${shadow.offsetX} ${shadow.offsetY} ${shadow.blurRadius} ${shadow.spreadRadius} ${shadow.color}`;
|
|
117
|
-
}
|
|
118
|
-
function minifyCSS(css) {
|
|
119
|
-
return css.replace(/\s+/g, " ").replace(/\s*{\s*/g, "{").replace(/\s*}\s*/g, "}").replace(/\s*:\s*/g, ":").replace(/\s*;\s*/g, ";").replace(/;\s*}/g, "}").trim();
|
|
120
|
-
}
|
|
121
|
-
function isContentSection(section) {
|
|
122
|
-
return "blocks" in section && Array.isArray(section.blocks);
|
|
123
|
-
}
|
|
124
|
-
var BlockRenderer = ({ block }) => {
|
|
125
|
-
const { type, config } = block;
|
|
126
|
-
if (type === "markdown") {
|
|
127
|
-
const content = config.content || "";
|
|
128
|
-
return /* @__PURE__ */ jsx("div", { className: "footer-block footer-markdown", children: /* @__PURE__ */ jsx(ReactMarkdown, { children: content }) });
|
|
129
|
-
}
|
|
130
|
-
if (type === "link") {
|
|
131
|
-
const linkConfig = config;
|
|
132
|
-
const target = linkConfig.external ? "_blank" : void 0;
|
|
133
|
-
const rel = linkConfig.external ? "noopener noreferrer" : void 0;
|
|
134
|
-
const variantClasses = {
|
|
135
|
-
default: "footer-link hover:underline transition-colors",
|
|
136
|
-
underline: "footer-link underline",
|
|
137
|
-
"no-underline": "footer-link no-underline",
|
|
138
|
-
"button-primary": "footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90",
|
|
139
|
-
"button-secondary": "footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
140
|
-
"button-outline": "footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors border border-gray-200 text-surface-foreground hover:bg-accent hover:text-accent-foreground"
|
|
141
|
-
};
|
|
142
|
-
const className = variantClasses[linkConfig.variant || "default"];
|
|
143
|
-
return /* @__PURE__ */ jsx(
|
|
144
|
-
"a",
|
|
145
|
-
{
|
|
146
|
-
href: linkConfig.href,
|
|
147
|
-
target,
|
|
148
|
-
rel,
|
|
149
|
-
className,
|
|
150
|
-
"aria-label": linkConfig.ariaLabel || linkConfig.text,
|
|
151
|
-
children: linkConfig.text
|
|
152
|
-
}
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
if (type === "button") {
|
|
156
|
-
const buttonConfig = config;
|
|
157
|
-
const target = buttonConfig.newTab ? "_blank" : void 0;
|
|
158
|
-
const rel = buttonConfig.newTab ? "noopener noreferrer" : void 0;
|
|
159
|
-
return /* @__PURE__ */ jsx(
|
|
160
|
-
"a",
|
|
161
|
-
{
|
|
162
|
-
href: buttonConfig.url,
|
|
163
|
-
target,
|
|
164
|
-
rel,
|
|
165
|
-
className: "footer-block footer-button inline-flex items-center justify-center px-4 py-2 rounded-md transition-colors",
|
|
166
|
-
children: buttonConfig.text
|
|
167
|
-
}
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
if (type === "image") {
|
|
171
|
-
const imageConfig = config;
|
|
172
|
-
return /* @__PURE__ */ jsx("div", { className: "footer-block footer-image", children: /* @__PURE__ */ jsx(
|
|
173
|
-
"img",
|
|
174
|
-
{
|
|
175
|
-
src: imageConfig.src,
|
|
176
|
-
alt: imageConfig.alt || "",
|
|
177
|
-
width: imageConfig.width,
|
|
178
|
-
height: imageConfig.height
|
|
179
|
-
}
|
|
180
|
-
) });
|
|
181
|
-
}
|
|
182
|
-
if (type === "divider") {
|
|
183
|
-
return /* @__PURE__ */ jsx("hr", { className: "footer-block footer-divider" });
|
|
184
|
-
}
|
|
185
|
-
return null;
|
|
1
|
+
import { Footer } from "./components/footer";
|
|
2
|
+
export {
|
|
3
|
+
Footer
|
|
186
4
|
};
|
|
187
|
-
var FooterSectionComponent = ({
|
|
188
|
-
section,
|
|
189
|
-
footer,
|
|
190
|
-
site,
|
|
191
|
-
resolvedColors,
|
|
192
|
-
level = 0,
|
|
193
|
-
blockRegistry
|
|
194
|
-
}) => {
|
|
195
|
-
const sectionStyle = useMemo(() => {
|
|
196
|
-
const style = {
|
|
197
|
-
display: "flex",
|
|
198
|
-
flexDirection: section.type === "row" ? "row" : "column",
|
|
199
|
-
alignItems: section.style.align || "flex-start",
|
|
200
|
-
justifyContent: section.style.justify || "flex-start",
|
|
201
|
-
gap: section.style.gap || "0"
|
|
202
|
-
};
|
|
203
|
-
if (section.style.flex) {
|
|
204
|
-
style.flex = section.style.flex;
|
|
205
|
-
}
|
|
206
|
-
if (section.style.background) {
|
|
207
|
-
style.backgroundColor = resolveColorToCSS(section.style.background);
|
|
208
|
-
}
|
|
209
|
-
if (section.style.padding) {
|
|
210
|
-
const padding = typeof section.style.padding === "object" && "base" in section.style.padding ? section.style.padding.base : section.style.padding;
|
|
211
|
-
style.padding = padding;
|
|
212
|
-
}
|
|
213
|
-
if (section.style.border) {
|
|
214
|
-
const border = typeof section.style.border === "object" && "base" in section.style.border ? section.style.border.base : section.style.border;
|
|
215
|
-
if (border) {
|
|
216
|
-
style.border = `${border.width || "0"} ${border.style || "solid"} ${border.color ? resolveColorToCSS(border.color) : "transparent"}`;
|
|
217
|
-
if (border.radius) {
|
|
218
|
-
style.borderRadius = border.radius;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
return style;
|
|
223
|
-
}, [section]);
|
|
224
|
-
if (isContentSection(section)) {
|
|
225
|
-
return /* @__PURE__ */ jsx(
|
|
226
|
-
"div",
|
|
227
|
-
{
|
|
228
|
-
className: "footer-section footer-content-section",
|
|
229
|
-
style: sectionStyle,
|
|
230
|
-
"data-section-id": section.id,
|
|
231
|
-
children: section?.blocks?.map(
|
|
232
|
-
(block) => blockRegistry ? /* @__PURE__ */ jsx(
|
|
233
|
-
BlockRenderer$1,
|
|
234
|
-
{
|
|
235
|
-
block,
|
|
236
|
-
blockRegistry
|
|
237
|
-
},
|
|
238
|
-
block.id
|
|
239
|
-
) : /* @__PURE__ */ jsx(BlockRenderer, { block }, block.id)
|
|
240
|
-
)
|
|
241
|
-
}
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
return /* @__PURE__ */ jsx(
|
|
245
|
-
"div",
|
|
246
|
-
{
|
|
247
|
-
className: "footer-section footer-container-section",
|
|
248
|
-
style: sectionStyle,
|
|
249
|
-
"data-section-id": section.id,
|
|
250
|
-
children: section?.sections?.sort((a, b) => a.order - b.order)?.map((childSection) => /* @__PURE__ */ jsx(
|
|
251
|
-
FooterSectionComponent,
|
|
252
|
-
{
|
|
253
|
-
section: childSection,
|
|
254
|
-
footer,
|
|
255
|
-
site,
|
|
256
|
-
resolvedColors,
|
|
257
|
-
level: level + 1,
|
|
258
|
-
blockRegistry
|
|
259
|
-
},
|
|
260
|
-
childSection.id
|
|
261
|
-
))
|
|
262
|
-
}
|
|
263
|
-
);
|
|
264
|
-
};
|
|
265
|
-
var Footer = ({
|
|
266
|
-
footer,
|
|
267
|
-
site,
|
|
268
|
-
className = "",
|
|
269
|
-
id = "default",
|
|
270
|
-
blockRegistry
|
|
271
|
-
}) => {
|
|
272
|
-
const resolvedColors = resolveFooterColors(footer.style);
|
|
273
|
-
const styles = generateFooterCSS(id, footer, resolvedColors);
|
|
274
|
-
const sortedSections = [...footer.sections].sort((a, b) => a.order - b.order);
|
|
275
|
-
const containerBehavior = footer.style.container || "edged";
|
|
276
|
-
const sectionsContent = sortedSections.map((section) => {
|
|
277
|
-
const sectionElement = /* @__PURE__ */ jsx(
|
|
278
|
-
FooterSectionComponent,
|
|
279
|
-
{
|
|
280
|
-
section,
|
|
281
|
-
footer,
|
|
282
|
-
site,
|
|
283
|
-
resolvedColors,
|
|
284
|
-
blockRegistry
|
|
285
|
-
},
|
|
286
|
-
section.id
|
|
287
|
-
);
|
|
288
|
-
if (containerBehavior === "edged") {
|
|
289
|
-
return /* @__PURE__ */ jsx("div", { className: "container mx-auto", children: sectionElement }, section.id);
|
|
290
|
-
}
|
|
291
|
-
return sectionElement;
|
|
292
|
-
});
|
|
293
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
294
|
-
styles && /* @__PURE__ */ jsx("style", { children: styles }),
|
|
295
|
-
/* @__PURE__ */ jsx(
|
|
296
|
-
"footer",
|
|
297
|
-
{
|
|
298
|
-
className: cn(
|
|
299
|
-
{
|
|
300
|
-
"container mx-auto": containerBehavior === "boxed"
|
|
301
|
-
},
|
|
302
|
-
className
|
|
303
|
-
),
|
|
304
|
-
"data-footer-id": id,
|
|
305
|
-
"data-container": containerBehavior,
|
|
306
|
-
children: /* @__PURE__ */ jsx("div", { className: `footer-${id} footer-container`, children: sectionsContent })
|
|
307
|
-
}
|
|
308
|
-
)
|
|
309
|
-
] });
|
|
310
|
-
};
|
|
311
|
-
|
|
312
|
-
export { Footer };
|
|
313
|
-
//# sourceMappingURL=index.js.map
|
|
314
5
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/footer.utils.ts","../src/components/blocks/block-renderer.tsx","../src/components/footer/footer-section.tsx","../src/components/footer.tsx"],"names":["resolveColorToCSS","jsx","RegistryBlockRenderer"],"mappings":"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","file":"index.js","sourcesContent":["import {\n BorderConfig,\n FooterConfig,\n FooterContentSection,\n FooterSection,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { isResponsiveConfig } from \"@otl-core/cms-utils\";\nimport { resolveColorToCSS } from \"@otl-core/style-utils\";\n\n/**\n * Resolve all colors in the footer configuration to CSS values\n */\nexport function resolveFooterColors(\n style: FooterConfig[\"style\"],\n): Record<string, string | undefined> {\n const resolved: Record<string, string | undefined> = {\n background: resolveColorToCSS(style.background),\n text: resolveColorToCSS(style.text),\n linkColor: resolveColorToCSS(style.link.color),\n linkHoverColor: resolveColorToCSS(style.link.hoverColor),\n };\n\n return resolved;\n}\n\n/**\n * Resolve a responsive value to get the base value\n */\nfunction getResponsiveBase<T>(value: ResponsiveValue<T> | T): T {\n if (typeof value === \"object\" && value !== null && \"base\" in value) {\n return value.base;\n }\n return value as T;\n}\n\n/**\n * Resolve border config to CSS string\n */\nfunction resolveBorder(\n border: ResponsiveValue<BorderConfig> | undefined,\n): string {\n if (!border) return \"\";\n\n const base = getResponsiveBase(border);\n if (!base) return \"\";\n\n const width = base.width || \"0\";\n const style = base.style || \"solid\";\n const color = base.color ? resolveColorToCSS(base.color) : \"transparent\";\n\n return `${width} ${style} ${color}`;\n}\n\n/**\n * Generate CSS for the footer configuration\n */\nexport function generateFooterCSS(\n id: string,\n footer: FooterConfig,\n resolvedColors: Record<string, string | undefined>,\n): string {\n const cssBlocks: string[] = [];\n const containerBehavior = footer.style.container || \"edged\";\n\n // Base footer styles\n const baseMargin = getResponsiveBase(footer.style.layout.margin);\n const basePadding = getResponsiveBase(footer.style.layout.padding);\n const baseSectionGap = getResponsiveBase(footer.style.layout.sectionGap);\n const borderCSS = resolveBorder(footer.style.border);\n\n const baseStyles = `\n .footer-${id} {\n display: flex;\n flex-direction: column;\n ${resolvedColors.background ? `background-color: ${resolvedColors.background};` : \"\"}\n ${resolvedColors.text ? `color: ${resolvedColors.text};` : \"\"}\n ${baseMargin ? `margin: ${baseMargin};` : \"\"}\n ${basePadding ? `padding: ${basePadding};` : \"\"}\n ${borderCSS ? `border: ${borderCSS};` : \"\"}\n ${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : \"\"}\n ${baseSectionGap ? `gap: ${baseSectionGap};` : \"\"}\n }\n `;\n cssBlocks.push(baseStyles);\n\n // Container-specific styles\n if (containerBehavior === \"edged\") {\n // In edged mode, each container wrapper should be full width\n cssBlocks.push(`\n .footer-${id} > div.container {\n width: 100%;\n }\n `);\n }\n\n // Top-level sections (rows) should always be full width\n cssBlocks.push(`\n .footer-${id} .footer-section {\n width: 100%;\n }\n `);\n\n // Responsive layout for nested sections (columns within rows)\n // Mobile: stack all columns vertically\n cssBlocks.push(`\n @media (max-width: 767px) {\n .footer-${id} .footer-container-section {\n flex-wrap: wrap;\n }\n .footer-${id} .footer-container-section > .footer-content-section {\n flex: 1 1 100%;\n width: 100%;\n }\n }\n `);\n\n // Tablet: allow 2 columns per row\n cssBlocks.push(`\n @media (min-width: 768px) and (max-width: 1023px) {\n .footer-${id} .footer-container-section {\n flex-wrap: wrap;\n }\n .footer-${id} .footer-container-section > .footer-content-section {\n flex: 1 1 calc(50% - ${baseSectionGap || \"0px\"} / 2);\n min-width: 0;\n }\n }\n `);\n\n // Desktop: columns naturally fit based on their flex properties\n cssBlocks.push(`\n @media (min-width: 1024px) {\n .footer-${id} .footer-container-section {\n flex-wrap: nowrap;\n }\n .footer-${id} .footer-container-section > .footer-content-section {\n flex: 1 1 auto;\n min-width: 0;\n }\n }\n `);\n\n // Link styles\n if (resolvedColors.linkColor || resolvedColors.linkHoverColor) {\n cssBlocks.push(`\n .footer-${id} a {\n ${resolvedColors.linkColor ? `color: ${resolvedColors.linkColor};` : \"\"}\n text-decoration: none;\n transition: color 0.2s;\n }\n .footer-${id} a:hover {\n ${resolvedColors.linkHoverColor ? `color: ${resolvedColors.linkHoverColor};` : \"\"}\n }\n `);\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\n/**\n * Format shadow config to CSS box-shadow value\n */\nfunction formatShadow(shadow: ShadowConfig): string {\n const insetStr = shadow.inset ? \"inset \" : \"\";\n return `${insetStr}${shadow.offsetX} ${shadow.offsetY} ${shadow.blurRadius} ${shadow.spreadRadius} ${shadow.color}`;\n}\n\n/**\n * Minify CSS by removing extra whitespace\n */\nfunction minifyCSS(css: string): string {\n return css\n .replace(/\\s+/g, \" \")\n .replace(/\\s*{\\s*/g, \"{\")\n .replace(/\\s*}\\s*/g, \"}\")\n .replace(/\\s*:\\s*/g, \":\")\n .replace(/\\s*;\\s*/g, \";\")\n .replace(/;\\s*}/g, \"}\")\n .trim();\n}\n\n/**\n * Check if a section has nested sections (is a container section)\n */\nexport function isContainerSection(\n section: FooterSection | FooterContentSection,\n): section is FooterSection {\n return \"sections\" in section && Array.isArray(section.sections);\n}\n\n/**\n * Check if a section is a content section (has items)\n */\nexport function isContentSection(\n section: FooterSection | FooterContentSection,\n): section is FooterContentSection {\n return \"blocks\" in section && Array.isArray(section.blocks);\n}\n","/**\n * Block Renderer for Footer Components\n * Renders blocks within the footer context\n * This is a minimal implementation that supports the blocks commonly used in footers\n */\n\nimport { BlockInstance } from \"@otl-core/cms-types\";\nimport React from \"react\";\nimport ReactMarkdown from \"react-markdown\";\n\ninterface BlockRendererProps {\n block: BlockInstance;\n}\n\nexport const BlockRenderer: React.FC<BlockRendererProps> = ({ block }) => {\n const { type, config } = block;\n\n // Markdown block\n if (type === \"markdown\") {\n const content = (config as { content?: string }).content || \"\";\n return (\n <div className=\"footer-block footer-markdown\">\n <ReactMarkdown>{content}</ReactMarkdown>\n </div>\n );\n }\n\n // Link block\n if (type === \"link\") {\n const linkConfig = config as {\n text?: string;\n href?: string;\n external?: boolean;\n variant?: string;\n ariaLabel?: string;\n };\n\n const target = linkConfig.external ? \"_blank\" : undefined;\n const rel = linkConfig.external ? \"noopener noreferrer\" : undefined;\n\n const variantClasses = {\n default: \"footer-link hover:underline transition-colors\",\n underline: \"footer-link underline\",\n \"no-underline\": \"footer-link no-underline\",\n \"button-primary\":\n \"footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90\",\n \"button-secondary\":\n \"footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n \"button-outline\":\n \"footer-link inline-flex items-center justify-center px-4 py-2 rounded-md font-medium transition-colors border border-gray-200 text-surface-foreground hover:bg-accent hover:text-accent-foreground\",\n };\n\n const className =\n variantClasses[\n (linkConfig.variant as keyof typeof variantClasses) || \"default\"\n ];\n\n return (\n <a\n href={linkConfig.href}\n target={target}\n rel={rel}\n className={className}\n aria-label={linkConfig.ariaLabel || linkConfig.text}\n >\n {linkConfig.text}\n </a>\n );\n }\n\n // Button block (existing button rendering logic)\n if (type === \"button\") {\n const buttonConfig = config as {\n text?: string;\n url?: string;\n variant?: string;\n size?: string;\n newTab?: boolean;\n };\n\n const target = buttonConfig.newTab ? \"_blank\" : undefined;\n const rel = buttonConfig.newTab ? \"noopener noreferrer\" : undefined;\n\n return (\n <a\n href={buttonConfig.url}\n target={target}\n rel={rel}\n className=\"footer-block footer-button inline-flex items-center justify-center px-4 py-2 rounded-md transition-colors\"\n >\n {buttonConfig.text}\n </a>\n );\n }\n\n // Image block\n if (type === \"image\") {\n const imageConfig = config as {\n src?: string;\n alt?: string;\n width?: number;\n height?: number;\n };\n\n return (\n <div className=\"footer-block footer-image\">\n <img\n src={imageConfig.src}\n alt={imageConfig.alt || \"\"}\n width={imageConfig.width}\n height={imageConfig.height}\n />\n </div>\n );\n }\n\n // Divider block\n if (type === \"divider\") {\n return <hr className=\"footer-block footer-divider\" />;\n }\n\n // Fallback for unknown block types\n return null;\n};\n","import {\n Site,\n FooterConfig,\n FooterContentSection,\n FooterSection,\n} from \"@otl-core/cms-types\";\nimport React, { useMemo } from \"react\";\nimport { resolveColorToCSS } from \"@otl-core/style-utils\";\nimport { isContentSection } from \"../../lib/footer.utils\";\nimport { BlockRenderer as LocalBlockRenderer } from \"../blocks/block-renderer\";\nimport type { BlockRegistry } from \"@otl-core/block-registry\";\nimport { BlockRenderer as RegistryBlockRenderer } from \"@otl-core/block-registry\";\n\ninterface FooterSectionProps {\n section: FooterSection | FooterContentSection;\n footer: FooterConfig;\n site: Site;\n resolvedColors: Record<string, string | undefined>;\n level?: number;\n blockRegistry?: BlockRegistry;\n}\n\nexport const FooterSectionComponent: React.FC<FooterSectionProps> = ({\n section,\n footer,\n site,\n resolvedColors,\n level = 0,\n blockRegistry,\n}) => {\n const sectionStyle: React.CSSProperties = useMemo(() => {\n const style: React.CSSProperties = {\n display: \"flex\",\n flexDirection: section.type === \"row\" ? \"row\" : \"column\",\n alignItems: section.style.align || \"flex-start\",\n justifyContent: section.style.justify || \"flex-start\",\n gap: section.style.gap || \"0\",\n };\n\n if (section.style.flex) {\n style.flex = section.style.flex;\n }\n\n // Apply section-specific background\n if (section.style.background) {\n style.backgroundColor = resolveColorToCSS(section.style.background);\n }\n\n // Apply section-specific padding\n if (section.style.padding) {\n const padding =\n typeof section.style.padding === \"object\" &&\n \"base\" in section.style.padding\n ? section.style.padding.base\n : section.style.padding;\n style.padding = padding;\n }\n\n // Apply section-specific border\n if (section.style.border) {\n const border =\n typeof section.style.border === \"object\" &&\n \"base\" in section.style.border\n ? section.style.border.base\n : section.style.border;\n\n if (border) {\n style.border = `${border.width || \"0\"} ${border.style || \"solid\"} ${\n border.color ? resolveColorToCSS(border.color) : \"transparent\"\n }`;\n if (border.radius) {\n style.borderRadius = border.radius;\n }\n }\n }\n\n return style;\n }, [section]);\n\n // Content section - render blocks\n if (isContentSection(section)) {\n return (\n <div\n className=\"footer-section footer-content-section\"\n style={sectionStyle}\n data-section-id={section.id}\n >\n {section?.blocks?.map((block) =>\n blockRegistry ? (\n <RegistryBlockRenderer\n key={block.id}\n block={block}\n blockRegistry={blockRegistry}\n />\n ) : (\n <LocalBlockRenderer key={block.id} block={block} />\n ),\n )}\n </div>\n );\n }\n\n // Container section - render nested sections recursively\n return (\n <div\n className=\"footer-section footer-container-section\"\n style={sectionStyle}\n data-section-id={section.id}\n >\n {section?.sections\n ?.sort((a, b) => a.order - b.order)\n ?.map((childSection) => (\n <FooterSectionComponent\n key={childSection.id}\n section={childSection}\n footer={footer}\n site={site}\n resolvedColors={resolvedColors}\n level={level + 1}\n blockRegistry={blockRegistry}\n />\n ))}\n </div>\n );\n};\n","import { Site, FooterConfig } from \"@otl-core/cms-types\";\nimport type { BlockRegistry } from \"@otl-core/block-registry\";\nimport React from \"react\";\nimport { generateFooterCSS, resolveFooterColors } from \"../lib/footer.utils\";\nimport { cn } from \"@otl-core/style-utils\";\nimport { FooterSectionComponent } from \"./footer/footer-section\";\n\nexport interface FooterProps {\n footer: FooterConfig;\n site: Site;\n className?: string;\n id?: string;\n blockRegistry?: BlockRegistry;\n}\n\nexport const Footer: React.FC<FooterProps> = ({\n footer,\n site,\n className = \"\",\n id = \"default\",\n blockRegistry,\n}) => {\n const resolvedColors = resolveFooterColors(footer.style);\n const styles = generateFooterCSS(id, footer, resolvedColors);\n const sortedSections = [...footer.sections].sort((a, b) => a.order - b.order);\n const containerBehavior = footer.style.container || \"edged\";\n\n // Render sections with container wrapping per section for \"edged\" mode\n const sectionsContent = sortedSections.map((section) => {\n const sectionElement = (\n <FooterSectionComponent\n key={section.id}\n section={section}\n footer={footer}\n site={site}\n resolvedColors={resolvedColors}\n blockRegistry={blockRegistry}\n />\n );\n\n // In \"edged\" mode, wrap each top-level section in its own container\n if (containerBehavior === \"edged\") {\n return (\n <div key={section.id} className=\"container mx-auto\">\n {sectionElement}\n </div>\n );\n }\n\n return sectionElement;\n });\n\n return (\n <>\n {styles && <style>{styles}</style>}\n <footer\n className={cn(\n {\n \"container mx-auto\": containerBehavior === \"boxed\",\n },\n className,\n )}\n data-footer-id={id}\n data-container={containerBehavior}\n >\n <div className={`footer-${id} footer-container`}>{sectionsContent}</div>\n </footer>\n </>\n );\n};\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export { Footer } from \"./components/footer\";\n"],"mappings":"AAAA,SAAS,cAAc;","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { FooterConfig, FooterSection, FooterContentSection } from '@otl-core/cms-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Resolve all colors in the footer configuration to CSS values
|
|
5
|
+
*/
|
|
6
|
+
declare function resolveFooterColors(style: FooterConfig["style"]): Record<string, string | undefined>;
|
|
7
|
+
/**
|
|
8
|
+
* Generate CSS for the footer configuration
|
|
9
|
+
*/
|
|
10
|
+
declare function generateFooterCSS(id: string, footer: FooterConfig, resolvedColors: Record<string, string | undefined>): string;
|
|
11
|
+
/**
|
|
12
|
+
* Check if a section has nested sections (is a container section)
|
|
13
|
+
*/
|
|
14
|
+
declare function isContainerSection(section: FooterSection | FooterContentSection): section is FooterSection;
|
|
15
|
+
/**
|
|
16
|
+
* Check if a section is a content section (has items)
|
|
17
|
+
*/
|
|
18
|
+
declare function isContentSection(section: FooterSection | FooterContentSection): section is FooterContentSection;
|
|
19
|
+
|
|
20
|
+
export { generateFooterCSS, isContainerSection, isContentSection, resolveFooterColors };
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { isResponsiveConfig } from "@otl-core/cms-utils";
|
|
2
|
+
import { resolveColorToCSS } from "@otl-core/style-utils";
|
|
3
|
+
function resolveFooterColors(style) {
|
|
4
|
+
const resolved = {
|
|
5
|
+
background: resolveColorToCSS(style.background),
|
|
6
|
+
text: resolveColorToCSS(style.text),
|
|
7
|
+
linkColor: resolveColorToCSS(style.link.color),
|
|
8
|
+
linkHoverColor: resolveColorToCSS(style.link.hoverColor)
|
|
9
|
+
};
|
|
10
|
+
return resolved;
|
|
11
|
+
}
|
|
12
|
+
function getResponsiveBase(value) {
|
|
13
|
+
if (typeof value === "object" && value !== null && "base" in value) {
|
|
14
|
+
return value.base;
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function resolveBorder(border) {
|
|
19
|
+
if (!border) return "";
|
|
20
|
+
const base = getResponsiveBase(border);
|
|
21
|
+
if (!base) return "";
|
|
22
|
+
const width = base.width || "0";
|
|
23
|
+
const style = base.style || "solid";
|
|
24
|
+
const color = base.color ? resolveColorToCSS(base.color) : "transparent";
|
|
25
|
+
return `${width} ${style} ${color}`;
|
|
26
|
+
}
|
|
27
|
+
function generateFooterCSS(id, footer, resolvedColors) {
|
|
28
|
+
const cssBlocks = [];
|
|
29
|
+
const containerBehavior = footer.style.container || "edged";
|
|
30
|
+
const baseMargin = getResponsiveBase(footer.style.layout.margin);
|
|
31
|
+
const basePadding = getResponsiveBase(footer.style.layout.padding);
|
|
32
|
+
const baseSectionGap = getResponsiveBase(footer.style.layout.sectionGap);
|
|
33
|
+
const borderCSS = resolveBorder(footer.style.border);
|
|
34
|
+
const baseStyles = `
|
|
35
|
+
.footer-${id} {
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
${resolvedColors.background ? `background-color: ${resolvedColors.background};` : ""}
|
|
39
|
+
${resolvedColors.text ? `color: ${resolvedColors.text};` : ""}
|
|
40
|
+
${baseMargin ? `margin: ${baseMargin};` : ""}
|
|
41
|
+
${basePadding ? `padding: ${basePadding};` : ""}
|
|
42
|
+
${borderCSS ? `border: ${borderCSS};` : ""}
|
|
43
|
+
${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : ""}
|
|
44
|
+
${baseSectionGap ? `gap: ${baseSectionGap};` : ""}
|
|
45
|
+
}
|
|
46
|
+
`;
|
|
47
|
+
cssBlocks.push(baseStyles);
|
|
48
|
+
if (containerBehavior === "edged") {
|
|
49
|
+
cssBlocks.push(`
|
|
50
|
+
.footer-${id} > div.container {
|
|
51
|
+
width: 100%;
|
|
52
|
+
}
|
|
53
|
+
`);
|
|
54
|
+
}
|
|
55
|
+
cssBlocks.push(`
|
|
56
|
+
.footer-${id} .footer-section {
|
|
57
|
+
width: 100%;
|
|
58
|
+
}
|
|
59
|
+
`);
|
|
60
|
+
cssBlocks.push(`
|
|
61
|
+
@media (max-width: 767px) {
|
|
62
|
+
.footer-${id} .footer-container-section {
|
|
63
|
+
flex-wrap: wrap;
|
|
64
|
+
}
|
|
65
|
+
.footer-${id} .footer-container-section > .footer-content-section {
|
|
66
|
+
flex: 1 1 100%;
|
|
67
|
+
width: 100%;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`);
|
|
71
|
+
cssBlocks.push(`
|
|
72
|
+
@media (min-width: 768px) and (max-width: 1023px) {
|
|
73
|
+
.footer-${id} .footer-container-section {
|
|
74
|
+
flex-wrap: wrap;
|
|
75
|
+
}
|
|
76
|
+
.footer-${id} .footer-container-section > .footer-content-section {
|
|
77
|
+
flex: 1 1 calc(50% - ${baseSectionGap || "0px"} / 2);
|
|
78
|
+
min-width: 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
`);
|
|
82
|
+
cssBlocks.push(`
|
|
83
|
+
@media (min-width: 1024px) {
|
|
84
|
+
.footer-${id} .footer-container-section {
|
|
85
|
+
flex-wrap: nowrap;
|
|
86
|
+
}
|
|
87
|
+
.footer-${id} .footer-container-section > .footer-content-section {
|
|
88
|
+
flex: 1 1 auto;
|
|
89
|
+
min-width: 0;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
`);
|
|
93
|
+
if (resolvedColors.linkColor || resolvedColors.linkHoverColor) {
|
|
94
|
+
cssBlocks.push(`
|
|
95
|
+
.footer-${id} a {
|
|
96
|
+
${resolvedColors.linkColor ? `color: ${resolvedColors.linkColor};` : ""}
|
|
97
|
+
text-decoration: none;
|
|
98
|
+
transition: color 0.2s;
|
|
99
|
+
}
|
|
100
|
+
.footer-${id} a:hover {
|
|
101
|
+
${resolvedColors.linkHoverColor ? `color: ${resolvedColors.linkHoverColor};` : ""}
|
|
102
|
+
}
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
return minifyCSS(cssBlocks.filter(Boolean).join(""));
|
|
106
|
+
}
|
|
107
|
+
function formatShadow(shadow) {
|
|
108
|
+
const insetStr = shadow.inset ? "inset " : "";
|
|
109
|
+
return `${insetStr}${shadow.offsetX} ${shadow.offsetY} ${shadow.blurRadius} ${shadow.spreadRadius} ${shadow.color}`;
|
|
110
|
+
}
|
|
111
|
+
function minifyCSS(css) {
|
|
112
|
+
return css.replace(/\s+/g, " ").replace(/\s*{\s*/g, "{").replace(/\s*}\s*/g, "}").replace(/\s*:\s*/g, ":").replace(/\s*;\s*/g, ";").replace(/;\s*}/g, "}").trim();
|
|
113
|
+
}
|
|
114
|
+
function isContainerSection(section) {
|
|
115
|
+
return "sections" in section && Array.isArray(section.sections);
|
|
116
|
+
}
|
|
117
|
+
function isContentSection(section) {
|
|
118
|
+
return "blocks" in section && Array.isArray(section.blocks);
|
|
119
|
+
}
|
|
120
|
+
export {
|
|
121
|
+
generateFooterCSS,
|
|
122
|
+
isContainerSection,
|
|
123
|
+
isContentSection,
|
|
124
|
+
resolveFooterColors
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=footer.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/footer.utils.ts"],"sourcesContent":["import {\n BorderConfig,\n FooterConfig,\n FooterContentSection,\n FooterSection,\n ResponsiveValue,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { isResponsiveConfig } from \"@otl-core/cms-utils\";\nimport { resolveColorToCSS } from \"@otl-core/style-utils\";\n\n/**\n * Resolve all colors in the footer configuration to CSS values\n */\nexport function resolveFooterColors(\n style: FooterConfig[\"style\"],\n): Record<string, string | undefined> {\n const resolved: Record<string, string | undefined> = {\n background: resolveColorToCSS(style.background),\n text: resolveColorToCSS(style.text),\n linkColor: resolveColorToCSS(style.link.color),\n linkHoverColor: resolveColorToCSS(style.link.hoverColor),\n };\n\n return resolved;\n}\n\n/**\n * Resolve a responsive value to get the base value\n */\nfunction getResponsiveBase<T>(value: ResponsiveValue<T> | T): T {\n if (typeof value === \"object\" && value !== null && \"base\" in value) {\n return value.base;\n }\n return value as T;\n}\n\n/**\n * Resolve border config to CSS string\n */\nfunction resolveBorder(\n border: ResponsiveValue<BorderConfig> | undefined,\n): string {\n if (!border) return \"\";\n\n const base = getResponsiveBase(border);\n if (!base) return \"\";\n\n const width = base.width || \"0\";\n const style = base.style || \"solid\";\n const color = base.color ? resolveColorToCSS(base.color) : \"transparent\";\n\n return `${width} ${style} ${color}`;\n}\n\n/**\n * Generate CSS for the footer configuration\n */\nexport function generateFooterCSS(\n id: string,\n footer: FooterConfig,\n resolvedColors: Record<string, string | undefined>,\n): string {\n const cssBlocks: string[] = [];\n const containerBehavior = footer.style.container || \"edged\";\n\n // Base footer styles\n const baseMargin = getResponsiveBase(footer.style.layout.margin);\n const basePadding = getResponsiveBase(footer.style.layout.padding);\n const baseSectionGap = getResponsiveBase(footer.style.layout.sectionGap);\n const borderCSS = resolveBorder(footer.style.border);\n\n const baseStyles = `\n .footer-${id} {\n display: flex;\n flex-direction: column;\n ${resolvedColors.background ? `background-color: ${resolvedColors.background};` : \"\"}\n ${resolvedColors.text ? `color: ${resolvedColors.text};` : \"\"}\n ${baseMargin ? `margin: ${baseMargin};` : \"\"}\n ${basePadding ? `padding: ${basePadding};` : \"\"}\n ${borderCSS ? `border: ${borderCSS};` : \"\"}\n ${footer.style.shadow ? `box-shadow: ${formatShadow(isResponsiveConfig(footer.style.shadow) ? footer.style.shadow.base : footer.style.shadow)};` : \"\"}\n ${baseSectionGap ? `gap: ${baseSectionGap};` : \"\"}\n }\n `;\n cssBlocks.push(baseStyles);\n\n // Container-specific styles\n if (containerBehavior === \"edged\") {\n // In edged mode, each container wrapper should be full width\n cssBlocks.push(`\n .footer-${id} > div.container {\n width: 100%;\n }\n `);\n }\n\n // Top-level sections (rows) should always be full width\n cssBlocks.push(`\n .footer-${id} .footer-section {\n width: 100%;\n }\n `);\n\n // Responsive layout for nested sections (columns within rows)\n // Mobile: stack all columns vertically\n cssBlocks.push(`\n @media (max-width: 767px) {\n .footer-${id} .footer-container-section {\n flex-wrap: wrap;\n }\n .footer-${id} .footer-container-section > .footer-content-section {\n flex: 1 1 100%;\n width: 100%;\n }\n }\n `);\n\n // Tablet: allow 2 columns per row\n cssBlocks.push(`\n @media (min-width: 768px) and (max-width: 1023px) {\n .footer-${id} .footer-container-section {\n flex-wrap: wrap;\n }\n .footer-${id} .footer-container-section > .footer-content-section {\n flex: 1 1 calc(50% - ${baseSectionGap || \"0px\"} / 2);\n min-width: 0;\n }\n }\n `);\n\n // Desktop: columns naturally fit based on their flex properties\n cssBlocks.push(`\n @media (min-width: 1024px) {\n .footer-${id} .footer-container-section {\n flex-wrap: nowrap;\n }\n .footer-${id} .footer-container-section > .footer-content-section {\n flex: 1 1 auto;\n min-width: 0;\n }\n }\n `);\n\n // Link styles\n if (resolvedColors.linkColor || resolvedColors.linkHoverColor) {\n cssBlocks.push(`\n .footer-${id} a {\n ${resolvedColors.linkColor ? `color: ${resolvedColors.linkColor};` : \"\"}\n text-decoration: none;\n transition: color 0.2s;\n }\n .footer-${id} a:hover {\n ${resolvedColors.linkHoverColor ? `color: ${resolvedColors.linkHoverColor};` : \"\"}\n }\n `);\n }\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\n/**\n * Format shadow config to CSS box-shadow value\n */\nfunction formatShadow(shadow: ShadowConfig): string {\n const insetStr = shadow.inset ? \"inset \" : \"\";\n return `${insetStr}${shadow.offsetX} ${shadow.offsetY} ${shadow.blurRadius} ${shadow.spreadRadius} ${shadow.color}`;\n}\n\n/**\n * Minify CSS by removing extra whitespace\n */\nfunction minifyCSS(css: string): string {\n return css\n .replace(/\\s+/g, \" \")\n .replace(/\\s*{\\s*/g, \"{\")\n .replace(/\\s*}\\s*/g, \"}\")\n .replace(/\\s*:\\s*/g, \":\")\n .replace(/\\s*;\\s*/g, \";\")\n .replace(/;\\s*}/g, \"}\")\n .trim();\n}\n\n/**\n * Check if a section has nested sections (is a container section)\n */\nexport function isContainerSection(\n section: FooterSection | FooterContentSection,\n): section is FooterSection {\n return \"sections\" in section && Array.isArray(section.sections);\n}\n\n/**\n * Check if a section is a content section (has items)\n */\nexport function isContentSection(\n section: FooterSection | FooterContentSection,\n): section is FooterContentSection {\n return \"blocks\" in section && Array.isArray(section.blocks);\n}\n"],"mappings":"AAQA,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAK3B,SAAS,oBACd,OACoC;AACpC,QAAM,WAA+C;AAAA,IACnD,YAAY,kBAAkB,MAAM,UAAU;AAAA,IAC9C,MAAM,kBAAkB,MAAM,IAAI;AAAA,IAClC,WAAW,kBAAkB,MAAM,KAAK,KAAK;AAAA,IAC7C,gBAAgB,kBAAkB,MAAM,KAAK,UAAU;AAAA,EACzD;AAEA,SAAO;AACT;AAKA,SAAS,kBAAqB,OAAkC;AAC9D,MAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,OAAO;AAClE,WAAO,MAAM;AAAA,EACf;AACA,SAAO;AACT;AAKA,SAAS,cACP,QACQ;AACR,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,OAAO,kBAAkB,MAAM;AACrC,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,QAAQ,KAAK,SAAS;AAC5B,QAAM,QAAQ,KAAK,QAAQ,kBAAkB,KAAK,KAAK,IAAI;AAE3D,SAAO,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK;AACnC;AAKO,SAAS,kBACd,IACA,QACA,gBACQ;AACR,QAAM,YAAsB,CAAC;AAC7B,QAAM,oBAAoB,OAAO,MAAM,aAAa;AAGpD,QAAM,aAAa,kBAAkB,OAAO,MAAM,OAAO,MAAM;AAC/D,QAAM,cAAc,kBAAkB,OAAO,MAAM,OAAO,OAAO;AACjE,QAAM,iBAAiB,kBAAkB,OAAO,MAAM,OAAO,UAAU;AACvE,QAAM,YAAY,cAAc,OAAO,MAAM,MAAM;AAEnD,QAAM,aAAa;AAAA,cACP,EAAE;AAAA;AAAA;AAAA,QAGR,eAAe,aAAa,qBAAqB,eAAe,UAAU,MAAM,EAAE;AAAA,QAClF,eAAe,OAAO,UAAU,eAAe,IAAI,MAAM,EAAE;AAAA,QAC3D,aAAa,WAAW,UAAU,MAAM,EAAE;AAAA,QAC1C,cAAc,YAAY,WAAW,MAAM,EAAE;AAAA,QAC7C,YAAY,WAAW,SAAS,MAAM,EAAE;AAAA,QACxC,OAAO,MAAM,SAAS,eAAe,aAAa,mBAAmB,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM,OAAO,OAAO,OAAO,MAAM,MAAM,CAAC,MAAM,EAAE;AAAA,QACnJ,iBAAiB,QAAQ,cAAc,MAAM,EAAE;AAAA;AAAA;AAGrD,YAAU,KAAK,UAAU;AAGzB,MAAI,sBAAsB,SAAS;AAEjC,cAAU,KAAK;AAAA,gBACH,EAAE;AAAA;AAAA;AAAA,KAGb;AAAA,EACH;AAGA,YAAU,KAAK;AAAA,cACH,EAAE;AAAA;AAAA;AAAA,GAGb;AAID,YAAU,KAAK;AAAA;AAAA,gBAED,EAAE;AAAA;AAAA;AAAA,gBAGF,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,GAKf;AAGD,YAAU,KAAK;AAAA;AAAA,gBAED,EAAE;AAAA;AAAA;AAAA,gBAGF,EAAE;AAAA,+BACa,kBAAkB,KAAK;AAAA;AAAA;AAAA;AAAA,GAInD;AAGD,YAAU,KAAK;AAAA;AAAA,gBAED,EAAE;AAAA;AAAA;AAAA,gBAGF,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,GAKf;AAGD,MAAI,eAAe,aAAa,eAAe,gBAAgB;AAC7D,cAAU,KAAK;AAAA,gBACH,EAAE;AAAA,UACR,eAAe,YAAY,UAAU,eAAe,SAAS,MAAM,EAAE;AAAA;AAAA;AAAA;AAAA,gBAI/D,EAAE;AAAA,UACR,eAAe,iBAAiB,UAAU,eAAe,cAAc,MAAM,EAAE;AAAA;AAAA,KAEpF;AAAA,EACH;AAEA,SAAO,UAAU,UAAU,OAAO,OAAO,EAAE,KAAK,EAAE,CAAC;AACrD;AAKA,SAAS,aAAa,QAA8B;AAClD,QAAM,WAAW,OAAO,QAAQ,WAAW;AAC3C,SAAO,GAAG,QAAQ,GAAG,OAAO,OAAO,IAAI,OAAO,OAAO,IAAI,OAAO,UAAU,IAAI,OAAO,YAAY,IAAI,OAAO,KAAK;AACnH;AAKA,SAAS,UAAU,KAAqB;AACtC,SAAO,IACJ,QAAQ,QAAQ,GAAG,EACnB,QAAQ,YAAY,GAAG,EACvB,QAAQ,YAAY,GAAG,EACvB,QAAQ,YAAY,GAAG,EACvB,QAAQ,YAAY,GAAG,EACvB,QAAQ,UAAU,GAAG,EACrB,KAAK;AACV;AAKO,SAAS,mBACd,SAC0B;AAC1B,SAAO,cAAc,WAAW,MAAM,QAAQ,QAAQ,QAAQ;AAChE;AAKO,SAAS,iBACd,SACiC;AACjC,SAAO,YAAY,WAAW,MAAM,QAAQ,QAAQ,MAAM;AAC5D;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { HeaderSection, Site, HeaderConfig, LocalizedString, HeaderDropdownContent, ShadowConfig } from '@otl-core/cms-types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Convert ShadowConfig to CSS box-shadow string
|
|
5
|
+
*/
|
|
6
|
+
declare function shadowConfigToCSS(shadow: ShadowConfig): string;
|
|
7
|
+
declare function calculateNavigationWidth(sections: HeaderSection[], site?: Site): number;
|
|
8
|
+
type Breakpoint = "sm" | "md" | "lg" | "xl" | "2xl" | null;
|
|
9
|
+
declare function getBreakpointForWidth(estimatedWidth: number): Breakpoint;
|
|
10
|
+
declare function generateNavigationCSS(id: string, navigation: HeaderConfig, resolvedColors: Record<string, string | undefined>, dropdownIds?: string[]): string;
|
|
11
|
+
declare function sectionsToDropdownContent(sections: HeaderSection[]): HeaderDropdownContent[];
|
|
12
|
+
declare function resolveDropdownColor(colorRef: {
|
|
13
|
+
type: string;
|
|
14
|
+
value: string;
|
|
15
|
+
} | undefined, resolvedColors: Record<string, string | undefined>, fallback?: string): string | undefined;
|
|
16
|
+
declare function getLocalizedString(value: string | LocalizedString | null | undefined, site?: Site): string;
|
|
17
|
+
declare function parseMarkdownToHTML(markdown: string): string;
|
|
18
|
+
|
|
19
|
+
export { type Breakpoint, calculateNavigationWidth, generateNavigationCSS, getBreakpointForWidth, getLocalizedString, parseMarkdownToHTML, resolveDropdownColor, sectionsToDropdownContent, shadowConfigToCSS };
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { marked } from "marked";
|
|
2
|
+
import {
|
|
3
|
+
generateDesktopDropdownAnimations,
|
|
4
|
+
generateMobileMenuAnimations,
|
|
5
|
+
generateResponsiveSpacingCSS,
|
|
6
|
+
generateScrollbarStyles,
|
|
7
|
+
generateToggleIconAnimations,
|
|
8
|
+
minifyCSS
|
|
9
|
+
} from "@otl-core/style-utils";
|
|
10
|
+
function shadowConfigToCSS(shadow) {
|
|
11
|
+
const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;
|
|
12
|
+
const parts = [offsetX, offsetY, blurRadius, spreadRadius, color];
|
|
13
|
+
if (inset) {
|
|
14
|
+
return `inset ${parts.join(" ")}`;
|
|
15
|
+
}
|
|
16
|
+
return parts.join(" ");
|
|
17
|
+
}
|
|
18
|
+
function calculateNavigationWidth(sections, site) {
|
|
19
|
+
let totalWidth = 150;
|
|
20
|
+
for (const section of sections) {
|
|
21
|
+
for (const item of section?.items || []) {
|
|
22
|
+
if (item.type === "logo") continue;
|
|
23
|
+
const label = typeof item.label === "string" ? item.label : getLocalizedString(item.label, site) || "";
|
|
24
|
+
const labelLength = label.length;
|
|
25
|
+
if (item.type === "button") {
|
|
26
|
+
totalWidth += labelLength * 8 + 48;
|
|
27
|
+
} else if (item.type === "link" || item.type === "dropdown") {
|
|
28
|
+
totalWidth += labelLength * 8 + 24;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return totalWidth;
|
|
33
|
+
}
|
|
34
|
+
function getBreakpointForWidth(estimatedWidth) {
|
|
35
|
+
const MAX_USABLE_WIDTH = 1400;
|
|
36
|
+
if (estimatedWidth > MAX_USABLE_WIDTH) return null;
|
|
37
|
+
if (estimatedWidth <= 640) return "sm";
|
|
38
|
+
if (estimatedWidth <= 768) return "md";
|
|
39
|
+
if (estimatedWidth <= 1024) return "lg";
|
|
40
|
+
if (estimatedWidth <= 1280) return "xl";
|
|
41
|
+
return "2xl";
|
|
42
|
+
}
|
|
43
|
+
function generateNavigationCSS(id, navigation, resolvedColors, dropdownIds = []) {
|
|
44
|
+
const cssBlocks = [];
|
|
45
|
+
if (navigation.style) {
|
|
46
|
+
const headerCSS = generateResponsiveSpacingCSS(`header-${id}`, {
|
|
47
|
+
margin: navigation.style.layout?.margin
|
|
48
|
+
});
|
|
49
|
+
if (headerCSS) cssBlocks.push(headerCSS);
|
|
50
|
+
}
|
|
51
|
+
if (navigation.style) {
|
|
52
|
+
const navbarCSS = generateResponsiveSpacingCSS(`navbar-${id}`, {
|
|
53
|
+
border: navigation.style.border,
|
|
54
|
+
padding: navigation.style.layout?.padding,
|
|
55
|
+
gap: navigation.style.layout?.sectionGap,
|
|
56
|
+
shadow: navigation.style.shadow
|
|
57
|
+
});
|
|
58
|
+
if (navbarCSS) cssBlocks.push(navbarCSS);
|
|
59
|
+
}
|
|
60
|
+
if (navigation.style && dropdownIds.length > 0) {
|
|
61
|
+
dropdownIds.forEach((dropdownId) => {
|
|
62
|
+
const dropdownCSS = generateResponsiveSpacingCSS(
|
|
63
|
+
`navigation-dropdown-${dropdownId}`,
|
|
64
|
+
{
|
|
65
|
+
padding: navigation.style?.dropdown?.padding,
|
|
66
|
+
border: navigation.style?.dropdown?.border
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
if (dropdownCSS) cssBlocks.push(dropdownCSS);
|
|
70
|
+
const dropdownContentCSS = generateResponsiveSpacingCSS(
|
|
71
|
+
`dropdown-content-${dropdownId}`,
|
|
72
|
+
{
|
|
73
|
+
gap: navigation.style?.dropdown?.sectionGap
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (resolvedColors.burgerButtonBackgroundHover) {
|
|
80
|
+
cssBlocks.push(
|
|
81
|
+
`.mobile-menu-toggle-${id}:hover{background-color:${resolvedColors.burgerButtonBackgroundHover}!important}`
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
if (resolvedColors.dropdownMenuLinkHoverColor || resolvedColors.dropdownMenuLinkHoverBackground) {
|
|
85
|
+
const hoverStyles = [];
|
|
86
|
+
if (resolvedColors.dropdownMenuLinkHoverBackground) {
|
|
87
|
+
hoverStyles.push(
|
|
88
|
+
`background-color:${resolvedColors.dropdownMenuLinkHoverBackground}!important`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (resolvedColors.dropdownMenuLinkHoverColor) {
|
|
92
|
+
hoverStyles.push(
|
|
93
|
+
`color:${resolvedColors.dropdownMenuLinkHoverColor}!important`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
cssBlocks.push(
|
|
97
|
+
`#mobile-menu-dropdown-${id} a:hover{${hoverStyles.join(";")}}`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
cssBlocks.push(...generateToggleIconAnimations());
|
|
101
|
+
cssBlocks.push(...generateMobileMenuAnimations());
|
|
102
|
+
cssBlocks.push(...generateScrollbarStyles());
|
|
103
|
+
cssBlocks.push(...generateDesktopDropdownAnimations());
|
|
104
|
+
return minifyCSS(cssBlocks.filter(Boolean).join(""));
|
|
105
|
+
}
|
|
106
|
+
function sectionsToDropdownContent(sections) {
|
|
107
|
+
const result = [];
|
|
108
|
+
sections.forEach((section) => {
|
|
109
|
+
const items = section?.items?.filter((item) => {
|
|
110
|
+
if (item.type === "logo") return false;
|
|
111
|
+
const vis = item.visibility || (item.collapse === false ? "navbar-only" : void 0);
|
|
112
|
+
if (vis === "navbar-only") return false;
|
|
113
|
+
return true;
|
|
114
|
+
});
|
|
115
|
+
if (items?.length === 0) return;
|
|
116
|
+
items?.forEach((item) => {
|
|
117
|
+
if (item.type === "link") {
|
|
118
|
+
const config = item.config;
|
|
119
|
+
const navConfig = {
|
|
120
|
+
label: item.label || "",
|
|
121
|
+
href: config.href,
|
|
122
|
+
icon: config.icon,
|
|
123
|
+
external: config.external
|
|
124
|
+
};
|
|
125
|
+
result.push({
|
|
126
|
+
id: item.id,
|
|
127
|
+
type: "navigation-item",
|
|
128
|
+
config: navConfig
|
|
129
|
+
});
|
|
130
|
+
} else if (item.type === "button") {
|
|
131
|
+
const config = item.config;
|
|
132
|
+
const btnConfig = {
|
|
133
|
+
label: item.label || "",
|
|
134
|
+
href: config.href,
|
|
135
|
+
icon: config.icon,
|
|
136
|
+
external: config.external,
|
|
137
|
+
variant: config.variant,
|
|
138
|
+
size: config.size
|
|
139
|
+
};
|
|
140
|
+
result.push({
|
|
141
|
+
id: item.id,
|
|
142
|
+
type: "button",
|
|
143
|
+
config: btnConfig
|
|
144
|
+
});
|
|
145
|
+
} else if (item.type === "dropdown") {
|
|
146
|
+
const config = item.config;
|
|
147
|
+
result.push({
|
|
148
|
+
id: item.id,
|
|
149
|
+
type: "dropdown",
|
|
150
|
+
label: item.label || "",
|
|
151
|
+
config
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
if (sections.indexOf(section) < sections.length - 1) {
|
|
156
|
+
result.push({
|
|
157
|
+
id: `divider-${section.id}`,
|
|
158
|
+
type: "divider",
|
|
159
|
+
config: {}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
function resolveDropdownColor(colorRef, resolvedColors, fallback) {
|
|
166
|
+
if (!colorRef) return fallback;
|
|
167
|
+
if (colorRef.type === "custom") {
|
|
168
|
+
return colorRef.value;
|
|
169
|
+
}
|
|
170
|
+
if (colorRef.type === "theme") {
|
|
171
|
+
return resolvedColors[colorRef.value] || fallback;
|
|
172
|
+
}
|
|
173
|
+
if (colorRef.type === "variable") {
|
|
174
|
+
return `var(--color-${colorRef.value})`;
|
|
175
|
+
}
|
|
176
|
+
return fallback;
|
|
177
|
+
}
|
|
178
|
+
function getBrowserPreferredLocales(options = {}) {
|
|
179
|
+
const defaultOptions = {
|
|
180
|
+
languageCodeOnly: false
|
|
181
|
+
};
|
|
182
|
+
const opt = {
|
|
183
|
+
...defaultOptions,
|
|
184
|
+
...options
|
|
185
|
+
};
|
|
186
|
+
const browserLocales = navigator.languages === void 0 ? [navigator.language] : navigator.languages;
|
|
187
|
+
if (!browserLocales) {
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
return browserLocales.map((locale) => {
|
|
191
|
+
const trimmedLocale = locale.trim();
|
|
192
|
+
return opt.languageCodeOnly ? trimmedLocale.split(/-|_/)[0] : trimmedLocale;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function getLocalizedString(value, site) {
|
|
196
|
+
if (value === null || value === void 0) return "";
|
|
197
|
+
if (typeof value === "string") return value;
|
|
198
|
+
const preferredLocale = getBrowserPreferredLocales() || [
|
|
199
|
+
site?.default_locale || "en"
|
|
200
|
+
];
|
|
201
|
+
for (const locale of preferredLocale) {
|
|
202
|
+
if (locale in value && value[locale]) {
|
|
203
|
+
return value[locale];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (site?.default_locale && site.default_locale in value && value[site.default_locale]) {
|
|
207
|
+
return value[site.default_locale];
|
|
208
|
+
}
|
|
209
|
+
if ("en" in value && value.en) {
|
|
210
|
+
return value.en;
|
|
211
|
+
}
|
|
212
|
+
if (site?.supported_locales) {
|
|
213
|
+
for (const locale of site.supported_locales) {
|
|
214
|
+
if (locale in value && value[locale]) {
|
|
215
|
+
return value[locale];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const keys = Object.keys(value);
|
|
220
|
+
if (keys.length > 0 && value[keys[0]]) {
|
|
221
|
+
return value[keys[0]];
|
|
222
|
+
}
|
|
223
|
+
return "";
|
|
224
|
+
}
|
|
225
|
+
function parseMarkdownToHTML(markdown) {
|
|
226
|
+
const html = marked.parse(markdown, { async: false });
|
|
227
|
+
return html.replace(/<h1>/g, '<div class="h1">').replace(/<\/h1>/g, "</div>").replace(/<h2>/g, '<div class="h2">').replace(/<\/h2>/g, "</div>").replace(/<h3>/g, '<div class="h3">').replace(/<\/h3>/g, "</div>").replace(/<h4>/g, '<div class="h4">').replace(/<\/h4>/g, "</div>").replace(/<h5>/g, '<div class="h5">').replace(/<\/h5>/g, "</div>").replace(/<h6>/g, '<div class="h6">').replace(/<\/h6>/g, "</div>");
|
|
228
|
+
}
|
|
229
|
+
export {
|
|
230
|
+
calculateNavigationWidth,
|
|
231
|
+
generateNavigationCSS,
|
|
232
|
+
getBreakpointForWidth,
|
|
233
|
+
getLocalizedString,
|
|
234
|
+
parseMarkdownToHTML,
|
|
235
|
+
resolveDropdownColor,
|
|
236
|
+
sectionsToDropdownContent,
|
|
237
|
+
shadowConfigToCSS
|
|
238
|
+
};
|
|
239
|
+
//# sourceMappingURL=navigation.utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/lib/navigation.utils.ts"],"sourcesContent":["import {\n Site,\n HeaderConfig,\n HeaderDropdownButtonConfig,\n HeaderDropdownContent,\n HeaderDropdownNavigationItemConfig,\n HeaderNavigationItem,\n HeaderNavigationItemButtonConfig,\n HeaderNavigationItemDropdownConfig,\n HeaderNavigationItemLinkConfig,\n HeaderSection,\n LocalizedString,\n ShadowConfig,\n} from \"@otl-core/cms-types\";\nimport { marked } from \"marked\";\nimport {\n generateDesktopDropdownAnimations,\n generateMobileMenuAnimations,\n generateResponsiveSpacingCSS,\n generateScrollbarStyles,\n generateToggleIconAnimations,\n minifyCSS,\n} from \"@otl-core/style-utils\";\n\n/**\n * Convert ShadowConfig to CSS box-shadow string\n */\nexport function shadowConfigToCSS(shadow: ShadowConfig): string {\n const { offsetX, offsetY, blurRadius, spreadRadius, color, inset } = shadow;\n const parts = [offsetX, offsetY, blurRadius, spreadRadius, color];\n if (inset) {\n return `inset ${parts.join(\" \")}`;\n }\n return parts.join(\" \");\n}\n\nexport function calculateNavigationWidth(\n sections: HeaderSection[],\n site?: Site,\n): number {\n let totalWidth = 150;\n\n for (const section of sections) {\n for (const item of section?.items || []) {\n if (item.type === \"logo\") continue;\n\n const label =\n typeof item.label === \"string\"\n ? item.label\n : getLocalizedString(item.label, site) || \"\";\n const labelLength = label.length;\n\n if (item.type === \"button\") {\n totalWidth += labelLength * 8 + 48;\n } else if (item.type === \"link\" || item.type === \"dropdown\") {\n totalWidth += labelLength * 8 + 24;\n }\n }\n }\n\n return totalWidth;\n}\n\nexport type Breakpoint = \"sm\" | \"md\" | \"lg\" | \"xl\" | \"2xl\" | null;\n\nexport function getBreakpointForWidth(estimatedWidth: number): Breakpoint {\n const MAX_USABLE_WIDTH = 1400;\n\n if (estimatedWidth > MAX_USABLE_WIDTH) return null;\n\n if (estimatedWidth <= 640) return \"sm\";\n if (estimatedWidth <= 768) return \"md\";\n if (estimatedWidth <= 1024) return \"lg\";\n if (estimatedWidth <= 1280) return \"xl\";\n return \"2xl\";\n}\n\nexport function generateNavigationCSS(\n id: string,\n navigation: HeaderConfig,\n resolvedColors: Record<string, string | undefined>,\n dropdownIds: string[] = [],\n): string {\n const cssBlocks: (string | null)[] = [];\n\n if (navigation.style) {\n const headerCSS = generateResponsiveSpacingCSS(`header-${id}`, {\n margin: navigation.style.layout?.margin,\n });\n if (headerCSS) cssBlocks.push(headerCSS);\n }\n\n if (navigation.style) {\n const navbarCSS = generateResponsiveSpacingCSS(`navbar-${id}`, {\n border: navigation.style.border,\n padding: navigation.style.layout?.padding,\n gap: navigation.style.layout?.sectionGap,\n shadow: navigation.style.shadow,\n });\n if (navbarCSS) cssBlocks.push(navbarCSS);\n }\n\n if (navigation.style && dropdownIds.length > 0) {\n dropdownIds.forEach((dropdownId) => {\n const dropdownCSS = generateResponsiveSpacingCSS(\n `navigation-dropdown-${dropdownId}`,\n {\n padding: navigation.style?.dropdown?.padding,\n border: navigation.style?.dropdown?.border,\n },\n );\n if (dropdownCSS) cssBlocks.push(dropdownCSS);\n\n const dropdownContentCSS = generateResponsiveSpacingCSS(\n `dropdown-content-${dropdownId}`,\n {\n gap: navigation.style?.dropdown?.sectionGap,\n },\n );\n if (dropdownContentCSS) cssBlocks.push(dropdownContentCSS);\n });\n }\n\n if (resolvedColors.burgerButtonBackgroundHover) {\n cssBlocks.push(\n `.mobile-menu-toggle-${id}:hover{background-color:${resolvedColors.burgerButtonBackgroundHover}!important}`,\n );\n }\n\n if (\n resolvedColors.dropdownMenuLinkHoverColor ||\n resolvedColors.dropdownMenuLinkHoverBackground\n ) {\n const hoverStyles: string[] = [];\n if (resolvedColors.dropdownMenuLinkHoverBackground) {\n hoverStyles.push(\n `background-color:${resolvedColors.dropdownMenuLinkHoverBackground}!important`,\n );\n }\n if (resolvedColors.dropdownMenuLinkHoverColor) {\n hoverStyles.push(\n `color:${resolvedColors.dropdownMenuLinkHoverColor}!important`,\n );\n }\n cssBlocks.push(\n `#mobile-menu-dropdown-${id} a:hover{${hoverStyles.join(\";\")}}`,\n );\n }\n\n cssBlocks.push(...generateToggleIconAnimations());\n cssBlocks.push(...generateMobileMenuAnimations());\n cssBlocks.push(...generateScrollbarStyles());\n cssBlocks.push(...generateDesktopDropdownAnimations());\n\n return minifyCSS(cssBlocks.filter(Boolean).join(\"\"));\n}\n\nexport function sectionsToDropdownContent(\n sections: HeaderSection[],\n): HeaderDropdownContent[] {\n const result: HeaderDropdownContent[] = [];\n\n sections.forEach((section: HeaderSection) => {\n const items = section?.items?.filter((item: HeaderNavigationItem) => {\n if (item.type === \"logo\") return false;\n const vis =\n item.visibility ||\n ((item as unknown as Record<string, unknown>).collapse === false\n ? \"navbar-only\"\n : undefined);\n if (vis === \"navbar-only\") return false;\n return true;\n });\n\n if (items?.length === 0) return;\n\n items?.forEach((item: HeaderNavigationItem) => {\n if (item.type === \"link\") {\n const config = item.config as HeaderNavigationItemLinkConfig;\n const navConfig: HeaderDropdownNavigationItemConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n };\n result.push({\n id: item.id,\n type: \"navigation-item\",\n config: navConfig,\n });\n } else if (item.type === \"button\") {\n const config = item.config as HeaderNavigationItemButtonConfig;\n const btnConfig: HeaderDropdownButtonConfig = {\n label: item.label || \"\",\n href: config.href,\n icon: config.icon,\n external: config.external,\n variant: config.variant,\n size: config.size,\n };\n result.push({\n id: item.id,\n type: \"button\",\n config: btnConfig,\n });\n } else if (item.type === \"dropdown\") {\n const config = item.config as HeaderNavigationItemDropdownConfig;\n result.push({\n id: item.id,\n type: \"dropdown\",\n label: item.label || \"\",\n config,\n });\n }\n });\n\n if (sections.indexOf(section) < sections.length - 1) {\n result.push({\n id: `divider-${section.id}`,\n type: \"divider\",\n config: {},\n });\n }\n });\n\n return result;\n}\n\nexport function resolveDropdownColor(\n colorRef: { type: string; value: string } | undefined,\n resolvedColors: Record<string, string | undefined>,\n fallback?: string,\n): string | undefined {\n if (!colorRef) return fallback;\n\n if (colorRef.type === \"custom\") {\n return colorRef.value;\n }\n\n if (colorRef.type === \"theme\") {\n return resolvedColors[colorRef.value] || fallback;\n }\n\n if (colorRef.type === \"variable\") {\n // For variables, construct the CSS variable reference\n return `var(--color-${colorRef.value})`;\n }\n\n return fallback;\n}\n\nfunction getBrowserPreferredLocales(options = {}) {\n const defaultOptions = {\n languageCodeOnly: false,\n };\n const opt = {\n ...defaultOptions,\n ...options,\n };\n const browserLocales =\n navigator.languages === undefined\n ? [navigator.language]\n : navigator.languages;\n if (!browserLocales) {\n return undefined;\n }\n return browserLocales.map((locale) => {\n const trimmedLocale = locale.trim();\n return opt.languageCodeOnly ? trimmedLocale.split(/-|_/)[0] : trimmedLocale;\n });\n}\n\nexport function getLocalizedString(\n value: string | LocalizedString | null | undefined,\n site?: Site,\n): string {\n // Handle null/undefined\n if (value === null || value === undefined) return \"\";\n\n // If it's already a string, return it\n if (typeof value === \"string\") return value;\n\n // Get the preferred locale from options or use default fallback\n const preferredLocale = getBrowserPreferredLocales() || [\n site?.default_locale || \"en\",\n ];\n\n // Try preferred locale\n for (const locale of preferredLocale) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n\n // Try default locale\n if (\n site?.default_locale &&\n site.default_locale in value &&\n value[site.default_locale]\n ) {\n return value[site.default_locale];\n }\n\n // Try 'en' as fallback\n if (\"en\" in value && value.en) {\n return value.en;\n }\n\n // Try any supported locale\n if (site?.supported_locales) {\n for (const locale of site.supported_locales) {\n if (locale in value && value[locale]) {\n return value[locale];\n }\n }\n }\n\n // Return first available value as last resort\n const keys = Object.keys(value);\n if (keys.length > 0 && value[keys[0]]) {\n return value[keys[0]];\n }\n\n return \"\";\n}\n\nexport function parseMarkdownToHTML(markdown: string): string {\n // Parse markdown to HTML\n const html = marked.parse(markdown, { async: false }) as string;\n\n // Transform h1-h6 elements to divs with corresponding classes\n return html\n .replace(/<h1>/g, '<div class=\"h1\">')\n .replace(/<\\/h1>/g, \"</div>\")\n .replace(/<h2>/g, '<div class=\"h2\">')\n .replace(/<\\/h2>/g, \"</div>\")\n .replace(/<h3>/g, '<div class=\"h3\">')\n .replace(/<\\/h3>/g, \"</div>\")\n .replace(/<h4>/g, '<div class=\"h4\">')\n .replace(/<\\/h4>/g, \"</div>\")\n .replace(/<h5>/g, '<div class=\"h5\">')\n .replace(/<\\/h5>/g, \"</div>\")\n .replace(/<h6>/g, '<div class=\"h6\">')\n .replace(/<\\/h6>/g, \"</div>\");\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@otl-core/next-footer",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Reusable footer components for OTL CMS",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,14 +49,14 @@
|
|
|
49
49
|
"tailwind-merge": "^3.3.1"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@otl-core/block-registry": "^1.1.
|
|
53
|
-
"@otl-core/cms-utils": "^1.1.
|
|
54
|
-
"@otl-core/style-utils": "^1.1.
|
|
52
|
+
"@otl-core/block-registry": "^1.1.20",
|
|
53
|
+
"@otl-core/cms-utils": "^1.1.20",
|
|
54
|
+
"@otl-core/style-utils": "^1.1.20"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@eslint/eslintrc": "^3.3.1",
|
|
58
|
-
"@otl-core/cms-types": "^1.1.
|
|
59
|
-
"@otl-core/cms-utils": "^1.1.
|
|
58
|
+
"@otl-core/cms-types": "^1.1.20",
|
|
59
|
+
"@otl-core/cms-utils": "^1.1.20",
|
|
60
60
|
"@radix-ui/react-focus-scope": "^1.1.7",
|
|
61
61
|
"@radix-ui/react-slot": "^1.2.3",
|
|
62
62
|
"@testing-library/jest-dom": "^6.9.1",
|