lib-pixelbuild 0.2.3 → 0.3.1

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.
@@ -5,8 +5,8 @@ import { BlockRenderer } from '../renderers/BlockRenderer.js';
5
5
  import { buildResponsiveCssForStyles } from '../utils/responsiveStyles.js';
6
6
  import { buildFontFamily } from '../utils/fonts.js';
7
7
  function mergeStyles(websiteStyles, pageStyles) {
8
- const merged = Object.assign({}, websiteStyles);
9
- for (const key of Object.keys(pageStyles)) {
8
+ const merged = Object.assign({}, (websiteStyles || {}));
9
+ for (const key of Object.keys(pageStyles || {})) {
10
10
  const val = pageStyles[key];
11
11
  if (val !== '' && val !== null && val !== undefined) {
12
12
  ;
@@ -21,7 +21,7 @@ function toCssValue(val) {
21
21
  return undefined;
22
22
  }
23
23
  const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
24
- var _a, _b, _c, _d;
24
+ var _a, _b, _c, _d, _e;
25
25
  const mergedStyles = useMemo(() => mergeStyles(website.styles, page.styles), [website.styles, page.styles]);
26
26
  const designSystem = website.designSystem;
27
27
  const pageStyle = useMemo(() => {
@@ -60,6 +60,6 @@ const PageBuilder = memo(function PageBuilder({ website, page, editionMode }) {
60
60
  (_d = designSystem === null || designSystem === void 0 ? void 0 : designSystem.typography) === null || _d === void 0 ? void 0 : _d.fontSizeBase,
61
61
  mergedStyles
62
62
  ]);
63
- 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(BlockRenderer, { blocks: page.blocks, editionMode: editionMode, componentDefaults: website.componentDefaults }), page.blocks.length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "Nenhum conte\u00FAdo adicionado." }))] })] }));
63
+ return (_jsxs(Suspense, { fallback: _jsx("div", { children: ((_e = website.properties) === null || _e === void 0 ? void 0 : _e.loadingMessage) || 'Carregando...' }), 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(BlockRenderer, { blocks: page.blocks, editionMode: editionMode, componentDefaults: website.componentDefaults }), (page.blocks || []).length === 0 && editionMode && (_jsx("div", { style: { padding: '40px', textAlign: 'center', color: '#94a3b8' }, children: "Nenhum conte\u00FAdo adicionado." }))] })] }));
64
64
  });
65
65
  export { PageBuilder };
@@ -0,0 +1,4 @@
1
+ import type { ComponentType } from '../types/ComponentType.js';
2
+ export declare function VideoComponent({ component }: {
3
+ readonly component: ComponentType;
4
+ }): import("react").JSX.Element;
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useMemo } from 'react';
3
+ import { getBoolean } from '../utils/propertyUtils.js';
4
+ function toEmbed(src) {
5
+ const value = src.trim();
6
+ if (!value)
7
+ return null;
8
+ const youtube = value.match(/(?:youtube\.com\/(?:watch\?v=|embed\/|shorts\/)|youtu\.be\/)([A-Za-z0-9_-]{6,})/);
9
+ if (youtube)
10
+ return { kind: 'iframe', src: `https://www.youtube.com/embed/${youtube[1]}` };
11
+ const vimeo = value.match(/vimeo\.com\/(?:video\/)?(\d+)/);
12
+ if (vimeo)
13
+ return { kind: 'iframe', src: `https://player.vimeo.com/video/${vimeo[1]}` };
14
+ return { kind: 'native', src: value };
15
+ }
16
+ export function VideoComponent({ component }) {
17
+ const { src = '', height = '400px', placeholderBackgroundColor = '#e0e0e0', placeholderTextColor = '#666' } = component.properties;
18
+ const fullBleed = getBoolean(component.properties, 'fullBleed', false);
19
+ const video = useMemo(() => toEmbed(src), [src]);
20
+ const content = (video === null || video === void 0 ? void 0 : video.kind) === 'iframe' ? (_jsx("iframe", { title: "V\u00EDdeo", src: video.src, width: "100%", height: height, style: { border: 0, borderRadius: '4px' }, allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, loading: "lazy" })) : (video === null || video === void 0 ? void 0 : video.kind) === 'native' ? (_jsx("video", { controls: true, src: video.src, style: { width: '100%', height, borderRadius: '4px', display: 'block' } })) : (_jsx("div", { style: {
21
+ width: '100%',
22
+ height,
23
+ backgroundColor: placeholderBackgroundColor,
24
+ display: 'flex',
25
+ alignItems: 'center',
26
+ justifyContent: 'center',
27
+ borderRadius: '4px',
28
+ color: placeholderTextColor
29
+ }, children: "V\u00EDdeo n\u00E3o configurado" }));
30
+ if (fullBleed) {
31
+ return (_jsx("div", { "data-pb-component": component.id, style: Object.assign(Object.assign({}, component.styles), { width: 'calc(100% + var(--pb-gutter, 1.5rem))', marginLeft: 'calc(var(--pb-gutter, 1.5rem) * -0.5)', marginRight: 'calc(var(--pb-gutter, 1.5rem) * -0.5)' }), children: content }));
32
+ }
33
+ return (_jsx("div", { "data-pb-component": component.id, style: component.styles, children: content }));
34
+ }
@@ -9,6 +9,7 @@ import { CardComponent } from '../components/CardComponent.js';
9
9
  import { MapComponent } from '../components/MapComponent.js';
