@cntrl-site/sdk-nextjs 1.6.11 → 1.6.13
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/.idea/codeStyles/codeStyleConfig.xml +5 -0
- package/Icon/r +0 -0
- package/lib/components/Section/Section.js +67 -4
- package/lib/components/items/CodeEmbedItem/CodeEmbedItem.js +18 -7
- package/lib/provider/CntrlSdkContext.js +8 -0
- package/package.json +2 -2
- package/src/components/Section/Section.tsx +95 -8
- package/src/components/items/CodeEmbedItem/CodeEmbedItem.tsx +20 -8
- package/src/provider/CntrlSdkContext.ts +11 -1
- package/src/utils/ArticleRectManager/ArticleRectObserver.ts +1 -1
- package/src/utils/getCompoundBondaryStyles.ts +0 -1
- package/cntrl-site-sdk-nextjs-1.6.11-alpha.0.tgz +0 -0
package/Icon/r
ADDED
|
File without changes
|
|
@@ -11,13 +11,22 @@ const sdk_1 = require("@cntrl-site/sdk");
|
|
|
11
11
|
const useCntrlContext_1 = require("../../provider/useCntrlContext");
|
|
12
12
|
const useSectionRegistry_1 = require("../../utils/ArticleRectManager/useSectionRegistry");
|
|
13
13
|
const color_1 = require("@cntrl-site/color");
|
|
14
|
+
const useLayoutContext_1 = require("../useLayoutContext");
|
|
14
15
|
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
|
|
16
|
+
function isVideoUrl(url) {
|
|
17
|
+
const videoExtensions = ['.mp4', '.webm', '.ogg'];
|
|
18
|
+
return videoExtensions.some(ext => url.toLowerCase().endsWith(ext));
|
|
19
|
+
}
|
|
15
20
|
const Section = ({ section, data, children }) => {
|
|
21
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
16
22
|
const id = (0, react_1.useId)();
|
|
17
23
|
const sectionRef = (0, react_1.useRef)(null);
|
|
18
24
|
const { layouts, customSections } = (0, useCntrlContext_1.useCntrlContext)();
|
|
19
|
-
const
|
|
25
|
+
const layout = (0, useLayoutContext_1.useLayoutContext)();
|
|
26
|
+
const layoutValues = [section.height, section.color, (_a = section.media) !== null && _a !== void 0 ? _a : {}];
|
|
20
27
|
const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
|
|
28
|
+
const isVideo = layout && ((_c = (_b = section.media) === null || _b === void 0 ? void 0 : _b[layout]) === null || _c === void 0 ? void 0 : _c.url) ? isVideoUrl(String((_e = (_d = section.media) === null || _d === void 0 ? void 0 : _d[layout]) === null || _e === void 0 ? void 0 : _e.url)) : false;
|
|
29
|
+
const videoRef = (0, react_1.useRef)(null);
|
|
21
30
|
(0, useSectionRegistry_1.useSectionRegistry)(section.id, sectionRef.current);
|
|
22
31
|
const getSectionVisibilityStyles = () => {
|
|
23
32
|
return layouts
|
|
@@ -33,15 +42,69 @@ const Section = ({ section, data, children }) => {
|
|
|
33
42
|
}`;
|
|
34
43
|
}, '');
|
|
35
44
|
};
|
|
45
|
+
(0, react_1.useEffect)(() => {
|
|
46
|
+
if (!isVideo || !sectionRef.current || !videoRef.current)
|
|
47
|
+
return;
|
|
48
|
+
const video = videoRef.current;
|
|
49
|
+
const section = sectionRef.current;
|
|
50
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
51
|
+
if (entry.isIntersecting) {
|
|
52
|
+
video.style.display = 'block';
|
|
53
|
+
video.play().catch(() => { });
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
video.style.display = 'none';
|
|
57
|
+
video.pause();
|
|
58
|
+
}
|
|
59
|
+
}, {
|
|
60
|
+
root: null,
|
|
61
|
+
rootMargin: '50px',
|
|
62
|
+
threshold: 0
|
|
63
|
+
});
|
|
64
|
+
observer.observe(section);
|
|
65
|
+
return () => observer.disconnect();
|
|
66
|
+
}, [isVideo]);
|
|
36
67
|
if (SectionComponent)
|
|
37
68
|
return (0, jsx_runtime_1.jsx)("div", { ref: sectionRef, children: (0, jsx_runtime_1.jsx)(SectionComponent, { data: data, children: children }) });
|
|
38
|
-
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.
|
|
39
|
-
${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([height, color]) =>
|
|
69
|
+
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)("div", { className: `section-${section.id}`, id: section.name, ref: sectionRef, children: [layout && ((_g = (_f = section.media) === null || _f === void 0 ? void 0 : _f[layout]) === null || _g === void 0 ? void 0 : _g.url) && ((_j = (_h = section.media) === null || _h === void 0 ? void 0 : _h[layout]) === null || _j === void 0 ? void 0 : _j.size) !== 'none' && sectionRef.current && ((0, jsx_runtime_1.jsx)("div", { className: `section-background-overlay-${section.id}`, children: (0, jsx_runtime_1.jsx)("div", { className: `section-background-wrapper-${section.id}`, children: isVideo ? ((0, jsx_runtime_1.jsx)("video", { ref: videoRef, autoPlay: true, loop: true, muted: true, playsInline: true, preload: "auto", className: `video-background-${section.id}`, children: (0, jsx_runtime_1.jsx)("source", { src: (_m = (_l = (_k = section.media) === null || _k === void 0 ? void 0 : _k[layout]) === null || _l === void 0 ? void 0 : _l.url) !== null && _m !== void 0 ? _m : '' }) })) : ((0, jsx_runtime_1.jsx)("img", { src: (_q = (_p = (_o = section.media) === null || _o === void 0 ? void 0 : _o[layout]) === null || _p === void 0 ? void 0 : _p.url) !== null && _q !== void 0 ? _q : '', className: `image-background-${section.id}` })) }, `section-background-wrapper-${section.id}`) })), children] }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
|
|
70
|
+
${(0, sdk_1.getLayoutStyles)(layouts, layoutValues, ([height, color, media]) => {
|
|
71
|
+
var _a;
|
|
72
|
+
return (`
|
|
40
73
|
.section-${section.id} {
|
|
41
74
|
height: ${getSectionHeight(height)};
|
|
42
75
|
position: relative;
|
|
43
76
|
background-color: ${color_1.CntrlColor.parse(color !== null && color !== void 0 ? color : DEFAULT_COLOR).fmt('rgba')};
|
|
44
|
-
}
|
|
77
|
+
}
|
|
78
|
+
.section-background-overlay-${section.id} {
|
|
79
|
+
height: ${getSectionHeight(height)};
|
|
80
|
+
width: 100%;
|
|
81
|
+
position: relative;
|
|
82
|
+
overflow: clip;
|
|
83
|
+
}
|
|
84
|
+
.section-background-wrapper-${section.id} {
|
|
85
|
+
transform: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? 'translateY(-100vh)' : 'unset'};
|
|
86
|
+
left: 0;
|
|
87
|
+
position: relative;
|
|
88
|
+
height: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? `calc(${getSectionHeight(height)} + 200vh)` : getSectionHeight(height)}};
|
|
89
|
+
width: 100%;
|
|
90
|
+
}
|
|
91
|
+
.video-background-${section.id} {
|
|
92
|
+
object-fit: ${(_a = media === null || media === void 0 ? void 0 : media.size) !== null && _a !== void 0 ? _a : 'cover'};
|
|
93
|
+
width: 100%;
|
|
94
|
+
height: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? '100vh' : '100%'};
|
|
95
|
+
position: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? 'sticky' : 'relative'};
|
|
96
|
+
top: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? '100vh' : 'unset'};
|
|
97
|
+
left: 0;
|
|
98
|
+
}
|
|
99
|
+
.image-background-${section.id} {
|
|
100
|
+
object-fit: ${media === null || media === void 0 ? void 0 : media.size};
|
|
101
|
+
width: 100%;
|
|
102
|
+
height: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? '100vh' : '100%'};
|
|
103
|
+
position: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? 'sticky' : 'relative'};
|
|
104
|
+
top: ${(media === null || media === void 0 ? void 0 : media.position) === 'fixed' ? '100vh' : 'unset'};
|
|
105
|
+
}
|
|
106
|
+
`);
|
|
107
|
+
})}
|
|
45
108
|
${getSectionVisibilityStyles()}
|
|
46
109
|
` })] }));
|
|
47
110
|
};
|
|
@@ -25,9 +25,12 @@ const stylesMap = {
|
|
|
25
25
|
[sdk_1.AreaAnchor.BottomRight]: { justifyContent: 'flex-end', alignItems: 'flex-end' }
|
|
26
26
|
};
|
|
27
27
|
const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
28
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
28
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
29
29
|
const id = (0, react_1.useId)();
|
|
30
|
-
const { layouts } = (0, useCntrlContext_1.useCntrlContext)();
|
|
30
|
+
const { layouts, fonts } = (0, useCntrlContext_1.useCntrlContext)();
|
|
31
|
+
const fontGoogleTags = fonts === null || fonts === void 0 ? void 0 : fonts.google;
|
|
32
|
+
const fontAdobeTags = fonts === null || fonts === void 0 ? void 0 : fonts.adobe;
|
|
33
|
+
const fontCustomTags = new sdk_1.FontFaceGenerator((_a = fonts === null || fonts === void 0 ? void 0 : fonts.custom) !== null && _a !== void 0 ? _a : []).generate();
|
|
31
34
|
const { anchor, blur: itemBlur, opacity: itemOpacity } = (0, useCodeEmbedItem_1.useCodeEmbedItem)(item, sectionId);
|
|
32
35
|
const itemAngle = (0, useItemAngle_1.useItemAngle)(item, sectionId);
|
|
33
36
|
const { html } = item.commonParams;
|
|
@@ -36,9 +39,9 @@ const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilit
|
|
|
36
39
|
const pos = stylesMap[anchor];
|
|
37
40
|
const layoutValues = [item.area, item.layoutParams];
|
|
38
41
|
const stateParams = interactionCtrl === null || interactionCtrl === void 0 ? void 0 : interactionCtrl.getState(['angle', 'blur', 'opacity']);
|
|
39
|
-
const blur = ((
|
|
40
|
-
const opacity = (
|
|
41
|
-
const angle = (
|
|
42
|
+
const blur = ((_c = (_b = stateParams === null || stateParams === void 0 ? void 0 : stateParams.styles) === null || _b === void 0 ? void 0 : _b.blur) !== null && _c !== void 0 ? _c : itemBlur);
|
|
43
|
+
const opacity = (_e = (_d = stateParams === null || stateParams === void 0 ? void 0 : stateParams.styles) === null || _d === void 0 ? void 0 : _d.opacity) !== null && _e !== void 0 ? _e : itemOpacity;
|
|
44
|
+
const angle = (_g = (_f = stateParams === null || stateParams === void 0 ? void 0 : stateParams.styles) === null || _f === void 0 ? void 0 : _f.angle) !== null && _g !== void 0 ? _g : itemAngle;
|
|
42
45
|
(0, react_1.useEffect)(() => {
|
|
43
46
|
if (!ref)
|
|
44
47
|
return;
|
|
@@ -59,13 +62,21 @@ const CodeEmbedItem = ({ item, sectionId, onResize, interactionCtrl, onVisibilit
|
|
|
59
62
|
const iframe = ref.querySelector(`[data-embed="${item.id}"]`);
|
|
60
63
|
if (!iframe)
|
|
61
64
|
return;
|
|
62
|
-
|
|
65
|
+
const htmlWithStyles = `
|
|
66
|
+
${fontGoogleTags}
|
|
67
|
+
${fontAdobeTags}
|
|
68
|
+
<style>
|
|
69
|
+
${fontCustomTags}
|
|
70
|
+
</style>
|
|
71
|
+
${item.commonParams.html}
|
|
72
|
+
`;
|
|
73
|
+
iframe.srcdoc = htmlWithStyles;
|
|
63
74
|
}, [item.commonParams.html, item.commonParams.iframe, ref]);
|
|
64
75
|
const isInteractive = opacity !== 0;
|
|
65
76
|
(0, react_1.useEffect)(() => {
|
|
66
77
|
onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange(isInteractive);
|
|
67
78
|
}, [isInteractive, onVisibilityChange]);
|
|
68
|
-
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (
|
|
79
|
+
return ((0, jsx_runtime_1.jsxs)(LinkWrapper_1.LinkWrapper, { url: (_h = item.link) === null || _h === void 0 ? void 0 : _h.url, target: (_j = item.link) === null || _j === void 0 ? void 0 : _j.target, children: [(0, jsx_runtime_1.jsx)("div", { className: `embed-wrapper-${item.id}`, style: Object.assign(Object.assign(Object.assign(Object.assign({}, (angle !== undefined ? { transform: `rotate(${angle}deg)` } : {})), (blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {})), (opacity !== undefined ? { opacity } : {})), { transition: (_k = stateParams === null || stateParams === void 0 ? void 0 : stateParams.transition) !== null && _k !== void 0 ? _k : 'none' }), ref: setRef, children: item.commonParams.iframe ? ((0, jsx_runtime_1.jsx)("iframe", { "data-embed": item.id, className: `embed-${item.id}`, style: Object.assign(Object.assign({}, pos), { border: 'unset' }) })) : ((0, jsx_runtime_1.jsx)("div", { className: `embed-${item.id}`, style: Object.assign({}, pos), dangerouslySetInnerHTML: { __html: html } })) }), (0, jsx_runtime_1.jsx)(style_1.default, { id: id, children: `
|
|
69
80
|
.embed-wrapper-${item.id} {
|
|
70
81
|
position: absolute;
|
|
71
82
|
width: 100%;
|
|
@@ -15,6 +15,7 @@ class CntrlSdkContext {
|
|
|
15
15
|
this.customItems = customItems;
|
|
16
16
|
this.customSections = customSections;
|
|
17
17
|
this._layouts = [];
|
|
18
|
+
this._fonts = undefined;
|
|
18
19
|
this.sectionHeightMap = new Map();
|
|
19
20
|
}
|
|
20
21
|
resolveSectionData(sections) {
|
|
@@ -33,11 +34,15 @@ class CntrlSdkContext {
|
|
|
33
34
|
}
|
|
34
35
|
init({ project, article }) {
|
|
35
36
|
this.setLayouts(project.layouts);
|
|
37
|
+
this.setFonts(project.fonts);
|
|
36
38
|
this.setSectionsHeight(article.sections);
|
|
37
39
|
}
|
|
38
40
|
setLayouts(layouts) {
|
|
39
41
|
this._layouts = layouts;
|
|
40
42
|
}
|
|
43
|
+
setFonts(fonts) {
|
|
44
|
+
this._fonts = fonts;
|
|
45
|
+
}
|
|
41
46
|
setSectionsHeight(sections) {
|
|
42
47
|
for (const section of sections) {
|
|
43
48
|
this.sectionHeightMap.set(section.id, section.height);
|
|
@@ -50,6 +55,9 @@ class CntrlSdkContext {
|
|
|
50
55
|
get layouts() {
|
|
51
56
|
return this._layouts;
|
|
52
57
|
}
|
|
58
|
+
get fonts() {
|
|
59
|
+
return this._fonts;
|
|
60
|
+
}
|
|
53
61
|
}
|
|
54
62
|
exports.CntrlSdkContext = CntrlSdkContext;
|
|
55
63
|
function isDefined(value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cntrl-site/sdk-nextjs",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.13",
|
|
4
4
|
"description": "SDK for Next.js",
|
|
5
5
|
"author": "arsen@momdesign.nyc",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@antfu/eslint-config": "^3.8.0",
|
|
32
32
|
"@cntrl-site/color": "^1.0.0",
|
|
33
33
|
"@cntrl-site/effects": "^1.3.2",
|
|
34
|
-
"@cntrl-site/sdk": "^1.19.
|
|
34
|
+
"@cntrl-site/sdk": "^1.19.6",
|
|
35
35
|
"@types/vimeo__player": "^2.18.0",
|
|
36
36
|
"@vimeo/player": "^2.25.0",
|
|
37
37
|
"html-react-parser": "^3.0.1",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FC, ReactElement, useId, useRef } from 'react';
|
|
1
|
+
import { FC, ReactElement, useEffect, useId, useRef, useState, useContext } from 'react';
|
|
2
2
|
import JSXStyle from 'styled-jsx/style';
|
|
3
3
|
import {
|
|
4
4
|
getLayoutMediaQuery,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
11
11
|
import { useSectionRegistry } from '../../utils/ArticleRectManager/useSectionRegistry';
|
|
12
12
|
import { CntrlColor } from '@cntrl-site/color';
|
|
13
|
+
import { useLayoutContext } from '../useLayoutContext';
|
|
13
14
|
|
|
14
15
|
type SectionChild = ReactElement<any, any>;
|
|
15
16
|
const DEFAULT_COLOR = 'rgba(0, 0, 0, 0)';
|
|
@@ -20,13 +21,22 @@ interface Props {
|
|
|
20
21
|
data?: any;
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
function isVideoUrl(url: string): boolean {
|
|
25
|
+
const videoExtensions = ['.mp4', '.webm', '.ogg'];
|
|
26
|
+
return videoExtensions.some(ext => url.toLowerCase().endsWith(ext));
|
|
27
|
+
}
|
|
28
|
+
|
|
23
29
|
export const Section: FC<Props> = ({ section, data, children }) => {
|
|
24
30
|
const id = useId();
|
|
25
31
|
const sectionRef = useRef<HTMLDivElement | null>(null);
|
|
26
32
|
const { layouts, customSections } = useCntrlContext();
|
|
27
|
-
const
|
|
33
|
+
const layout = useLayoutContext();
|
|
34
|
+
const layoutValues: Record<string, any>[] = [section.height, section.color, section.media ?? {}];
|
|
28
35
|
const SectionComponent = section.name ? customSections.getComponent(section.name) : undefined;
|
|
36
|
+
const isVideo = layout && section.media?.[layout]?.url ? isVideoUrl(String(section.media?.[layout]?.url)) : false;
|
|
37
|
+
const videoRef = useRef<HTMLVideoElement | null>(null);
|
|
29
38
|
useSectionRegistry(section.id, sectionRef.current);
|
|
39
|
+
|
|
30
40
|
const getSectionVisibilityStyles = () => {
|
|
31
41
|
return layouts
|
|
32
42
|
.sort((a, b) => a.startsWith - b.startsWith)
|
|
@@ -36,33 +46,110 @@ export const Section: FC<Props> = ({ section, data, children }) => {
|
|
|
36
46
|
${acc}
|
|
37
47
|
${getLayoutMediaQuery(layout.id, layouts)} {
|
|
38
48
|
.section-${section.id} {
|
|
39
|
-
display: ${isHidden ? 'none': 'block'};
|
|
49
|
+
display: ${isHidden ? 'none' : 'block'};
|
|
40
50
|
}
|
|
41
51
|
}`;
|
|
42
52
|
}, '');
|
|
43
53
|
};
|
|
44
54
|
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!isVideo || !sectionRef.current || !videoRef.current) return;
|
|
57
|
+
const video = videoRef.current;
|
|
58
|
+
const section = sectionRef.current;
|
|
59
|
+
const observer = new IntersectionObserver(
|
|
60
|
+
([entry]) => {
|
|
61
|
+
if (entry.isIntersecting) {
|
|
62
|
+
video.style.display = 'block';
|
|
63
|
+
video.play().catch(() => {});
|
|
64
|
+
} else {
|
|
65
|
+
video.style.display = 'none';
|
|
66
|
+
video.pause();
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
root: null,
|
|
71
|
+
rootMargin: '50px',
|
|
72
|
+
threshold: 0
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
observer.observe(section);
|
|
76
|
+
return () => observer.disconnect();
|
|
77
|
+
}, [isVideo]);
|
|
78
|
+
|
|
45
79
|
if (SectionComponent) return <div ref={sectionRef}><SectionComponent data={data}>{children}</SectionComponent></div>;
|
|
46
80
|
|
|
47
|
-
|
|
81
|
+
return (
|
|
48
82
|
<>
|
|
49
83
|
<div
|
|
50
84
|
className={`section-${section.id}`}
|
|
51
85
|
id={section.name}
|
|
52
86
|
ref={sectionRef}
|
|
53
87
|
>
|
|
88
|
+
{layout && section.media?.[layout]?.url && section.media?.[layout]?.size !== 'none' && sectionRef.current && (
|
|
89
|
+
<div className={`section-background-overlay-${section.id}`}>
|
|
90
|
+
<div
|
|
91
|
+
key={`section-background-wrapper-${section.id}`}
|
|
92
|
+
className={`section-background-wrapper-${section.id}`}
|
|
93
|
+
>
|
|
94
|
+
{isVideo ? (
|
|
95
|
+
<video
|
|
96
|
+
ref={videoRef}
|
|
97
|
+
autoPlay
|
|
98
|
+
loop
|
|
99
|
+
muted
|
|
100
|
+
playsInline
|
|
101
|
+
preload="auto"
|
|
102
|
+
className={`video-background-${section.id}`}
|
|
103
|
+
>
|
|
104
|
+
<source src={section.media?.[layout]?.url ?? ''} />
|
|
105
|
+
</video>
|
|
106
|
+
) : (
|
|
107
|
+
<img src={section.media?.[layout]?.url ?? ''} className={`image-background-${section.id}`} />
|
|
108
|
+
)}
|
|
109
|
+
</div>
|
|
110
|
+
</div>
|
|
111
|
+
)}
|
|
54
112
|
{children}
|
|
55
113
|
</div>
|
|
56
114
|
<JSXStyle id={id}>{`
|
|
57
115
|
${
|
|
58
|
-
|
|
116
|
+
getLayoutStyles(layouts, layoutValues, ([height, color, media]) => (`
|
|
59
117
|
.section-${section.id} {
|
|
60
118
|
height: ${getSectionHeight(height)};
|
|
61
119
|
position: relative;
|
|
62
120
|
background-color: ${CntrlColor.parse(color ?? DEFAULT_COLOR).fmt('rgba')};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
|
|
121
|
+
}
|
|
122
|
+
.section-background-overlay-${section.id} {
|
|
123
|
+
height: ${getSectionHeight(height)};
|
|
124
|
+
width: 100%;
|
|
125
|
+
position: relative;
|
|
126
|
+
overflow: clip;
|
|
127
|
+
}
|
|
128
|
+
.section-background-wrapper-${section.id} {
|
|
129
|
+
transform: ${media?.position === 'fixed' ? 'translateY(-100vh)' : 'unset'};
|
|
130
|
+
left: 0;
|
|
131
|
+
position: relative;
|
|
132
|
+
height: ${media?.position === 'fixed' ? `calc(${getSectionHeight(height)} + 200vh)` : getSectionHeight(height)}};
|
|
133
|
+
width: 100%;
|
|
134
|
+
}
|
|
135
|
+
.video-background-${section.id} {
|
|
136
|
+
object-fit: ${media?.size ?? 'cover'};
|
|
137
|
+
width: 100%;
|
|
138
|
+
height: ${media?.position === 'fixed' ? '100vh' : '100%'};
|
|
139
|
+
position: ${media?.position === 'fixed' ? 'sticky' : 'relative'};
|
|
140
|
+
top: ${media?.position === 'fixed' ? '100vh' : 'unset'};
|
|
141
|
+
left: 0;
|
|
142
|
+
}
|
|
143
|
+
.image-background-${section.id} {
|
|
144
|
+
object-fit: ${media?.size};
|
|
145
|
+
width: 100%;
|
|
146
|
+
height: ${media?.position === 'fixed' ? '100vh' : '100%'};
|
|
147
|
+
position: ${media?.position === 'fixed' ? 'sticky' : 'relative'};
|
|
148
|
+
top: ${media?.position === 'fixed' ? '100vh' : 'unset'};
|
|
149
|
+
}
|
|
150
|
+
`
|
|
151
|
+
))
|
|
152
|
+
}
|
|
66
153
|
${getSectionVisibilityStyles()}
|
|
67
154
|
`}</JSXStyle>
|
|
68
155
|
</>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { getLayoutStyles, CodeEmbedItem as TCodeEmbedItem, AreaAnchor } from '@cntrl-site/sdk';
|
|
1
|
+
import { getLayoutStyles, CodeEmbedItem as TCodeEmbedItem, AreaAnchor, FontFaceGenerator } from '@cntrl-site/sdk';
|
|
2
2
|
import { FC, useEffect, useId, useState } from 'react';
|
|
3
3
|
import { useCntrlContext } from '../../../provider/useCntrlContext';
|
|
4
4
|
import { ItemProps } from '../Item';
|
|
5
5
|
import JSXStyle from 'styled-jsx/style';
|
|
6
|
-
import { useRegisterResize } from
|
|
6
|
+
import { useRegisterResize } from '../../../common/useRegisterResize';
|
|
7
7
|
import { useItemAngle } from '../useItemAngle';
|
|
8
8
|
import { LinkWrapper } from '../LinkWrapper';
|
|
9
9
|
import { useCodeEmbedItem } from './useCodeEmbedItem';
|
|
@@ -22,7 +22,10 @@ const stylesMap = {
|
|
|
22
22
|
|
|
23
23
|
export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => {
|
|
24
24
|
const id = useId();
|
|
25
|
-
const { layouts } = useCntrlContext();
|
|
25
|
+
const { layouts, fonts } = useCntrlContext();
|
|
26
|
+
const fontGoogleTags = fonts?.google;
|
|
27
|
+
const fontAdobeTags = fonts?.adobe;
|
|
28
|
+
const fontCustomTags = new FontFaceGenerator(fonts?.custom ?? []).generate();
|
|
26
29
|
const { anchor, blur: itemBlur, opacity: itemOpacity } = useCodeEmbedItem(item, sectionId);
|
|
27
30
|
const itemAngle = useItemAngle(item, sectionId);
|
|
28
31
|
const { html } = item.commonParams;
|
|
@@ -47,14 +50,23 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
47
50
|
script.parentNode!.removeChild(script);
|
|
48
51
|
ref.appendChild(newScript);
|
|
49
52
|
}
|
|
50
|
-
}, [item.commonParams.html])
|
|
53
|
+
}, [item.commonParams.html]);
|
|
51
54
|
|
|
52
55
|
useEffect(() => {
|
|
53
56
|
if (!ref) return;
|
|
54
57
|
const iframe: HTMLIFrameElement | null = ref.querySelector(`[data-embed="${item.id}"]`);
|
|
55
58
|
if (!iframe) return;
|
|
56
|
-
|
|
59
|
+
const htmlWithStyles = `
|
|
60
|
+
${fontGoogleTags}
|
|
61
|
+
${fontAdobeTags}
|
|
62
|
+
<style>
|
|
63
|
+
${fontCustomTags}
|
|
64
|
+
</style>
|
|
65
|
+
${item.commonParams.html}
|
|
66
|
+
`;
|
|
67
|
+
iframe.srcdoc = htmlWithStyles;
|
|
57
68
|
}, [item.commonParams.html, item.commonParams.iframe, ref]);
|
|
69
|
+
|
|
58
70
|
const isInteractive = opacity !== 0;
|
|
59
71
|
useEffect(() => {
|
|
60
72
|
onVisibilityChange?.(isInteractive);
|
|
@@ -69,7 +81,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
69
81
|
...(blur !== undefined ? { filter: `blur(${blur * 100}vw)` } : {}),
|
|
70
82
|
...(opacity !== undefined ? { opacity } : {}),
|
|
71
83
|
transition: stateParams?.transition ?? 'none'
|
|
72
|
-
|
|
84
|
+
}}
|
|
73
85
|
ref={setRef}
|
|
74
86
|
>
|
|
75
87
|
{item.commonParams.iframe ? (
|
|
@@ -102,7 +114,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
102
114
|
border: none;
|
|
103
115
|
}
|
|
104
116
|
${getLayoutStyles(layouts, layoutValues, ([area, layoutParams], exemplary) => {
|
|
105
|
-
|
|
117
|
+
return (`
|
|
106
118
|
.embed-wrapper-${item.id} {
|
|
107
119
|
opacity: ${layoutParams.opacity};
|
|
108
120
|
transform: rotate(${area.angle}deg);
|
|
@@ -113,7 +125,7 @@ export const CodeEmbedItem: FC<ItemProps<TCodeEmbedItem>> = ({ item, sectionId,
|
|
|
113
125
|
height: ${item.commonParams.scale ? `${area.height * exemplary}px` : '100%'};
|
|
114
126
|
}
|
|
115
127
|
`);
|
|
116
|
-
|
|
128
|
+
})}
|
|
117
129
|
`}</JSXStyle>
|
|
118
130
|
</LinkWrapper>
|
|
119
131
|
);
|
|
@@ -9,6 +9,7 @@ interface SdkContextInitProps {
|
|
|
9
9
|
|
|
10
10
|
export class CntrlSdkContext {
|
|
11
11
|
private _layouts: Layout[] = [];
|
|
12
|
+
private _fonts?: Project['fonts'] = undefined;
|
|
12
13
|
private sectionHeightMap: Map<string, Record<string, SectionHeight>> = new Map();
|
|
13
14
|
constructor(
|
|
14
15
|
public readonly customItems: CustomItemRegistry,
|
|
@@ -31,6 +32,7 @@ export class CntrlSdkContext {
|
|
|
31
32
|
|
|
32
33
|
init({ project, article }: SdkContextInitProps) {
|
|
33
34
|
this.setLayouts(project.layouts);
|
|
35
|
+
this.setFonts(project.fonts);
|
|
34
36
|
this.setSectionsHeight(article.sections);
|
|
35
37
|
}
|
|
36
38
|
|
|
@@ -38,9 +40,13 @@ export class CntrlSdkContext {
|
|
|
38
40
|
this._layouts = layouts;
|
|
39
41
|
}
|
|
40
42
|
|
|
43
|
+
private setFonts(fonts: Project['fonts']) {
|
|
44
|
+
this._fonts = fonts;
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
setSectionsHeight(sections: Section[]) {
|
|
42
48
|
for (const section of sections) {
|
|
43
|
-
this.sectionHeightMap.set(section.id, section.height)
|
|
49
|
+
this.sectionHeightMap.set(section.id, section.height);
|
|
44
50
|
}
|
|
45
51
|
}
|
|
46
52
|
|
|
@@ -52,6 +58,10 @@ export class CntrlSdkContext {
|
|
|
52
58
|
get layouts(): Layout[] {
|
|
53
59
|
return this._layouts;
|
|
54
60
|
}
|
|
61
|
+
|
|
62
|
+
get fonts(): Project['fonts'] | undefined {
|
|
63
|
+
return this._fonts;
|
|
64
|
+
}
|
|
55
65
|
}
|
|
56
66
|
|
|
57
67
|
function isDefined<T>(value: T): value is Exclude<T, undefined> {
|
|
@@ -27,7 +27,7 @@ export class ArticleRectObserver extends EventEmitter<EventMap> {
|
|
|
27
27
|
getSectionScroll(sectionId: string): number {
|
|
28
28
|
const sectionTop = this.sectionsScrollMap.get(sectionId);
|
|
29
29
|
if (sectionTop === undefined) return 0;
|
|
30
|
-
return -
|
|
30
|
+
return -(sectionTop / this.articleWidth - this.scrollPos);
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
getSectionTop(sectionId: string): number {
|
|
Binary file
|