lib-pixelbuild 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/builders/PageBuilder.js +42 -26
  2. package/dist/components/ButtonsComponent.d.ts +5 -0
  3. package/dist/components/ButtonsComponent.js +45 -0
  4. package/dist/components/CardComponent.js +31 -6
  5. package/dist/components/FormComponent.js +9 -4
  6. package/dist/components/{CarouselComponent.d.ts → IconComponent.d.ts} +3 -2
  7. package/dist/components/IconComponent.js +12 -0
  8. package/dist/components/ImageComponent.d.ts +5 -0
  9. package/dist/components/ImageComponent.js +18 -0
  10. package/dist/components/ListComponent.js +5 -2
  11. package/dist/components/LoadingComponent.js +2 -2
  12. package/dist/components/MapComponent.js +11 -12
  13. package/dist/components/SliderComponent.d.ts +0 -1
  14. package/dist/components/SliderComponent.js +173 -93
  15. package/dist/components/SocialIconsComponent.d.ts +3 -2
  16. package/dist/components/SocialIconsComponent.js +20 -16
  17. package/dist/components/TextComponent.js +5 -3
  18. package/dist/constants/ComponentEnum.d.ts +2 -0
  19. package/dist/constants/ComponentEnum.js +2 -0
  20. package/dist/designSystem/baseCss.d.ts +8 -0
  21. package/dist/designSystem/baseCss.js +406 -0
  22. package/dist/designSystem/buildSiteCss.d.ts +8 -0
  23. package/dist/designSystem/buildSiteCss.js +11 -0
  24. package/dist/designSystem/index.d.ts +6 -0
  25. package/dist/designSystem/index.js +5 -0
  26. package/dist/designSystem/theme.d.ts +9 -0
  27. package/dist/designSystem/theme.js +11 -0
  28. package/dist/designSystem/themeVars.d.ts +8 -0
  29. package/dist/designSystem/themeVars.js +9 -0
  30. package/dist/designSystem/tokens.d.ts +82 -0
  31. package/dist/designSystem/tokens.js +144 -0
  32. package/dist/elements/AlertElement.js +4 -4
  33. package/dist/elements/ButtonElement.js +21 -7
  34. package/dist/elements/ElementColWrapper.js +11 -2
  35. package/dist/elements/IconElement.js +5 -5
  36. package/dist/elements/IconMap.js +101 -28
  37. package/dist/elements/InputElement.js +10 -9
  38. package/dist/elements/TextElement.js +5 -1
  39. package/dist/factories/ButtonActionFactory.d.ts +3 -4
  40. package/dist/factories/ButtonActionFactory.js +2 -2
  41. package/dist/factories/ComponentFactory.d.ts +2 -1
  42. package/dist/factories/ComponentFactory.js +29 -12
  43. package/dist/index.d.ts +20 -5
  44. package/dist/index.js +15 -1
  45. package/dist/layouts/Footer.js +13 -2
  46. package/dist/layouts/Header.js +43 -16
  47. package/dist/layouts/SiteLayout.d.ts +8 -1
  48. package/dist/layouts/SiteLayout.js +36 -3
  49. package/dist/renderers/BlockRenderer.d.ts +8 -0
  50. package/dist/renderers/BlockRenderer.js +68 -0
  51. package/dist/services/EmailService.d.ts +14 -5
  52. package/dist/services/EmailService.js +21 -24
  53. package/dist/stores/UseFormStore.d.ts +7 -2
  54. package/dist/stores/UseFormStore.js +8 -3
  55. package/dist/types/{SectionColumnType.d.ts → BlockType.d.ts} +2 -6
  56. package/dist/types/ComponentType.d.ts +3 -0
  57. package/dist/types/ElementType.d.ts +1 -0
  58. package/dist/types/EmailSettingsType.d.ts +5 -0
  59. package/dist/types/HeaderPropertiesType.d.ts +1 -0
  60. package/dist/types/MailBodyType.d.ts +2 -0
  61. package/dist/types/PageType.d.ts +2 -2
  62. package/dist/types/SocialPropertiesType.d.ts +3 -11
  63. package/dist/types/StylesType.d.ts +12 -0
  64. package/dist/types/WebsitePropertiesType.d.ts +2 -0
  65. package/dist/types/WebsiteType.d.ts +6 -0
  66. package/dist/ui/PbAlert.d.ts +10 -0
  67. package/dist/ui/PbAlert.js +8 -0
  68. package/dist/ui/PbButton.d.ts +20 -0
  69. package/dist/ui/PbButton.js +20 -0
  70. package/dist/ui/PbCol.d.ts +14 -0
  71. package/dist/ui/PbCol.js +43 -0
  72. package/dist/ui/PbContainer.d.ts +7 -0
  73. package/dist/ui/PbContainer.js +17 -0
  74. package/dist/ui/PbRow.d.ts +7 -0
  75. package/dist/ui/PbRow.js +17 -0
  76. package/dist/ui/PbSpinner.d.ts +3 -0
  77. package/dist/ui/PbSpinner.js +5 -0
  78. package/dist/ui/index.d.ts +6 -0
  79. package/dist/ui/index.js +6 -0
  80. package/dist/utils/emailTemplate.d.ts +7 -0
  81. package/dist/utils/emailTemplate.js +66 -0
  82. package/dist/utils/fonts.d.ts +2 -0
  83. package/dist/utils/fonts.js +10 -0
  84. package/dist/utils/imageCustomization.d.ts +3 -0
  85. package/dist/utils/imageCustomization.js +9 -0
  86. package/dist/utils/responsiveProperties.d.ts +2 -0
  87. package/dist/utils/responsiveProperties.js +28 -0
  88. package/dist/utils/responsiveStyles.d.ts +6 -0
  89. package/dist/utils/responsiveStyles.js +73 -0
  90. package/package.json +1 -8
  91. package/dist/components/CarouselComponent.js +0 -6
  92. package/dist/layouts/Menu.d.ts +0 -5
  93. package/dist/layouts/Menu.js +0 -34
  94. package/dist/renderers/SectionRenderer.d.ts +0 -6
  95. package/dist/renderers/SectionRenderer.js +0 -73
  96. package/dist/types/SectionType.d.ts +0 -10
  97. /package/dist/types/{SectionColumnType.js → BlockType.js} +0 -0
  98. /package/dist/types/{SectionType.js → EmailSettingsType.js} +0 -0