10
10
  import { ButtonsComponent } from '../components/ButtonsComponent.js';
11
11
  import { IconComponent } from '../components/IconComponent.js';
12
+ import { VideoComponent } from '../components/VideoComponent.js';
12
13
  /**
13
14
  * Aplica os estilos padrão do design system (`componentDefaults`) antes dos
14
15
  * estilos da instância — o override da instância prevalece.
@@ -46,6 +47,8 @@ export class ComponentFactory {
46
47
  return _jsx(ButtonsComponent, { component: resolved }, resolved.id);
47
48
  case ComponentTypeEnum.Icon:
48
49
  return _jsx(IconComponent, { component: resolved }, resolved.id);
50
+ case ComponentTypeEnum.Video:
51
+ return _jsx(VideoComponent, { component: resolved }, resolved.id);
49
52
  default:
50
53
  throw new Error('Invalid component type: ' + resolved.componentType);
51
54
  }
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export { SiteLayout, type EmailApiConfig } from './layouts/SiteLayout.js';
13
13
  export { PageBuilder } from './builders/PageBuilder.js';
14
14
  export { BlockRenderer } from './renderers/BlockRenderer.js';
15
15
  export { IconComponent } from './components/IconComponent.js';
16
+ export { VideoComponent } from './components/VideoComponent.js';
16
17
  export { LoadingComponent } from './components/LoadingComponent.js';
17
18
  export { ComponentFactory } from './factories/ComponentFactory.js';
18
19
  export { ElementFactory } from './factories/ElementFactory.js';
package/dist/index.js CHANGED
@@ -4,6 +4,7 @@ export { SiteLayout } from './layouts/SiteLayout.js';
4
4
  export { PageBuilder } from './builders/PageBuilder.js';
5
5
  export { BlockRenderer } from './renderers/BlockRenderer.js';
6
6
  export { IconComponent } from './components/IconComponent.js';
7
+ export { VideoComponent } from './components/VideoComponent.js';
7
8
  export { LoadingComponent } from './components/LoadingComponent.js';
8
9
  export { ComponentFactory } from './factories/ComponentFactory.js';
9
10
  export { ElementFactory } from './factories/ElementFactory.js';
@@ -5,10 +5,10 @@ import { PbRow } from '../ui/PbRow.js';
5
5
  import { PbCol } from '../ui/PbCol.js';
6
6
  import { SocialIconsComponent } from '../components/SocialIconsComponent.js';
7
7
  export function Footer({ website }) {
8
- var _a;
8
+ var _a, _b, _c, _d, _e, _f;
9
9
  const social = (_a = website.properties) === null || _a === void 0 ? void 0 : _a.social;
10
- const footer = website.footer.properties;
11
- const styles = website.footer.styles;
10
+ const footerProps = ((_b = website.footer) === null || _b === void 0 ? void 0 : _b.properties) || {};
11
+ const styles = ((_c = website.footer) === null || _c === void 0 ? void 0 : _c.styles) || {};
12
12
  const fluid = styles.fluid || undefined;
13
13
  const baseStyle = Object.assign({}, styles);
14
14
  delete baseStyle.fluid;
@@ -18,5 +18,5 @@ export function Footer({ website }) {
18
18
  flexDirection: 'column',
19
19
  alignItems: 'center'
20
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] })] })] }) }) }));
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((_d = footerProps.text1) !== null && _d !== void 0 ? _d : '') } }) }), _jsx(PbCol, { width: { xs: 12 }, style: textStyle, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize((_e = footerProps.text2) !== null && _e !== void 0 ? _e : '') } }) }), _jsx(PbCol, { width: { xs: 12 }, style: { display: 'flex', justifyContent: 'center' }, children: _jsx("div", { dangerouslySetInnerHTML: { __html: DOMPurify.sanitize((_f = footerProps.text3) !== null && _f !== void 0 ? _f : '') } }) }), _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] })] })] }) }) }));
22
22
  }
@@ -3,8 +3,9 @@ import { useMemo, useCallback, useState } from 'react';
3
3
  import { useLocation } from 'react-router-dom';
4
4
  import { PbContainer } from '../ui/PbContainer.js';
5
5
  export function Header({ website, imageBaseUrl }) {
6
- const headerProperties = website.header.properties;
7
- const headerStyles = website.header.styles;
6
+ var _a, _b;
7
+ const headerProperties = ((_a = website.header) === null || _a === void 0 ? void 0 : _a.properties) || {};
8
+ const headerStyles = ((_b = website.header) === null || _b === void 0 ? void 0 : _b.styles) || {};
8
9
  const location = useLocation();
9
10
  const [menuOpen, setMenuOpen] = useState(false);
10
11
  const menuPages = useMemo(() => (website.pages || []).filter((p) => p.menu === true).sort((a, b) => (a.menuOrder || 0) - (b.menuOrder || 0)), [website.pages]);
@@ -8,7 +8,7 @@ import { ThemeStyle } from '../designSystem/theme.js';
8
8
  import { buildFontFamily, buildGoogleFontsHref } from '../utils/fonts.js';
9
9
  import { buttonActionFactory } from '../factories/ButtonActionFactory.js';
10
10
  export function SiteLayout({ website, imageBaseUrl, emailApi }) {
11
- var _a, _b, _c, _d, _e, _f, _g, _h;
11
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
12
12
  const fontFamily = buildFontFamily((_a = website.styles) === null || _a === void 0 ? void 0 : _a.fontFamily);
13
13
  const fontHref = buildGoogleFontsHref((_b = website.styles) === null || _b === void 0 ? void 0 : _b.fontFamily);
14
14
  useEffect(() => {
@@ -36,5 +36,5 @@ export function SiteLayout({ website, imageBaseUrl, emailApi }) {
36
36
  (_f = (_e = website.properties) === null || _e === void 0 ? void 0 : _e.email) === null || _f === void 0 ? void 0 : _f.recipientName,
37
37
  (_h = (_g = website.properties) === null || _g === void 0 ? void 0 : _g.email) === null || _h === void 0 ? void 0 : _h.subject
38
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 })] })] }));
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: (_j = website.styles) === null || _j === void 0 ? void 0 : _j.backgroundColor, color: (_k = website.styles) === null || _k === void 0 ? void 0 : _k.color, fontFamily }, children: [_jsx(Header, { website: website, imageBaseUrl: imageBaseUrl }), _jsx(Outlet, {}), _jsx(Footer, { website: website })] })] }));
40
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lib-pixelbuild",
3
- "version": "0.2.3",
3
+ "version": "0.3.1",
4
4
  "engines": {
5
5
  "node": "^24.0.0",
6
6
  "npm": ">=10"