lib-pixelbuild 0.2.0 → 0.2.2
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/builders/PageBuilder.js +7 -3
- package/dist/components/ButtonsComponent.d.ts +5 -0
- package/dist/components/ButtonsComponent.js +44 -0
- package/dist/components/CardComponent.js +31 -6
- package/dist/components/FormComponent.js +8 -4
- package/dist/components/{CarouselComponent.d.ts → ImageComponent.d.ts} +3 -2
- package/dist/components/ImageComponent.js +17 -0
- package/dist/components/ListComponent.js +5 -1
- package/dist/components/MapComponent.js +4 -4
- package/dist/components/SliderComponent.d.ts +1 -2
- package/dist/components/SliderComponent.js +175 -93
- package/dist/components/SocialIconsComponent.d.ts +3 -2
- package/dist/components/SocialIconsComponent.js +20 -15
- package/dist/components/TextComponent.js +3 -2
- package/dist/constants/ComponentEnum.d.ts +1 -0
- package/dist/constants/ComponentEnum.js +1 -0
- package/dist/elements/ButtonElement.js +19 -6
- package/dist/elements/ElementColWrapper.js +10 -1
- package/dist/elements/IconElement.js +5 -5
- package/dist/elements/IconMap.js +101 -28
- package/dist/elements/InputElement.js +4 -3
- package/dist/elements/TextElement.js +1 -1
- package/dist/factories/ButtonActionFactory.d.ts +3 -4
- package/dist/factories/ButtonActionFactory.js +2 -2
- package/dist/factories/ComponentFactory.js +6 -3
- package/dist/index.d.ts +5 -2
- package/dist/index.js +2 -0
- package/dist/layouts/Footer.js +1 -1
- package/dist/layouts/Header.js +29 -13
- package/dist/layouts/SiteLayout.d.ts +8 -1
- package/dist/layouts/SiteLayout.js +35 -3
- package/dist/renderers/SectionRenderer.js +26 -9
- package/dist/services/EmailService.d.ts +14 -5
- package/dist/services/EmailService.js +21 -22
- package/dist/stores/UseFormStore.d.ts +7 -2
- package/dist/stores/UseFormStore.js +8 -3
- package/dist/types/ElementType.d.ts +1 -0
- package/dist/types/EmailSettingsType.d.ts +5 -0
- package/dist/types/EmailSettingsType.js +1 -0
- package/dist/types/HeaderPropertiesType.d.ts +1 -0
- package/dist/types/MailBodyType.d.ts +2 -0
- package/dist/types/SocialPropertiesType.d.ts +3 -11
- package/dist/types/StylesType.d.ts +12 -0
- package/dist/types/WebsitePropertiesType.d.ts +2 -0
- package/dist/types/WebsiteType.d.ts +1 -0
- package/dist/utils/emailTemplate.d.ts +7 -0
- package/dist/utils/emailTemplate.js +66 -0
- package/dist/utils/fonts.d.ts +2 -0
- package/dist/utils/fonts.js +10 -0
- package/dist/utils/imageCustomization.d.ts +3 -0
- package/dist/utils/imageCustomization.js +11 -0
- package/dist/utils/responsiveProperties.d.ts +2 -0
- package/dist/utils/responsiveProperties.js +28 -0
- package/dist/utils/responsiveStyles.d.ts +6 -0
- package/dist/utils/responsiveStyles.js +82 -0
- package/package.json +2 -4
- package/dist/components/CarouselComponent.js +0 -6
- package/dist/layouts/Menu.d.ts +0 -5
- package/dist/layouts/Menu.js +0 -34
|
@@ -2,11 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Suspense, memo, useMemo } from 'react';
|
|
3
3
|
import { Helmet } from 'react-helmet-async';
|
|
4
4
|
import { SectionRenderer } from '../renderers/SectionRenderer.js';
|
|
5
|
+
import { buildResponsiveCssForStyles } from '../utils/responsiveStyles.js';
|
|
6
|
+
import { buildFontFamily } from '../utils/fonts.js';
|
|
5
7
|
function mergeStyles(websiteStyles, pageStyles) {
|
|
6
8
|
const merged = Object.assign({}, websiteStyles);
|
|
7
9
|
for (const key of Object.keys(pageStyles)) {
|
|
8
10
|
const val = pageStyles[key];
|
|
9
11
|
if (val !== '' && val !== null && val !== undefined) {
|
|
12
|
+
;
|
|
10
13
|
merged[key] = val;
|
|
11
14
|
}
|
|
12
15
|
}
|
|
@@ -31,6 +34,7 @@ const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
|
|
|
31
34
|
backgroundPosition: toCssValue(mergedStyles.backgroundPosition),
|
|
32
35
|
width: toCssValue(mergedStyles.width),
|
|
33
36
|
height: toCssValue(mergedStyles.height),
|
|
37
|
+
fontFamily: buildFontFamily(mergedStyles.fontFamily),
|
|
34
38
|
fontSize: toCssValue(mergedStyles.fontSize),
|
|
35
39
|
fontWeight: toCssValue(mergedStyles.fontWeight),
|
|
36
40
|
textAlign: mergedStyles.textAlign,
|
|
@@ -41,8 +45,8 @@ const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
|
|
|
41
45
|
marginTop: toCssValue(mergedStyles.marginTop),
|
|
42
46
|
marginBottom: toCssValue(mergedStyles.marginBottom),
|
|
43
47
|
borderRadius: toCssValue(mergedStyles.borderRadius),
|
|
44
|
-
minHeight:
|
|
45
|
-
}), [mergedStyles
|
|
46
|
-
return (_jsxs(Suspense, { fallback: _jsx("div", { children: website.properties.loadingMessage }), children: [!editionMode && (_jsxs(Helmet, { children: [_jsx("title", { children: page.title }), _jsx("meta", { name: "description", content: page.title }), _jsx("meta", { property: "og:title", content: page.title }), _jsx("meta", { property: "og:description", content: page.title }), _jsx("meta", { property: "og:image", content: page.title })] })), _jsxs("div", { style: pageStyle, children: [_jsx(SectionRenderer, { sections: page.sections, editionMode: editionMode }), page.sections.length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "No sections configured. Use the layout editor to add content." }))] })] }));
|
|
48
|
+
minHeight: '100vh'
|
|
49
|
+
}), [mergedStyles]);
|
|
50
|
+
return (_jsxs(Suspense, { fallback: _jsx("div", { children: website.properties.loadingMessage }), children: [!editionMode && (_jsxs(Helmet, { children: [_jsx("title", { children: page.title }), _jsx("meta", { name: "description", content: page.title }), _jsx("meta", { property: "og:title", content: page.title }), _jsx("meta", { property: "og:description", content: page.title }), _jsx("meta", { property: "og:image", content: page.title })] })), _jsxs("div", { style: pageStyle, "data-pb-page": true, children: [_jsx("style", { children: buildResponsiveCssForStyles('[data-pb-page]', page.styles) }), _jsx(SectionRenderer, { sections: page.sections, editionMode: editionMode }), page.sections.length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "No sections configured. Use the layout editor to add content." }))] })] }));
|
|
47
51
|
});
|
|
48
52
|
export { PageBuilder };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useMemo } from 'react';
|
|
3
|
+
import { Button, Container } from 'react-bootstrap';
|
|
4
|
+
import { orderBySort } from '../utils/orderBySort.js';
|
|
5
|
+
import { getString, getNumber, getBoolean } from '../utils/propertyUtils.js';
|
|
6
|
+
const ALIGN_JUSTIFY = {
|
|
7
|
+
left: 'flex-start',
|
|
8
|
+
center: 'center',
|
|
9
|
+
right: 'flex-end',
|
|
10
|
+
};
|
|
11
|
+
const ButtonsComponent = memo(function ButtonsComponent({ component }) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
|
|
14
|
+
const properties = component.properties || {};
|
|
15
|
+
const isColumn = getString(properties, 'layout', 'row') === 'column';
|
|
16
|
+
const gap = (_a = getNumber(properties, 'gap', 12)) !== null && _a !== void 0 ? _a : 12;
|
|
17
|
+
const fullWidth = getBoolean(properties, 'fullWidth', false);
|
|
18
|
+
const align = (_b = ALIGN_JUSTIFY[getString(properties, 'align', 'left')]) !== null && _b !== void 0 ? _b : 'flex-start';
|
|
19
|
+
const containerStyle = {
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: isColumn ? 'column' : 'row',
|
|
22
|
+
flexWrap: 'wrap',
|
|
23
|
+
gap: `${gap}px`,
|
|
24
|
+
};
|
|
25
|
+
if (isColumn)
|
|
26
|
+
containerStyle.alignItems = align;
|
|
27
|
+
else
|
|
28
|
+
containerStyle.justifyContent = align;
|
|
29
|
+
return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx("div", { style: containerStyle, children: elements.map((element) => {
|
|
30
|
+
const props = element.properties || {};
|
|
31
|
+
const href = getString(props, 'path') || getString(props, 'href');
|
|
32
|
+
const text = getString(props, 'text') || getString(props, 'title');
|
|
33
|
+
const size = getString(props, 'size');
|
|
34
|
+
const style = Object.assign({}, element.styles);
|
|
35
|
+
if (fullWidth) {
|
|
36
|
+
if (isColumn)
|
|
37
|
+
style.width = '100%';
|
|
38
|
+
else
|
|
39
|
+
style.flex = '1 1 0%';
|
|
40
|
+
}
|
|
41
|
+
return (_jsx(Button, { "data-pb-element": element.id, as: href ? 'a' : 'button', variant: getString(props, 'variant', 'primary'), size: size === 'sm' || size === 'lg' ? size : undefined, href: href || undefined, target: href ? getString(props, 'target', '_self') : undefined, rel: href ? 'noopener noreferrer' : undefined, style: style, children: text }, element.id));
|
|
42
|
+
}) }) }));
|
|
43
|
+
});
|
|
44
|
+
export { ButtonsComponent };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useMemo } from 'react';
|
|
3
3
|
import { Row, Container } from 'react-bootstrap';
|
|
4
4
|
import { ElementFactory } from '../factories/ElementFactory.js';
|
|
@@ -24,7 +24,13 @@ function applyCardStyles(element, props) {
|
|
|
24
24
|
if (props.cardTextSize)
|
|
25
25
|
overrides.fontSize = props.cardTextSize;
|
|
26
26
|
}
|
|
27
|
-
return Object.assign(Object.assign({}, element), { styles: Object.assign(Object.assign({}, element.styles), overrides) });
|
|
27
|
+
return Object.assign(Object.assign({}, element), { styles: Object.assign(Object.assign({}, element.styles), overrides), fullBleed: element.elementType === 'image' ? true : element.fullBleed });
|
|
28
|
+
}
|
|
29
|
+
function stripWidth(element) {
|
|
30
|
+
return Object.assign(Object.assign({}, element), { width: {} });
|
|
31
|
+
}
|
|
32
|
+
function centerStyles(element) {
|
|
33
|
+
return Object.assign(Object.assign({}, element), { width: {}, styles: Object.assign(Object.assign({}, element.styles), { textAlign: 'center' }) });
|
|
28
34
|
}
|
|
29
35
|
const CardComponent = memo(function CardComponent({ component }) {
|
|
30
36
|
const { properties } = component;
|
|
@@ -38,7 +44,7 @@ const CardComponent = memo(function CardComponent({ component }) {
|
|
|
38
44
|
cardTitleColor: properties === null || properties === void 0 ? void 0 : properties.cardTitleColor,
|
|
39
45
|
cardTitleSize: properties === null || properties === void 0 ? void 0 : properties.cardTitleSize,
|
|
40
46
|
cardTextColor: properties === null || properties === void 0 ? void 0 : properties.cardTextColor,
|
|
41
|
-
cardTextSize: properties === null || properties === void 0 ? void 0 : properties.cardTextSize
|
|
47
|
+
cardTextSize: properties === null || properties === void 0 ? void 0 : properties.cardTextSize
|
|
42
48
|
}), [
|
|
43
49
|
properties === null || properties === void 0 ? void 0 : properties.cardElement1,
|
|
44
50
|
properties === null || properties === void 0 ? void 0 : properties.cardElement2,
|
|
@@ -49,14 +55,14 @@ const CardComponent = memo(function CardComponent({ component }) {
|
|
|
49
55
|
properties === null || properties === void 0 ? void 0 : properties.cardTitleColor,
|
|
50
56
|
properties === null || properties === void 0 ? void 0 : properties.cardTitleSize,
|
|
51
57
|
properties === null || properties === void 0 ? void 0 : properties.cardTextColor,
|
|
52
|
-
properties === null || properties === void 0 ? void 0 : properties.cardTextSize
|
|
58
|
+
properties === null || properties === void 0 ? void 0 : properties.cardTextSize
|
|
53
59
|
]);
|
|
54
60
|
const orderedElements = useMemo(() => {
|
|
55
61
|
const cardOrder = [
|
|
56
62
|
cardProps.cardElement1,
|
|
57
63
|
cardProps.cardElement2,
|
|
58
64
|
cardProps.cardElement3,
|
|
59
|
-
cardProps.cardElement4
|
|
65
|
+
cardProps.cardElement4
|
|
60
66
|
].filter((v) => typeof v === 'string' && v.length > 0);
|
|
61
67
|
if (cardOrder.length > 0) {
|
|
62
68
|
return cardOrder
|
|
@@ -64,8 +70,27 @@ const CardComponent = memo(function CardComponent({ component }) {
|
|
|
64
70
|
.filter((el) => el !== undefined);
|
|
65
71
|
}
|
|
66
72
|
return orderBySort(component.elements);
|
|
67
|
-
}, [
|
|
73
|
+
}, [
|
|
74
|
+
cardProps.cardElement1,
|
|
75
|
+
cardProps.cardElement2,
|
|
76
|
+
cardProps.cardElement3,
|
|
77
|
+
cardProps.cardElement4,
|
|
78
|
+
component.elements
|
|
79
|
+
]);
|
|
68
80
|
const elements = useMemo(() => orderedElements.map((el) => applyCardStyles(el, cardProps)), [orderedElements, cardProps]);
|
|
81
|
+
const layout = String((properties === null || properties === void 0 ? void 0 : properties.cardLayout) || 'stacked');
|
|
82
|
+
if (layout === 'icon-left' || layout === 'icon-right') {
|
|
83
|
+
const icon = elements.find((element) => element.elementType === 'icon');
|
|
84
|
+
const others = elements.filter((element) => element !== icon);
|
|
85
|
+
const iconBox = icon ? _jsx("div", { style: { flex: '0 0 auto' }, children: elementFactory.build(stripWidth(icon)) }) : null;
|
|
86
|
+
const contentBox = _jsx("div", { style: { flex: '1 1 220px', minWidth: 0 }, children: others.map((element) => elementFactory.build(stripWidth(element))) });
|
|
87
|
+
return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: '1rem', flexWrap: 'wrap' }, children: [layout === 'icon-left' ? iconBox : contentBox, layout === 'icon-left' ? contentBox : iconBox] }) }));
|
|
88
|
+
}
|
|
89
|
+
if (layout === 'icon-top') {
|
|
90
|
+
const icon = elements.find((element) => element.elementType === 'icon');
|
|
91
|
+
const others = elements.filter((element) => element !== icon);
|
|
92
|
+
return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsxs("div", { style: { textAlign: 'center' }, children: [icon && _jsx("div", { style: { display: 'inline-block' }, children: elementFactory.build(centerStyles(icon)) }), _jsx("div", { children: others.map((element) => elementFactory.build(centerStyles(element))) })] }) }));
|
|
93
|
+
}
|
|
69
94
|
return (_jsx(Container, { style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
|
|
70
95
|
});
|
|
71
96
|
export { CardComponent };
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useEffect, useMemo } from 'react';
|
|
3
|
-
import { Form, Row } from 'react-bootstrap';
|
|
3
|
+
import { Form, Row, Container } from 'react-bootstrap';
|
|
4
4
|
import { UseFormStore } from '../stores/UseFormStore.js';
|
|
5
5
|
import { ElementFactory } from '../factories/ElementFactory.js';
|
|
6
6
|
import { orderBySort } from '../utils/orderBySort.js';
|
|
7
7
|
const elementFactory = new ElementFactory();
|
|
8
8
|
const FormComponent = memo(function FormComponent({ component }) {
|
|
9
9
|
const registerForm = UseFormStore((state) => state.registerForm);
|
|
10
|
+
const properties = component.properties;
|
|
10
11
|
useEffect(() => {
|
|
11
|
-
registerForm(component.id
|
|
12
|
-
|
|
12
|
+
registerForm(component.id, {
|
|
13
|
+
recipient: typeof properties.recipient === 'string' ? properties.recipient : undefined,
|
|
14
|
+
subject: typeof properties.subject === 'string' ? properties.subject : undefined
|
|
15
|
+
});
|
|
16
|
+
}, [registerForm, component.id, properties.recipient, properties.subject]);
|
|
13
17
|
const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
|
|
14
18
|
const handleSubmit = (event) => {
|
|
15
19
|
event.preventDefault();
|
|
16
20
|
};
|
|
17
|
-
return (_jsx(Form, { onSubmit: handleSubmit, children: _jsx(Row, { children: elements.map((element) => elementFactory.build(element, component.id)) }) }));
|
|
21
|
+
return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Form, { onSubmit: handleSubmit, children: _jsx(Row, { children: elements.map((element) => elementFactory.build(element, component.id)) }) }) }));
|
|
18
22
|
});
|
|
19
23
|
export { FormComponent };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ComponentType } from '../types/ComponentType.js';
|
|
2
|
-
|
|
2
|
+
declare const ImageComponent: import("react").NamedExoticComponent<{
|
|
3
3
|
readonly component: ComponentType;
|
|
4
|
-
}
|
|
4
|
+
}>;
|
|
5
|
+
export { ImageComponent };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { memo, useMemo } from 'react';
|
|
3
|
+
import { Row, Container } from 'react-bootstrap';
|
|
4
|
+
import { ElementFactory } from '../factories/ElementFactory.js';
|
|
5
|
+
import { orderBySort } from '../utils/orderBySort.js';
|
|
6
|
+
import { resolveImageElement } from '../utils/imageCustomization.js';
|
|
7
|
+
import { getBoolean } from '../utils/propertyUtils.js';
|
|
8
|
+
const elementFactory = new ElementFactory();
|
|
9
|
+
const ImageComponent = memo(function ImageComponent({ component }) {
|
|
10
|
+
const fullBleed = getBoolean(component.properties, 'fullBleed', false);
|
|
11
|
+
const elements = useMemo(() => orderBySort(component.elements).map((element) => resolveImageElement(component, element)), [component.elements, component.properties]);
|
|
12
|
+
if (fullBleed) {
|
|
13
|
+
return (_jsx("div", { "data-pb-component": component.id, style: Object.assign(Object.assign({}, component.styles), { width: 'calc(100% + var(--bs-gutter-x, 1.5rem))', marginLeft: 'calc(var(--bs-gutter-x, 1.5rem) * -0.5)', marginRight: 'calc(var(--bs-gutter-x, 1.5rem) * -0.5)' }), children: elements.map((element) => elementFactory.build(Object.assign(Object.assign({}, element), { fullBleed: true }))) }));
|
|
14
|
+
}
|
|
15
|
+
return (_jsx(Container, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { id: "element-row", children: elements.map((element) => elementFactory.build(element)) }) }));
|
|
16
|
+
});
|
|
17
|
+
export { ImageComponent };
|
|
@@ -7,6 +7,10 @@ import { orderBySort } from '../utils/orderBySort.js';
|
|
|
7
7
|
const elementFactory = new ElementFactory();
|
|
8
8
|
const ListComponent = memo(function ListComponent({ component }) {
|
|
9
9
|
const elements = useMemo(() => orderBySort(component.elements), [component.elements]);
|
|
10
|
+
const properties = component.properties || {};
|
|
11
|
+
const itemFontSize = String(properties.itemFontSize || '22px');
|
|
12
|
+
const itemGap = String(properties.itemGap || '8px');
|
|
13
|
+
const itemAlign = String(properties.itemAlign || 'center');
|
|
10
14
|
const items = useMemo(() => {
|
|
11
15
|
const result = [];
|
|
12
16
|
for (let i = 0; i < elements.length; i++) {
|
|
@@ -24,6 +28,6 @@ const ListComponent = memo(function ListComponent({ component }) {
|
|
|
24
28
|
}
|
|
25
29
|
return result;
|
|
26
30
|
}, [elements]);
|
|
27
|
-
return (_jsx(Col, { style: component.styles, children: _jsx("ul", { style: { listStyle: 'none' }, children: items.map(({ icon, text, id }) => (_jsxs("li", { style: { display: 'flex', alignItems: 'center', justifyContent:
|
|
31
|
+
return (_jsx(Col, { "data-pb-component": component.id, style: component.styles, children: _jsx("ul", { style: { listStyle: 'none' }, children: items.map(({ icon, text, id }) => (_jsxs("li", { style: { display: 'flex', alignItems: 'center', justifyContent: itemAlign, marginBottom: itemGap }, children: [_jsx("span", { children: elementFactory.build(icon) }), _jsx("span", { style: { fontSize: itemFontSize }, children: text ? elementFactory.build(text) : null })] }, id))) }) }));
|
|
28
32
|
});
|
|
29
33
|
export { ListComponent };
|
|
@@ -8,7 +8,7 @@ function isValidCoord(value) {
|
|
|
8
8
|
return COORDS_PATTERN.test(value.trim()) && Math.abs(Number(value)) <= 180;
|
|
9
9
|
}
|
|
10
10
|
export function MapComponent({ component }) {
|
|
11
|
-
const { lat, lng, zoom = 15, height = '400px' } = component.properties;
|
|
11
|
+
const { lat, lng, zoom = 15, height = '400px', placeholderBackgroundColor = '#e0e0e0', placeholderTextColor = '#666' } = component.properties;
|
|
12
12
|
const src = useMemo(() => {
|
|
13
13
|
if (!lat || !lng)
|
|
14
14
|
return null;
|
|
@@ -19,14 +19,14 @@ export function MapComponent({ component }) {
|
|
|
19
19
|
}
|
|
20
20
|
return `https://maps.google.com/maps?q=${encodeURIComponent(`${latStr},${lngStr}`)}&z=${zoom}&output=embed`;
|
|
21
21
|
}, [lat, lng, zoom]);
|
|
22
|
-
return (_jsx(Col, { style: component.styles, children: _jsx(Row, { children: _jsx(Col, { children: src ? (_jsx("iframe", { title: "Localiza\u00E7\u00E3o", src: src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade" })) : (_jsx("div", { style: {
|
|
22
|
+
return (_jsx(Col, { "data-pb-component": component.id, style: component.styles, children: _jsx(Row, { children: _jsx(Col, { children: src ? (_jsx("iframe", { title: "Localiza\u00E7\u00E3o", src: src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allowFullScreen: true, loading: "lazy", referrerPolicy: "no-referrer-when-downgrade" })) : (_jsx("div", { style: {
|
|
23
23
|
width: '100%',
|
|
24
24
|
height,
|
|
25
|
-
backgroundColor:
|
|
25
|
+
backgroundColor: placeholderBackgroundColor,
|
|
26
26
|
display: 'flex',
|
|
27
27
|
alignItems: 'center',
|
|
28
28
|
justifyContent: 'center',
|
|
29
29
|
borderRadius: '4px',
|
|
30
|
-
color:
|
|
30
|
+
color: placeholderTextColor
|
|
31
31
|
}, children: "Map not configured" })) }) }) }));
|
|
32
32
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ComponentType } from '../types/ComponentType.js';
|
|
2
|
-
|
|
3
|
-
export declare function SliderComponent({ component, editionMode }: {
|
|
2
|
+
export declare function SliderComponent({ component, editionMode, }: {
|
|
4
3
|
readonly component: ComponentType;
|
|
5
4
|
readonly editionMode?: boolean;
|
|
6
5
|
}): import("react").JSX.Element;
|
|
@@ -1,109 +1,191 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from 'react';
|
|
3
|
-
import { useKeenSlider } from 'keen-slider/react.js';
|
|
2
|
+
import { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
|
4
3
|
import { ElementFactory } from '../factories/ElementFactory.js';
|
|
5
4
|
import { orderBySort } from '../utils/orderBySort.js';
|
|
6
|
-
import '
|
|
5
|
+
import { resolveResponsiveProperties, breakpointFromWidth } from '../utils/responsiveProperties.js';
|
|
7
6
|
const elementFactory = new ElementFactory();
|
|
8
7
|
function cleanComponentStyles(styles) {
|
|
9
8
|
const exclude = new Set(['minHeight', 'display', 'alignItems', 'justifyContent', 'flexDirection']);
|
|
10
9
|
return Object.fromEntries(Object.entries(styles).filter(([key]) => !exclude.has(key)));
|
|
11
10
|
}
|
|
12
|
-
function
|
|
13
|
-
const
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
function buildSlide(element, fixedHeight, sharedImageStyles, useSharedImages) {
|
|
12
|
+
const isImage = element.elementType === 'image' || element.elementType === 'video';
|
|
13
|
+
if (isImage) {
|
|
14
|
+
const base = fixedHeight ? { width: '100%', height: '100%', objectFit: 'cover' } : { width: '100%' };
|
|
15
|
+
const override = useSharedImages ? sharedImageStyles || {} : element.styles;
|
|
16
|
+
return elementFactory.build(Object.assign(Object.assign({}, element), { styles: Object.assign(Object.assign({}, base), override) }));
|
|
17
|
+
}
|
|
18
|
+
return elementFactory.build(Object.assign(Object.assign({}, element), { styles: element.styles }));
|
|
17
19
|
}
|
|
18
|
-
function
|
|
20
|
+
function resolveChromeColors(properties) {
|
|
21
|
+
return {
|
|
22
|
+
arrowBackground: String(properties.arrowBackground || 'rgba(0,0,0,0.45)'),
|
|
23
|
+
arrowColor: String(properties.arrowColor || '#fff'),
|
|
24
|
+
arrowSize: Number(properties.arrowSize) || 40,
|
|
25
|
+
dotActiveBackground: String(properties.dotActiveBackground || '#333'),
|
|
26
|
+
dotBackground: String(properties.dotBackground || 'rgba(0,0,0,0.15)'),
|
|
27
|
+
dotActiveColor: String(properties.dotActiveColor || '#fff'),
|
|
28
|
+
dotColor: String(properties.dotColor || '#666'),
|
|
29
|
+
dotSize: Number(properties.dotSize) || 28,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const ARROW_BASE_STYLE = {
|
|
33
|
+
position: 'absolute',
|
|
34
|
+
top: '50%',
|
|
35
|
+
transform: 'translateY(-50%)',
|
|
36
|
+
zIndex: 10,
|
|
37
|
+
borderRadius: '50%',
|
|
38
|
+
border: 'none',
|
|
39
|
+
fontSize: 18,
|
|
40
|
+
fontWeight: 700,
|
|
41
|
+
lineHeight: 1,
|
|
42
|
+
cursor: 'pointer',
|
|
43
|
+
display: 'flex',
|
|
44
|
+
alignItems: 'center',
|
|
45
|
+
justifyContent: 'center',
|
|
46
|
+
transition: 'background 0.2s',
|
|
47
|
+
};
|
|
48
|
+
function ArrowButton({ side, size, background, color, onClick, }) {
|
|
49
|
+
return (_jsx("button", { type: "button", "aria-label": side === 'left' ? 'Slide anterior' : 'Próximo slide', onClick: onClick, style: Object.assign(Object.assign({}, ARROW_BASE_STYLE), { [side]: 8, width: size, height: size, background, color }), children: _jsx("svg", { width: "10", height: "16", viewBox: "0 0 10 16", fill: "none", children: _jsx("path", { d: side === 'left' ? 'M8.5 1L1.5 8L8.5 15' : 'M1.5 1L8.5 8L1.5 15', stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
50
|
+
}
|
|
51
|
+
function Dots({ count, current, size, activeBackground, background, activeColor, color, onGoTo, }) {
|
|
52
|
+
return (_jsx("div", { "aria-label": "Navega\u00E7\u00E3o do slider", style: { display: 'flex', justifyContent: 'center', gap: 6, marginTop: 12 }, children: Array.from({ length: count }).map((_, index) => (_jsx("button", { type: "button", "aria-label": `Ir para o slide ${index + 1}`, "aria-current": current === index ? 'true' : undefined, onClick: () => onGoTo(index), style: {
|
|
53
|
+
width: size,
|
|
54
|
+
height: size,
|
|
55
|
+
borderRadius: '50%',
|
|
56
|
+
border: 'none',
|
|
57
|
+
background: current === index ? activeBackground : background,
|
|
58
|
+
color: current === index ? activeColor : color,
|
|
59
|
+
fontSize: 12,
|
|
60
|
+
fontWeight: 600,
|
|
61
|
+
lineHeight: 1,
|
|
62
|
+
cursor: 'pointer',
|
|
63
|
+
display: 'flex',
|
|
64
|
+
alignItems: 'center',
|
|
65
|
+
justifyContent: 'center',
|
|
66
|
+
transition: 'all 0.2s',
|
|
67
|
+
}, children: index + 1 }, index))) }));
|
|
68
|
+
}
|
|
69
|
+
function useSliderWidth(ref) {
|
|
70
|
+
const [width, setWidth] = useState(0);
|
|
71
|
+
useLayoutEffect(() => {
|
|
72
|
+
const el = ref.current;
|
|
73
|
+
if (!el)
|
|
74
|
+
return;
|
|
75
|
+
const measure = () => setWidth(el.getBoundingClientRect().width);
|
|
76
|
+
measure();
|
|
77
|
+
const observer = new ResizeObserver(measure);
|
|
78
|
+
observer.observe(el);
|
|
79
|
+
return () => observer.disconnect();
|
|
80
|
+
}, [ref]);
|
|
81
|
+
return width;
|
|
82
|
+
}
|
|
83
|
+
export function SliderComponent({ component, editionMode = false, }) {
|
|
19
84
|
const properties = component.properties || {};
|
|
20
85
|
const slides = orderBySort(component.elements);
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
86
|
+
const n = slides.length;
|
|
87
|
+
const containerRef = useRef(null);
|
|
88
|
+
const width = useSliderWidth(containerRef);
|
|
89
|
+
const breakpoint = breakpointFromWidth(width);
|
|
90
|
+
const resolved = useMemo(() => resolveResponsiveProperties(properties, breakpoint), [properties, breakpoint]);
|
|
91
|
+
const perView = Math.max(1, Number(resolved.perView) || 1);
|
|
92
|
+
const spacing = Number(resolved.spacing) > 0 ? Number(resolved.spacing) : 10;
|
|
93
|
+
const fixedHeight = Number(resolved.height) > 0 ? Number(resolved.height) : 0;
|
|
94
|
+
const loop = resolved.loop === undefined ? n > 1 : Boolean(resolved.loop);
|
|
95
|
+
const slideWidth = width > 0 ? (width - spacing * (perView - 1)) / perView : 0;
|
|
96
|
+
const slideStep = slideWidth + spacing;
|
|
97
|
+
const maxIndex = Math.max(0, n - perView);
|
|
98
|
+
const [index, setIndex] = useState(loop ? n : 0);
|
|
99
|
+
const [animate, setAnimate] = useState(false);
|
|
100
|
+
const [dragging, setDragging] = useState(false);
|
|
101
|
+
const dragRef = useRef(null);
|
|
102
|
+
const currentIndex = loop
|
|
103
|
+
? ((Math.round(index) % n) + n) % n
|
|
104
|
+
: Math.min(Math.max(0, Math.round(index)), maxIndex);
|
|
34
105
|
useEffect(() => {
|
|
35
|
-
if (!
|
|
106
|
+
if (editionMode || !resolved.autoplay || n <= 1)
|
|
36
107
|
return;
|
|
37
|
-
const interval = Number(
|
|
38
|
-
const timer = window.setInterval(() => {
|
|
108
|
+
const interval = Number(resolved.interval) > 0 ? Number(resolved.interval) : 5000;
|
|
109
|
+
const timer = window.setInterval(() => {
|
|
110
|
+
setAnimate(true);
|
|
111
|
+
setIndex((prev) => prev + 1);
|
|
112
|
+
}, interval);
|
|
39
113
|
return () => window.clearInterval(timer);
|
|
40
|
-
}, [
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
114
|
+
}, [editionMode, resolved.autoplay, resolved.interval, n]);
|
|
115
|
+
const snapToRange = (value) => {
|
|
116
|
+
if (!loop)
|
|
117
|
+
return value;
|
|
118
|
+
if (value >= 2 * n)
|
|
119
|
+
return value - n;
|
|
120
|
+
if (value < n)
|
|
121
|
+
return value + n;
|
|
122
|
+
return value;
|
|
123
|
+
};
|
|
124
|
+
const handleTransitionEnd = () => {
|
|
125
|
+
if (!loop || dragging)
|
|
126
|
+
return;
|
|
127
|
+
const snapped = snapToRange(index);
|
|
128
|
+
if (snapped !== index) {
|
|
129
|
+
setAnimate(false);
|
|
130
|
+
setIndex(snapped);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const goTo = (i) => {
|
|
134
|
+
const target = loop ? i : Math.min(Math.max(0, i), maxIndex);
|
|
135
|
+
setAnimate(true);
|
|
136
|
+
setIndex(target);
|
|
137
|
+
};
|
|
138
|
+
const goToDot = (i) => {
|
|
139
|
+
const target = loop ? n + i : Math.min(Math.max(0, i), maxIndex);
|
|
140
|
+
let delta = target - index;
|
|
141
|
+
if (loop) {
|
|
142
|
+
if (delta > n / 2)
|
|
143
|
+
delta -= n;
|
|
144
|
+
else if (delta < -n / 2)
|
|
145
|
+
delta += n;
|
|
146
|
+
}
|
|
147
|
+
setAnimate(true);
|
|
148
|
+
setIndex(index + delta);
|
|
149
|
+
};
|
|
150
|
+
const onPointerDown = (e) => {
|
|
151
|
+
if (n <= 1)
|
|
152
|
+
return;
|
|
153
|
+
dragRef.current = { startX: e.clientX, startIndex: index };
|
|
154
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
155
|
+
setDragging(true);
|
|
156
|
+
setAnimate(false);
|
|
157
|
+
};
|
|
158
|
+
const onPointerMove = (e) => {
|
|
159
|
+
const drag = dragRef.current;
|
|
160
|
+
if (!drag || slideStep <= 0)
|
|
161
|
+
return;
|
|
162
|
+
setIndex(drag.startIndex - (e.clientX - drag.startX) / slideStep);
|
|
163
|
+
};
|
|
164
|
+
const endDrag = () => {
|
|
165
|
+
if (!dragRef.current)
|
|
166
|
+
return;
|
|
167
|
+
dragRef.current = null;
|
|
168
|
+
setDragging(false);
|
|
169
|
+
setIndex((prev) => {
|
|
170
|
+
const rounded = Math.round(prev);
|
|
171
|
+
return loop ? snapToRange(rounded) : Math.min(Math.max(0, rounded), maxIndex);
|
|
172
|
+
});
|
|
173
|
+
setAnimate(true);
|
|
174
|
+
};
|
|
175
|
+
const translateX = -(index * slideStep);
|
|
176
|
+
const trackSlides = loop ? [...slides, ...slides, ...slides] : slides;
|
|
177
|
+
const showArrows = Boolean(resolved.showArrows) && n > perView;
|
|
178
|
+
const showDots = Boolean(resolved.showDots) && n > 1;
|
|
179
|
+
const chrome = resolveChromeColors(resolved);
|
|
180
|
+
const useSharedImages = resolved.imageCustomization !== 'separate';
|
|
181
|
+
const sharedImageStyles = resolved.imageStyles || {};
|
|
182
|
+
return (_jsxs("div", { ref: containerRef, "data-pb-component": component.id, style: Object.assign({ position: 'relative' }, cleanComponentStyles(component.styles)), children: [_jsx("div", { style: Object.assign({ overflow: 'hidden' }, (fixedHeight ? { height: fixedHeight } : {})), children: _jsx("div", { style: {
|
|
99
183
|
display: 'flex',
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
transition: '
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return _jsx(StaticSliderComponent, { component: component });
|
|
108
|
-
return _jsx(InteractiveSliderComponent, { component: component });
|
|
184
|
+
columnGap: spacing,
|
|
185
|
+
transform: `translateX(${translateX}px)`,
|
|
186
|
+
transition: animate && !dragging ? 'transform 0.3s ease' : 'none',
|
|
187
|
+
cursor: dragging ? 'grabbing' : n > 1 ? 'grab' : 'default',
|
|
188
|
+
touchAction: 'pan-y',
|
|
189
|
+
userSelect: 'none',
|
|
190
|
+
}, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: endDrag, onPointerCancel: endDrag, onTransitionEnd: handleTransitionEnd, children: trackSlides.map((element, i) => (_jsx("div", { style: { width: slideWidth, flexShrink: 0, overflow: 'hidden' }, children: buildSlide(element, fixedHeight, sharedImageStyles, useSharedImages) }, `${element.id}-${i}`))) }) }), showArrows && (_jsxs(_Fragment, { children: [_jsx(ArrowButton, { side: "left", size: chrome.arrowSize, background: chrome.arrowBackground, color: chrome.arrowColor, onClick: () => goTo(index - 1) }), _jsx(ArrowButton, { side: "right", size: chrome.arrowSize, background: chrome.arrowBackground, color: chrome.arrowColor, onClick: () => goTo(index + 1) })] })), showDots && (_jsx(Dots, { count: n, current: currentIndex, size: chrome.dotSize, activeBackground: chrome.dotActiveBackground, background: chrome.dotBackground, activeColor: chrome.dotActiveColor, color: chrome.dotColor, onGoTo: goToDot }))] }));
|
|
109
191
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SocialPropertiesType } from '../types/SocialPropertiesType.js';
|
|
2
|
-
export declare function SocialIconsComponent({ social }: {
|
|
3
|
-
readonly social
|
|
2
|
+
export declare function SocialIconsComponent({ social, color }: {
|
|
3
|
+
readonly social?: SocialPropertiesType;
|
|
4
|
+
readonly color?: string;
|
|
4
5
|
}): import("react").JSX.Element;
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Row, Col } from 'react-bootstrap';
|
|
3
|
-
import { FaFacebookF, FaInstagram, FaLink } from 'react-icons/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
import { FaFacebookF, FaInstagram, FaTiktok, FaWhatsapp, FaYoutube, FaXTwitter, FaLinkedin, FaThreads, FaLink, } from 'react-icons/fa6';
|
|
4
|
+
const SOCIAL_ICONS = {
|
|
5
|
+
facebook: FaFacebookF,
|
|
6
|
+
instagram: FaInstagram,
|
|
7
|
+
tiktok: FaTiktok,
|
|
8
|
+
whatsapp: FaWhatsapp,
|
|
9
|
+
youtube: FaYoutube,
|
|
10
|
+
x: FaXTwitter,
|
|
11
|
+
twitter: FaXTwitter,
|
|
12
|
+
linkedin: FaLinkedin,
|
|
13
|
+
threads: FaThreads,
|
|
14
|
+
linktree: FaLink,
|
|
15
|
+
kwai: FaLink,
|
|
16
|
+
};
|
|
17
|
+
export function SocialIconsComponent({ social, color }) {
|
|
18
|
+
const entries = Object.entries(social || {})
|
|
19
|
+
.filter(([, value]) => Boolean(value === null || value === void 0 ? void 0 : value.path))
|
|
20
|
+
.map(([id, value]) => ({ id, url: (value === null || value === void 0 ? void 0 : value.path) || '', Icon: SOCIAL_ICONS[id] || FaLink }));
|
|
21
|
+
if (entries.length === 0)
|
|
17
22
|
return null;
|
|
18
|
-
return (_jsx(Row, { children:
|
|
23
|
+
return (_jsx(Row, { children: entries.map(({ id, url, Icon }) => (_jsx(Col, { className: "text-center social-icons", style: { color }, children: _jsx("a", { href: url, target: "_blank", rel: "noopener noreferrer", "aria-label": id, children: _jsx(Icon, {}) }) }, id))) }));
|
|
19
24
|
}
|