package/dist/index.js CHANGED
@@ -2,11 +2,25 @@ export { Header } from './layouts/Header.js';
2
2
  export { Footer } from './layouts/Footer.js';
3
3
  export { SiteLayout } from './layouts/SiteLayout.js';
4
4
  export { PageBuilder } from './builders/PageBuilder.js';
5
- export { SectionRenderer } from './renderers/SectionRenderer.js';
5
+ export { BlockRenderer } from './renderers/BlockRenderer.js';
6
+ export { IconComponent } from './components/IconComponent.js';
6
7
  export { LoadingComponent } from './components/LoadingComponent.js';
7
8
  export { ComponentFactory } from './factories/ComponentFactory.js';
8
9
  export { ElementFactory } from './factories/ElementFactory.js';
10
+ export { iconMap } from './elements/IconMap.js';
9
11
  export { ComponentTypeEnum } from './constants/ComponentEnum.js';
10
12
  export { ElementTypeEnum } from './constants/ElementEnum.js';
13
+ export { ButtonActionEnum } from './constants/ButtonActionEnum.js';
11
14
  export { analyticsService } from './services/AnalyticsService.js';
12
15
  export { buttonActionFactory } from './factories/ButtonActionFactory.js';
16
+ export { defaultTokens, mergeTokens, tokenToCssVars, buildTokenCss, buildThemeVars } from './designSystem/tokens.js';
17
+ export { baseCss } from './designSystem/baseCss.js';
18
+ export { buildSiteCss } from './designSystem/buildSiteCss.js';
19
+ export { themeVarsStyle } from './designSystem/themeVars.js';
20
+ export { ThemeStyle } from './designSystem/theme.js';
21
+ export { PbContainer } from './ui/PbContainer.js';
22
+ export { PbRow } from './ui/PbRow.js';
23
+ export { PbCol } from './ui/PbCol.js';
24
+ export { PbButton } from './ui/PbButton.js';
25
+ export { PbSpinner } from './ui/PbSpinner.js';
26
+ export { PbAlert } from './ui/PbAlert.js';
@@ -1,11 +1,22 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import DOMPurify from 'dompurify';
3
- import { Container, Row, Col } from 'react-bootstrap';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { PbRow } from '../ui/PbRow.js';
5
+ import { PbCol } from '../ui/PbCol.js';
4
6
  import { SocialIconsComponent } from '../components/SocialIconsComponent.js';
5
7
  export function Footer({ website }) {
6
8
  var _a;
7
9
  const social = (_a = website.properties) === null || _a === void 0 ? void 0 : _a.social;
8
10
  const footer = website.footer.properties;
9
11
  const styles = website.footer.styles;
10
- return (_jsx(Container, { fluid: styles.fluid || undefined, style: { backgroundColor: styles.backgroundColor }, children: _jsxs(Row, { id: 'footer', style: styles, children: [_jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex justify-content-center", style: { marginBottom: '30px' }, children: social && (_jsx(SocialIconsComponent, { social: social })) }), _jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex flex-column align-items-center", dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text1) } }), _jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex flex-column align-items-center", dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text2) } }), _jsx(Col, { xs: 12, sm: 12, md: 12, lg: 12, className: "d-flex justify-content-center", dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text3) } }), _jsxs(Col, { xs: 12, sm: 12, md: 12, lg: 12, children: [_jsx("hr", { className: "footer-divider" }), _jsxs("p", { className: "text-center mb-0", children: ["\u00A9 ", new Date().getFullYear(), " ", website.name] })] })] }) }));
12
+ const fluid = styles.fluid || undefined;
13
+ const baseStyle = Object.assign({}, styles);
14
+ delete baseStyle.fluid;
15
+ delete baseStyle.responsive;
16
+ const textStyle = {
17
+ display: 'flex',
18
+ flexDirection: 'column',
19
+ alignItems: 'center'
20
+ };
21
+ return (_jsx(PbContainer, { fluid: fluid || undefined, children: _jsx("footer", { id: "footer", className: "pb-footer", style: { backgroundColor: styles.backgroundColor }, children: _jsxs(PbRow, { children: [_jsx(PbCol, { width: { xs: 12 }, style: { marginBottom: '30px' }, children: social && _jsx(SocialIconsComponent, { social: social, color: styles.socialIconColor || styles.color }) }), _jsx(PbCol, { width: { xs: 12 }, style: textStyle, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text1) } }) }), _jsx(PbCol, { width: { xs: 12 }, style: textStyle, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text2) } }) }), _jsx(PbCol, { width: { xs: 12 }, style: { display: 'flex', justifyContent: 'center' }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize(footer.text3) } }) }), _jsxs(PbCol, { width: { xs: 12 }, children: [_jsx("hr", { className: "pb-footer-divider" }), _jsxs("p", { className: "pb-text-center pb-mb-0", style: baseStyle, children: ["\u00A9 ", new Date().getFullYear(), " ", website.name] })] })] }) }) }));
11
22
  }
@@ -1,12 +1,12 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useCallback } from 'react';
2
+ import { useMemo, useCallback, useState } from 'react';
3
3
  import { useLocation } from 'react-router-dom';
4
- import { Container, Navbar, Nav } from 'react-bootstrap';
4
+ import { PbContainer } from '../ui/PbContainer.js';
5
5
  export function Header({ website, imageBaseUrl }) {
6
6
  const headerProperties = website.header.properties;
7
7
  const headerStyles = website.header.styles;
8
- const domain = (website.domain || '').replaceAll('.', '');
9
8
  const location = useLocation();
9
+ const [menuOpen, setMenuOpen] = useState(false);
10
10
  const menuPages = useMemo(() => (website.pages || []).filter((p) => p.menu === true).sort((a, b) => (a.menuOrder || 0) - (b.menuOrder || 0)), [website.pages]);
11
11
  const isActive = useCallback((path) => {
12
12
  const currentPath = location.pathname;
@@ -15,20 +15,47 @@ export function Header({ website, imageBaseUrl }) {
15
15
  return currentPath === path || currentPath.startsWith(path + '/');
16
16
  }, [location.pathname]);
17
17
  const showMenu = headerProperties.showMenu !== false && menuPages.length > 0;
18
- const logoUrl = useMemo(() => imageBaseUrl
19
- ? `${imageBaseUrl.replace(/\/+$/, '')}/${domain}/${website.logo}`
20
- : `https://noisdev-website-images.s3.sa-east-1.amazonaws.com/${domain}/${website.logo}`, [imageBaseUrl, domain, website.logo]);
21
- return (_jsx(Navbar, { expand: "lg", collapseOnSelect: true, className: "py-3", style: { backgroundColor: headerStyles.backgroundColor || undefined, width: '100%' }, children: _jsxs(Container, { fluid: headerStyles.fluid || undefined, children: [headerProperties.showLogo && (_jsx(Navbar.Brand, { style: { marginRight: showMenu ? 'auto' : 0, padding: 0 }, children: _jsx("img", { src: logoUrl, width: "200", className: "d-inline-block align-top", alt: "Logo" }) })), showMenu && (_jsxs(_Fragment, { children: [_jsx(Navbar.Toggle, { "aria-controls": "header-navbar-nav" }), _jsx(Navbar.Collapse, { id: "header-navbar-nav", children: _jsx(Nav, { className: `mx-auto ${headerProperties.showLogo ? '' : 'w-100 justify-content-center'}`, children: menuPages.map((p) => {
18
+ const logoUrl = useMemo(() => (imageBaseUrl && website.logo ? `${imageBaseUrl.replace(/\/+$/, '')}/${website.logo}` : undefined), [imageBaseUrl, website.logo]);
19
+ const logoAlign = headerProperties.logoAlign || 'center';
20
+ const menuLinkColor = headerStyles.menuLinkColor || headerStyles.color || undefined;
21
+ const menuActiveLinkColor = headerStyles.menuActiveLinkColor || headerStyles.menuLinkColor || headerStyles.color || undefined;
22
+ const textAlign = headerStyles.textAlign || 'left';
23
+ const brandStyle = { padding: 0 };
24
+ if (showMenu) {
25
+ if (logoAlign === 'right')
26
+ brandStyle.marginLeft = 'auto';
27
+ else if (logoAlign === 'center') {
28
+ brandStyle.marginRight = 'auto';
29
+ brandStyle.marginLeft = 'auto';
30
+ }
31
+ else {
32
+ brandStyle.marginRight = 'auto';
33
+ }
34
+ }
35
+ else if (logoAlign === 'center') {
36
+ brandStyle.margin = '0 auto';
37
+ }
38
+ else if (logoAlign === 'right') {
39
+ brandStyle.marginLeft = 'auto';
40
+ }
41
+ const innerStyle = { textAlign };
42
+ if (textAlign === 'center')
43
+ innerStyle.justifyContent = 'center';
44
+ else if (textAlign === 'right')
45
+ innerStyle.justifyContent = 'flex-end';
46
+ const closeMenu = useCallback(() => setMenuOpen(false), []);
47
+ return (_jsx("header", { className: "pb-header", style: {
48
+ backgroundColor: headerStyles.backgroundColor || undefined,
49
+ color: headerStyles.color || undefined
50
+ }, children: _jsx(PbContainer, { fluid: headerStyles.fluid || undefined, children: _jsxs("div", { className: "pb-header-inner", style: innerStyle, children: [headerProperties.showLogo && logoUrl && (_jsx("a", { className: "pb-brand", href: "/", style: brandStyle, "aria-label": "P\u00E1gina inicial", children: _jsx("img", { src: logoUrl, width: Number(headerProperties.logoWidth) || 200, alt: "Logo" }) })), showMenu && (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "pb-nav-toggle", "aria-label": menuOpen ? 'Fechar menu' : 'Abrir menu', "aria-expanded": menuOpen, onClick: () => setMenuOpen((open) => !open), children: "\u2630" }), _jsx("nav", { className: `pb-nav${menuOpen ? ' pb-nav-open' : ''}`, "aria-label": "Menu principal", children: menuPages.map((p) => {
22
51
  const active = isActive(p.path);
23
- return (_jsx(Nav.Link, { href: p.path, style: {
24
- color: active ? '#c0ad5b' : '#a4a4a4',
25
- fontSize: '0.9rem',
26
- letterSpacing: '0.05em',
27
- textTransform: 'uppercase',
52
+ return (_jsx("a", { href: p.path, onClick: closeMenu, className: `pb-nav-link${active ? ' pb-nav-link-active' : ''}`, style: {
53
+ color: active ? menuActiveLinkColor : menuLinkColor,
54
+ fontSize: headerStyles.menuFontSize || undefined,
55
+ letterSpacing: headerStyles.menuLetterSpacing || undefined,
56
+ textTransform: headerStyles.menuTextTransform || undefined,
28
57
  margin: '0 12px',
29
- paddingBottom: '4px',
30
- borderBottom: active ? '2px solid #c0ad5b' : '2px solid transparent',
31
- transition: 'color 0.3s, border-color 0.3s'
58
+ paddingBottom: '4px'
32
59
  }, children: p.title }, p.id));
33
- }) }) })] }))] }) }));
60
+ }) })] }))] }) }) }));
34
61
  }
@@ -1,5 +1,12 @@
1
1
  import type { WebsiteType } from '../types/WebsiteType.js';
2
- export declare function SiteLayout({ website, imageBaseUrl }: {
2
+ export interface EmailApiConfig {
3
+ apiUrl?: string;
4
+ authToken?: string;
5
+ sender?: string;
6
+ senderName?: string;
7
+ }
8
+ export declare function SiteLayout({ website, imageBaseUrl, emailApi }: {
3
9
  readonly website: WebsiteType;
4
10
  readonly imageBaseUrl?: string;
11
+ readonly emailApi?: EmailApiConfig;
5
12
  }): import("react").JSX.Element;
@@ -1,7 +1,40 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect } from 'react';
2
3
  import { Outlet } from 'react-router-dom';
4
+ import { Helmet } from 'react-helmet-async';
3
5
  import { Header } from './Header.js';
4
6
  import { Footer } from './Footer.js';
5
- export function SiteLayout({ website, imageBaseUrl }) {
6
- return (_jsxs("div", { id: "site-layout", style: { backgroundColor: website.styles.backgroundColor, color: website.styles.color }, children: [_jsx(Header, { website: website, imageBaseUrl: imageBaseUrl }), _jsx(Outlet, {}), _jsx(Footer, { website: website })] }));
7
+ import { ThemeStyle } from '../designSystem/theme.js';
8
+ import { buildFontFamily, buildGoogleFontsHref } from '../utils/fonts.js';
9
+ import { buttonActionFactory } from '../factories/ButtonActionFactory.js';
10
+ export function SiteLayout({ website, imageBaseUrl, emailApi }) {
11
+ var _a, _b, _c, _d, _e, _f, _g, _h;
12
+ const fontFamily = buildFontFamily((_a = website.styles) === null || _a === void 0 ? void 0 : _a.fontFamily);
13
+ const fontHref = buildGoogleFontsHref((_b = website.styles) === null || _b === void 0 ? void 0 : _b.fontFamily);
14
+ useEffect(() => {
15
+ var _a, _b, _c, _d, _e, _f;
16
+ if (!(emailApi === null || emailApi === void 0 ? void 0 : emailApi.apiUrl) || !emailApi.authToken)
17
+ return;
18
+ buttonActionFactory.configureEmail({
19
+ apiUrl: emailApi.apiUrl,
20
+ authToken: emailApi.authToken,
21
+ websiteId: website.id,
22
+ sender: emailApi.sender || 'contato@pixelbuild.com.br',
23
+ senderName: emailApi.senderName || website.name,
24
+ defaultRecipient: (_b = (_a = website.properties) === null || _a === void 0 ? void 0 : _a.email) === null || _b === void 0 ? void 0 : _b.recipient,
25
+ defaultRecipientName: (_d = (_c = website.properties) === null || _c === void 0 ? void 0 : _c.email) === null || _d === void 0 ? void 0 : _d.recipientName,
26
+ defaultSubject: (_f = (_e = website.properties) === null || _e === void 0 ? void 0 : _e.email) === null || _f === void 0 ? void 0 : _f.subject
27
+ });
28
+ }, [
29
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.apiUrl,
30
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.authToken,
31
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.sender,
32
+ emailApi === null || emailApi === void 0 ? void 0 : emailApi.senderName,
33
+ website.id,
34
+ website.name,
35
+ (_d = (_c = website.properties) === null || _c === void 0 ? void 0 : _c.email) === null || _d === void 0 ? void 0 : _d.recipient,
36
+ (_f = (_e = website.properties) === null || _e === void 0 ? void 0 : _e.email) === null || _f === void 0 ? void 0 : _f.recipientName,
37
+ (_h = (_g = website.properties) === null || _g === void 0 ? void 0 : _g.email) === null || _h === void 0 ? void 0 : _h.subject
38
+ ]);
39
+ return (_jsxs(_Fragment, { children: [_jsx(ThemeStyle, { designSystem: website.designSystem }), fontHref && (_jsxs(Helmet, { children: [_jsx("link", { rel: "preconnect", href: "https://fonts.googleapis.com" }), _jsx("link", { rel: "preconnect", href: "https://fonts.gstatic.com", crossOrigin: "" }), _jsx("link", { href: fontHref, rel: "stylesheet" })] })), _jsxs("div", { id: "site-layout", className: "pb-root", style: { backgroundColor: website.styles.backgroundColor, color: website.styles.color, fontFamily }, children: [_jsx(Header, { website: website, imageBaseUrl: imageBaseUrl }), _jsx(Outlet, {}), _jsx(Footer, { website: website })] })] }));
7
40
  }
@@ -0,0 +1,8 @@
1
+ import type { BlockType } from '../types/BlockType.js';
2
+ import type { ComponentDefaults } from '../types/WebsiteType.js';
3
+ declare const BlockRenderer: import("react").NamedExoticComponent<{
4
+ readonly blocks: BlockType[];
5
+ readonly editionMode?: boolean;
6
+ readonly componentDefaults?: ComponentDefaults;
7
+ }>;
8
+ export { BlockRenderer };
@@ -0,0 +1,68 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { memo, useMemo } from 'react';
3
+ import { PbContainer } from '../ui/PbContainer.js';
4
+ import { ComponentFactory } from '../factories/ComponentFactory.js';
5
+ import { orderBySort } from '../utils/orderBySort.js';
6
+ import { buildResponsiveCss } from '../utils/responsiveStyles.js';
7
+ const componentFactory = new ComponentFactory();
8
+ function gridClass(id) {
9
+ return `pixelbuild-grid-${String(id).replace(/[^a-zA-Z0-9_-]/g, '_')}`;
10
+ }
11
+ const BlockGrid = memo(function BlockGrid({ block, editionMode, componentDefaults }) {
12
+ const grid = gridClass(block.id);
13
+ const components = orderBySort(block.components);
14
+ const css = useMemo(() => {
15
+ const rules = components
16
+ .map((component) => {
17
+ var _a, _b, _c;
18
+ const properties = component.properties || {};
19
+ const row = Math.max(0, Number(properties.row) || 0);
20
+ const rowSpan = Math.max(1, Number(properties.rowSpan) || 1);
21
+ const xs = ((_a = component.width) === null || _a === void 0 ? void 0 : _a.xs) || 12;
22
+ const sm = ((_b = component.width) === null || _b === void 0 ? void 0 : _b.sm) || xs;
23
+ const md = ((_c = component.width) === null || _c === void 0 ? void 0 : _c.md) || sm;
24
+ const cls = gridClass(component.id);
25
+ return [
26
+ `.${grid} .${cls}{grid-column:span ${xs};grid-row:auto;min-width:0}`,
27
+ `@media (min-width:576px){.${grid} .${cls}{grid-column:span ${sm}}}`,
28
+ `@media (min-width:768px){.${grid} .${cls}{grid-column:span ${md};grid-row:${row + 1}/span ${rowSpan}}}`
29
+ ].join('');
30
+ })
31
+ .join('');
32
+ return `.${grid}{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--pb-gutter,1rem)}${rules}`;
33
+ }, [grid, components]);
34
+ if (editionMode && components.length === 0) {
35
+ return (_jsxs("div", { "data-pixelbuild-empty-block": block.id, style: {
36
+ minHeight: 80,
37
+ display: 'flex',
38
+ alignItems: 'center',
39
+ justifyContent: 'center',
40
+ gap: 6,
41
+ border: '1.5px dashed #c4d0dc',
42
+ color: '#94a3b8',
43
+ fontSize: 13,
44
+ cursor: 'pointer',
45
+ textAlign: 'center',
46
+ borderRadius: 8
47
+ }, children: [_jsx("span", { style: { fontSize: 18, lineHeight: 1 }, children: "+" }), "Adicionar componente"] }));
48
+ }
49
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: css }), _jsx("div", { className: grid, children: components.map((component) => (_jsx("div", { className: gridClass(component.id), children: componentFactory.build(component, editionMode, componentDefaults) }, component.id))) })] }));
50
+ });
51
+ const BlockContent = memo(function BlockContent({ block, editionMode, componentDefaults }) {
52
+ const content = useMemo(() => _jsx(BlockGrid, { block: block, editionMode: editionMode, componentDefaults: componentDefaults }), [block, editionMode, componentDefaults]);
53
+ if (block.sectionType === 'container-fluid') {
54
+ return (_jsx(PbContainer, { fluid: true, "data-pb-block": block.id, style: block.styles, children: content }));
55
+ }
56
+ if (block.sectionType === 'container') {
57
+ return (_jsx(PbContainer, { "data-pb-block": block.id, style: block.styles, children: content }));
58
+ }
59
+ return _jsx(PbContainer, { fluid: true, children: content });
60
+ });
61
+ const BlockRenderer = memo(function BlockRenderer({ blocks, editionMode = false, componentDefaults }) {
62
+ const sorted = useMemo(() => orderBySort(blocks || []), [blocks]);
63
+ if (sorted.length === 0) {
64
+ return null;
65
+ }
66
+ return (_jsxs(_Fragment, { children: [_jsx("style", { children: buildResponsiveCss(sorted) }), sorted.map((block) => (_jsx(BlockContent, { block: block, editionMode: editionMode, componentDefaults: componentDefaults }, block.id)))] }));
67
+ });
68
+ export { BlockRenderer };
@@ -3,15 +3,24 @@ import type { MailBodyType } from '../types/MailBodyType.js';
3
3
  export interface EmailServiceConfig {
4
4
  apiUrl: string;
5
5
  authToken: string;
6
- senderName: string;
6
+ websiteId: number | string;
7
7
  sender: string;
8
- recipientName: string;
9
- recipient: string;
8
+ senderName?: string;
9
+ defaultRecipient?: string;
10
+ defaultRecipientName?: string;
11
+ defaultSubject?: string;
12
+ }
13
+ export interface EmailSendOptions {
14
+ recipient?: string;
15
+ recipientName?: string;
16
+ subject?: string;
17
+ formId?: number | string;
18
+ websiteName?: string;
10
19
  }
11
20
  declare class EmailService {
12
21
  private readonly config;
13
22
  constructor(config: EmailServiceConfig);
14
- sendMail(params: FormFieldsType[]): Promise<boolean>;
15
- createBody(params: FormFieldsType[]): MailBodyType;
23
+ sendMail(params: FormFieldsType[], options?: EmailSendOptions): Promise<boolean>;
24
+ createBody(params: FormFieldsType[], options?: EmailSendOptions): MailBodyType;
16
25
  }
17
26
  export { EmailService };
@@ -1,14 +1,18 @@
1
+ import { buildFormEmailHtml } from '../utils/emailTemplate.js';
2
+ const DEFAULT_SUBJECT = 'Mensagem enviada pelo formulário do site';
3
+ const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
1
4
  class EmailService {
2
5
  constructor(config) {
3
6
  this.config = config;
4
7
  }
5
- async sendMail(params) {
6
- const body = this.createBody(params);
8
+ async sendMail(params, options = {}) {
9
+ const body = this.createBody(params, options);
7
10
  const response = await fetch(`${this.config.apiUrl}/send-mail`, {
8
11
  method: 'POST',
9
12
  headers: {
10
13
  'Content-Type': 'application/json',
11
- Authorization: `Bearer ${this.config.authToken}`
14
+ Authorization: `Bearer ${this.config.authToken}`,
15
+ 'X-Website-Id': String(this.config.websiteId)
12
16
  },
13
17
  body: JSON.stringify(body)
14
18
  });
@@ -17,29 +21,22 @@ class EmailService {
17
21
  }
18
22
  return true;
19
23
  }
20
- createBody(params) {
21
- var _a, _b, _c, _d, _e, _f;
22
- const firstName = params.find((e) => e.name === 'firstNameInput');
23
- const lastName = params.find((e) => e.name === 'lastNameInput');
24
- const birthDate = params.find((e) => e.name === 'birthDateField');
25
- const document = params.find((e) => e.name === 'documentField');
26
- const email = params.find((e) => e.name === 'emailField');
27
- const phone = params.find((e) => e.name === 'phoneField');
24
+ createBody(params, options = {}) {
25
+ var _a;
26
+ const rows = params
27
+ .filter((field) => { var _a; return field.name && String((_a = field.value) !== null && _a !== void 0 ? _a : '').trim() !== ''; })
28
+ .map((field) => { var _a; return ({ label: field.name, value: String((_a = field.value) !== null && _a !== void 0 ? _a : '') }); });
29
+ const emailField = params.find((field) => { var _a; return /email/i.test(field.name) || EMAIL_REGEX.test(String((_a = field.value) !== null && _a !== void 0 ? _a : '')); });
30
+ const subject = options.subject || this.config.defaultSubject || DEFAULT_SUBJECT;
28
31
  return {
29
- senderName: this.config.senderName,
32
+ senderName: this.config.senderName || options.websiteName || 'PixelBuild',
30
33
  sender: this.config.sender,
31
- recipientName: this.config.recipientName,
32
- recipient: this.config.recipient,
33
- title: 'Mensagem enviada pelo formulário do site',
34
- message: [
35
- `Nome: ${(_a = firstName === null || firstName === void 0 ? void 0 : firstName.value) !== null && _a !== void 0 ? _a : ''} ${(_b = lastName === null || lastName === void 0 ? void 0 : lastName.value) !== null && _b !== void 0 ? _b : ''}`,
36
- `Data de Nascimento: ${(_c = birthDate === null || birthDate === void 0 ? void 0 : birthDate.value) !== null && _c !== void 0 ? _c : ''}`,
37
- `CPF: ${(_d = document === null || document === void 0 ? void 0 : document.value) !== null && _d !== void 0 ? _d : ''}`,
38
- `E-mail: ${(_e = email === null || email === void 0 ? void 0 : email.value) !== null && _e !== void 0 ? _e : ''}`,
39
- `Celular: ${(_f = phone === null || phone === void 0 ? void 0 : phone.value) !== null && _f !== void 0 ? _f : ''}`
40
- ]
41
- .filter(Boolean)
42
- .join('\n')
34
+ recipientName: options.recipientName || this.config.defaultRecipientName || 'Site',
35
+ recipient: options.recipient || this.config.defaultRecipient || '',
36
+ title: subject,
37
+ message: buildFormEmailHtml(subject, rows),
38
+ isHtml: true,
39
+ lead: Object.assign(Object.assign({ formId: (_a = options.formId) !== null && _a !== void 0 ? _a : null }, Object.fromEntries(rows.map((row) => [row.label, row.value]))), (emailField ? { email: emailField.value } : {}))
43
40
  };
44
41
  }
45
42
  }
@@ -11,14 +11,19 @@ export interface FormElement {
11
11
  inputValidateId: number | null;
12
12
  [key: string]: string | number | boolean | null;
13
13
  }
14
+ export interface FormEmailConfig {
15
+ recipient?: string;
16
+ subject?: string;
17
+ }
14
18
  export interface FormEntry {
15
19
  elements: string[];
16
- [key: string]: string[] | null;
20
+ email?: FormEmailConfig;
21
+ [key: string]: string[] | FormEmailConfig | null | undefined;
17
22
  }
18
23
  export interface FormStoreState {
19
24
  forms: Record<string, FormEntry>;
20
25
  elements: Record<string, FormElement>;
21
- registerForm: (formId: number) => void;
26
+ registerForm: (formId: number, emailConfig?: FormEmailConfig) => void;
22
27
  registerElement: (elementId: number, formId?: number | null, initialState?: Partial<FormElement>) => void;
23
28
  unregisterElement: (elementId: number) => void;
24
29
  validateFormData: (inputValidateId: number, elementId: number, value: string) => void;
@@ -3,9 +3,14 @@ import { InputValidateFactory } from '../factories/InputValidateFactory.js';
3
3
  const UseFormStore = create((set, get) => ({
4
4
  forms: {},
5
5
  elements: {},
6
- registerForm: (formId) => set((state) => ({
7
- forms: Object.assign(Object.assign({}, state.forms), { [formId]: state.forms[formId] || { elements: [] } })
8
- })),
6
+ registerForm: (formId, emailConfig) => set((state) => {
7
+ const existing = state.forms[formId];
8
+ const nextForm = existing
9
+ ? Object.assign(Object.assign({}, existing), (emailConfig ? { email: emailConfig } : {})) : Object.assign({ elements: [] }, (emailConfig ? { email: emailConfig } : {}));
10
+ return {
11
+ forms: Object.assign(Object.assign({}, state.forms), { [formId]: nextForm })
12
+ };
13
+ }),
9
14
  registerElement: (elementId, formId = null, initialState = {}) => set((state) => {
10
15
  var _a, _b;
11
16
  const existingElement = state.elements[elementId];
@@ -1,14 +1,10 @@
1
1
  import type { StylesType } from './StylesType.js';
2
- import type { ColumnWidthType } from './ColumnWidthType.js';
3
2
  import type { ComponentType } from './ComponentType.js';
4
- import type { SectionType } from './SectionType.js';
5
- export interface SectionColumnType {
3
+ export interface BlockType {
6
4
  id: number;
7
- width: ColumnWidthType;
8
- offset: ColumnWidthType;
5
+ sectionType: 'container' | 'container-fluid';
9
6
  sort: number;
10
7
  properties: Record<string, unknown>;
11
8
  styles: StylesType;
12
9
  components: ComponentType[];
13
- childSections: SectionType[];
14
10
  }
@@ -1,5 +1,6 @@
1
1
  import type { StylesType } from './StylesType.js';
2
2
  import type { ElementType } from './ElementType.js';
3
+ import type { ColumnWidthType } from './ColumnWidthType.js';
3
4
  export interface ComponentType {
4
5
  id: number;
5
6
  componentType: string;
@@ -7,5 +8,7 @@ export interface ComponentType {
7
8
  enabled: boolean;
8
9
  properties: Record<string, unknown>;
9
10
  styles: StylesType;
11
+ width: ColumnWidthType;
12
+ offset: ColumnWidthType;
10
13
  elements: ElementType[];
11
14
  }
@@ -8,4 +8,5 @@ export interface ElementType {
8
8
  styles: StylesType;
9
9
  width: ColumnWidthType;
10
10
  offset: ColumnWidthType;
11
+ fullBleed?: boolean;
11
12
  }
@@ -0,0 +1,5 @@
1
+ export interface EmailSettingsType {
2
+ recipient?: string;
3
+ recipientName?: string;
4
+ subject?: string;
5
+ }
@@ -1,5 +1,6 @@
1
1
  export interface HeaderPropertiesType {
2
2
  logoAlign: 'left' | 'right' | 'center';
3
+ logoWidth?: string | number;
3
4
  showLogo: boolean;
4
5
  showMenu: boolean;
5
6
  }
@@ -5,4 +5,6 @@ export interface MailBodyType {
5
5
  recipient: string;
6
6
  title: string;
7
7
  message: string;
8
+ isHtml?: boolean;
9
+ lead?: Record<string, unknown>;
8
10
  }
@@ -1,5 +1,5 @@
1
1
  import type { StylesType } from './StylesType.js';
2
- import type { SectionType } from './SectionType.js';
2
+ import type { BlockType } from './BlockType.js';
3
3
  export interface PageType {
4
4
  id: number;
5
5
  websiteId: number;
@@ -13,5 +13,5 @@ export interface PageType {
13
13
  menuType: 'link' | 'dropdown';
14
14
  properties: Record<string, unknown>;
15
15
  styles: StylesType;
16
- sections: SectionType[];
16
+ blocks: BlockType[];
17
17
  }
@@ -1,11 +1,3 @@
1
- export interface SocialPropertiesType {
2
- instagram: {
3
- path: string;
4
- };
5
- facebook: {
6
- path: string;
7
- };
8
- linktree: {
9
- path: string;
10
- };
11
- }
1
+ export type SocialPropertiesType = Record<string, {
2
+ path?: string;
3
+ } | undefined>;
@@ -2,7 +2,12 @@ export type Float = 'left' | 'right' | 'none' | 'inline-start' | 'inline-end';
2
2
  export type TextAlign = 'left' | 'right' | 'center' | 'justify' | 'start' | 'end';
3
3
  export type ObjectFit = 'cover' | 'contain' | 'fill' | 'none' | 'scale-down';
4
4
  export type FontWeight = 'normal' | 'bold' | 'bolder' | 'lighter' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900';
5
+ export type BreakpointKey = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+ export type ResponsiveStylesType = {
7
+ [key in BreakpointKey]?: Partial<Omit<StylesType, 'responsive'>>;
8
+ };
5
9
  export interface StylesType {
10
+ responsive?: ResponsiveStylesType;
6
11
  alignItems?: string;
7
12
  backgroundColor?: string;
8
13
  backgroundGradientColorStart?: string;
@@ -18,6 +23,7 @@ export interface StylesType {
18
23
  display?: string;
19
24
  float?: Float;
20
25
  fluid?: boolean;
26
+ fontFamily?: string;
21
27
  fontSize?: string;
22
28
  fontWeight?: FontWeight;
23
29
  height?: string;
@@ -25,6 +31,12 @@ export interface StylesType {
25
31
  marginLeft?: string;
26
32
  marginRight?: string;
27
33
  marginBottom?: string;
34
+ menuLinkColor?: string;
35
+ menuActiveLinkColor?: string;
36
+ menuFontSize?: string;
37
+ menuLetterSpacing?: string;
38
+ menuTextTransform?: string;
39
+ socialIconColor?: string;
28
40
  objectFit?: ObjectFit;
29
41
  paddingTop?: string;
30
42
  paddingLeft?: string;
@@ -1,5 +1,7 @@
1
1
  import type { SocialPropertiesType } from './SocialPropertiesType.js';
2
+ import type { EmailSettingsType } from './EmailSettingsType.js';
2
3
  export interface WebsitePropertiesType {
3
4
  loadingMessage: string;
4
5
  social: SocialPropertiesType;
6
+ email?: EmailSettingsType;
5
7
  }
@@ -3,6 +3,9 @@ import type { StylesType } from './StylesType.js';
3
3
  import type { HeaderType } from './HeaderType.js';
4
4
  import type { FooterType } from './FooterType.js';
5
5
  import type { WebsitePropertiesType } from './WebsitePropertiesType.js';
6
+ import type { PartialDesignTokens } from '../designSystem/tokens.js';
7
+ /** Estilos padrão por tipo de componente (ex.: todos os botões, títulos...). */
8
+ export type ComponentDefaults = Record<string, Partial<StylesType>>;
6
9
  export interface WebsiteType {
7
10
  id: number;
8
11
  name: string;
@@ -13,7 +16,10 @@ export interface WebsiteType {
13
16
  footer: FooterType;
14
17
  properties: WebsitePropertiesType;
15
18
  styles: StylesType;
19
+ designSystem?: PartialDesignTokens;
20
+ componentDefaults?: ComponentDefaults;
16
21
  enabled: boolean;
22
+ maintenance?: boolean;
17
23
  publishedAt: string | null;
18
24
  createdAt: string;
19
25
  updatedAt: string;
@@ -0,0 +1,10 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ /**
3
+ * Alerta próprio do design system. Substitui o `Alert` do react-bootstrap.
4
+ */
5
+ export declare function PbAlert({ variant, title, style, children }: {
6
+ readonly variant?: string;
7
+ readonly title?: ReactNode;
8
+ readonly style?: CSSProperties;
9
+ readonly children?: ReactNode;
10
+ }): import("react").JSX.Element;
@@ -0,0 +1,8 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Alerta próprio do design system. Substitui o `Alert` do react-bootstrap.
4
+ */
5
+ export function PbAlert({ variant = 'info', title, style, children }) {
6
+ const classes = ['pb-alert', variant ? `pb-alert-${variant}` : 'pb-alert-info'].filter(Boolean).join(' ');
7
+ return (_jsxs("div", { className: classes, role: "alert", style: style, children: [title && _jsx("div", { className: "pb-alert-title", children: title }), children] }));
8
+ }
@@ -0,0 +1,20 @@
1
+ import { CSSProperties, ReactNode } from 'react';
2
+ export type PbButtonVariant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark' | 'outline-primary' | 'outline-secondary' | 'link';
3
+ /**
4
+ * Botão próprio do design system. Substitui o `Button` do react-bootstrap,
5
+ * mantendo o comportamento de link (`href`) e botão de formulário.
6
+ */
7
+ export declare function PbButton({ as, href, target, rel, type, variant, size, disabled, onClick, className, style, children }: {
8
+ readonly as?: string;
9
+ readonly href?: string;
10
+ readonly target?: string;
11
+ readonly rel?: string;
12
+ readonly type?: 'button' | 'submit' | 'reset';
13
+ readonly variant?: string;
14
+ readonly size?: 'sm' | 'lg';
15
+ readonly disabled?: boolean;
16
+ readonly onClick?: (event: React.MouseEvent<HTMLElement>) => void;
17
+ readonly className?: string;
18
+ readonly style?: CSSProperties;
19
+ readonly children?: ReactNode;
20
+ }): import("react").JSX.Element;