@cntrl-site/sdk-nextjs 0.2.13 → 0.4.0
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/cntrl-site-sdk-nextjs-0.4.0.tgz +0 -0
- package/lib/common/useCurrentLayout.js +42 -0
- package/lib/common/useKeyframeValue.js +66 -0
- package/lib/components/Article.js +7 -2
- package/lib/components/Item.js +24 -16
- package/lib/components/Page.js +9 -2
- package/lib/components/Section.js +3 -1
- package/lib/components/items/ImageItem.js +11 -4
- package/lib/components/items/RectangleItem.js +12 -5
- package/lib/components/items/RichTextItem.js +12 -4
- package/lib/components/items/VideoItem.js +29 -22
- package/lib/components/items/VimeoEmbed.js +15 -14
- package/lib/components/items/YoutubeEmbed.js +15 -14
- package/lib/components/items/useEmbedVideoItem.js +16 -0
- package/lib/components/items/useFileItem.js +22 -0
- package/lib/components/items/useRectangleItem.js +29 -0
- package/lib/components/useItemAngle.js +9 -0
- package/lib/components/useItemDimensions.js +19 -0
- package/lib/components/useItemPosition.js +34 -0
- package/lib/index.js +4 -4
- package/lib/provider/ArticleRectContext.js +5 -0
- package/lib/provider/CntrlSdkContext.js +13 -0
- package/lib/provider/Keyframes.js +12 -0
- package/lib/provider/KeyframesContext.js +6 -0
- package/lib/utils/Animator/Animator.js +159 -0
- package/lib/utils/ArticleRectManager/ArticleRectObserver.js +61 -0
- package/lib/utils/ArticleRectManager/useArticleRectObserver.js +18 -0
- package/lib/utils/EventEmitter.js +35 -0
- package/lib/utils/{RichTextConverter.js → RichTextConverter/RichTextConverter.js} +3 -3
- package/lib/utils/binSearchInsertAt.js +36 -0
- package/lib/utils/generateTypePresetStyles/generateTypePresetStyles.js +27 -0
- package/package.json +8 -3
- package/src/common/useCurrentLayout.ts +47 -0
- package/src/common/useKeyframeValue.ts +74 -0
- package/src/components/Article.tsx +13 -9
- package/src/components/Item.tsx +31 -21
- package/src/components/Page.tsx +16 -4
- package/src/components/Section.tsx +4 -3
- package/src/components/items/ImageItem.tsx +23 -14
- package/src/components/items/RectangleItem.tsx +21 -12
- package/src/components/items/RichTextItem.tsx +22 -11
- package/src/components/items/VideoItem.tsx +37 -30
- package/src/components/items/VimeoEmbed.tsx +19 -17
- package/src/components/items/YoutubeEmbed.tsx +17 -15
- package/src/components/items/useEmbedVideoItem.ts +19 -0
- package/src/components/items/useFileItem.ts +29 -0
- package/src/components/items/useRectangleItem.ts +40 -0
- package/src/components/useItemAngle.ts +12 -0
- package/src/components/useItemDimensions.ts +23 -0
- package/src/components/useItemPosition.ts +36 -0
- package/src/index.ts +2 -3
- package/src/provider/ArticleRectContext.ts +4 -0
- package/src/provider/CntrlSdkContext.ts +22 -2
- package/src/provider/Keyframes.ts +11 -0
- package/src/provider/KeyframesContext.ts +5 -0
- package/src/utils/Animator/Animator.ts +206 -0
- package/src/utils/ArticleRectManager/ArticleRectObserver.ts +69 -0
- package/src/utils/ArticleRectManager/useArticleRectObserver.ts +17 -0
- package/src/utils/EventEmitter.ts +41 -0
- package/src/utils/{RichTextConverter.tsx → RichTextConverter/RichTextConverter.tsx} +7 -6
- package/src/utils/binSearchInsertAt.ts +33 -0
- package/src/utils/generateTypePresetStyles/__mock__/layoutsMock.ts +37 -0
- package/src/utils/generateTypePresetStyles/__mock__/presetMock.ts +49 -0
- package/src/utils/generateTypePresetStyles/generateTypePresetStyles.test.ts +49 -0
- package/src/utils/generateTypePresetStyles/generateTypePresetStyles.ts +25 -0
- package/src/utils/getInvertedRanges.ts +43 -0
- package/.idea/workspace.xml +0 -293
- package/cntrl-site-sdk-nextjs-0.2.13.tgz +0 -0
package/src/components/Item.tsx
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { ComponentType, FC } from 'react';
|
|
1
|
+
import { ComponentType, FC, useEffect, useRef } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
getLayoutStyles,
|
|
4
4
|
ArticleItemType,
|
|
5
5
|
ArticleItemSizingType as SizingType,
|
|
6
|
-
TArticleItemAny
|
|
7
|
-
TLayout,
|
|
8
|
-
AnchorSide
|
|
6
|
+
TArticleItemAny
|
|
9
7
|
} from '@cntrl-site/sdk';
|
|
10
8
|
import { RectangleItem } from './items/RectangleItem';
|
|
11
9
|
import { ImageItem } from './items/ImageItem';
|
|
@@ -14,9 +12,12 @@ import { RichTextItem } from './items/RichTextItem';
|
|
|
14
12
|
import { VimeoEmbedItem } from './items/VimeoEmbed';
|
|
15
13
|
import { YoutubeEmbedItem } from './items/YoutubeEmbed';
|
|
16
14
|
import { CustomItem } from './items/CustomItem';
|
|
15
|
+
import { useCntrlContext } from '../provider/useCntrlContext';
|
|
16
|
+
import { useItemAngle } from './useItemAngle';
|
|
17
|
+
import { getItemTopStyle, useItemPosition } from './useItemPosition';
|
|
18
|
+
import { useItemDimensions } from './useItemDimensions';
|
|
17
19
|
|
|
18
20
|
export interface ItemProps<I extends TArticleItemAny> {
|
|
19
|
-
layouts: TLayout[];
|
|
20
21
|
item: I;
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -32,8 +33,13 @@ const itemsMap: Record<ArticleItemType, ComponentType<ItemProps<any>>> = {
|
|
|
32
33
|
|
|
33
34
|
const noop = () => null;
|
|
34
35
|
|
|
35
|
-
export const Item: FC<ItemProps<TArticleItemAny>> = ({ item
|
|
36
|
+
export const Item: FC<ItemProps<TArticleItemAny>> = ({ item }) => {
|
|
37
|
+
const { layouts } = useCntrlContext();
|
|
38
|
+
const angle = useItemAngle(item);
|
|
39
|
+
const { top, left } = useItemPosition(item);
|
|
40
|
+
const { width, height } = useItemDimensions(item);
|
|
36
41
|
const layoutValues: Record<string, any>[] = [item.area];
|
|
42
|
+
const isInitialRef = useRef(true);
|
|
37
43
|
if (item.layoutParams) {
|
|
38
44
|
layoutValues.push(item.layoutParams);
|
|
39
45
|
}
|
|
@@ -41,13 +47,30 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, layouts }) => {
|
|
|
41
47
|
const sizingAxis = parseSizing(item.commonParams.sizing);
|
|
42
48
|
const ItemComponent = itemsMap[item.type] || noop;
|
|
43
49
|
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
isInitialRef.current = false;
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
const styles = {
|
|
55
|
+
transform: `rotate(${angle}deg)`,
|
|
56
|
+
left: `${left * 100}vw`,
|
|
57
|
+
width: `${sizingAxis.x === SizingType.Manual ? `${width * 100}vw` : 'max-content'}`,
|
|
58
|
+
height: `${sizingAxis.y === SizingType.Manual ? `${height * 100}vw` : 'unset'}`,
|
|
59
|
+
top
|
|
60
|
+
};
|
|
61
|
+
|
|
44
62
|
return (
|
|
45
|
-
<div
|
|
46
|
-
|
|
63
|
+
<div
|
|
64
|
+
suppressHydrationWarning={true}
|
|
65
|
+
className={`item-${item.id}`}
|
|
66
|
+
style={isInitialRef.current ? {} : styles }
|
|
67
|
+
>
|
|
68
|
+
<ItemComponent item={item} />
|
|
47
69
|
<style jsx>{`
|
|
48
70
|
${getLayoutStyles(layouts, layoutValues, ([area]) => (`
|
|
49
71
|
.item-${item.id} {
|
|
50
72
|
position: absolute;
|
|
73
|
+
z-index: ${area.zIndex};
|
|
51
74
|
top: ${getItemTopStyle(area.top, area.anchorSide)};
|
|
52
75
|
left: ${area.left * 100}vw;
|
|
53
76
|
width: ${sizingAxis.x === SizingType.Manual ? `${area.width * 100}vw` : 'max-content'};
|
|
@@ -61,19 +84,6 @@ export const Item: FC<ItemProps<TArticleItemAny>> = ({ item, layouts }) => {
|
|
|
61
84
|
);
|
|
62
85
|
};
|
|
63
86
|
|
|
64
|
-
function getItemTopStyle(top: number, anchorSide: AnchorSide) {
|
|
65
|
-
const defaultValue = `${top * 100}vw`;
|
|
66
|
-
if (!anchorSide) return defaultValue;
|
|
67
|
-
switch (anchorSide) {
|
|
68
|
-
case AnchorSide.Top:
|
|
69
|
-
return defaultValue;
|
|
70
|
-
case AnchorSide.Center:
|
|
71
|
-
return `calc(50% + ${top * 100}vw)`;
|
|
72
|
-
case AnchorSide.Bottom:
|
|
73
|
-
return `calc(100% + ${top * 100}vw)`;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
87
|
function parseSizing(sizing: string): Axis {
|
|
78
88
|
const axisSizing = sizing.split(' ');
|
|
79
89
|
return {
|
package/src/components/Page.tsx
CHANGED
|
@@ -1,24 +1,36 @@
|
|
|
1
|
-
import React, { FC } from 'react';
|
|
1
|
+
import React, { FC, useMemo } from 'react';
|
|
2
2
|
import HTMLReactParser from 'html-react-parser';
|
|
3
|
-
import { TArticle, TProject, TMeta } from '@cntrl-site/sdk';
|
|
3
|
+
import { TArticle, TProject, TMeta, TKeyframeAny } from '@cntrl-site/sdk';
|
|
4
4
|
import { Article } from './Article';
|
|
5
|
+
import { KeyframesContext } from '../provider/KeyframesContext';
|
|
5
6
|
import { CNTRLHead } from './Head';
|
|
7
|
+
import { useCntrlContext } from '../provider/useCntrlContext';
|
|
8
|
+
import { generateTypePresetStyles } from '../utils/generateTypePresetStyles/generateTypePresetStyles';
|
|
9
|
+
import { Keyframes } from '../provider/Keyframes';
|
|
6
10
|
|
|
7
11
|
interface Props {
|
|
8
12
|
article: TArticle;
|
|
9
13
|
project: TProject;
|
|
10
14
|
meta: TMeta;
|
|
15
|
+
keyframes: TKeyframeAny[];
|
|
11
16
|
}
|
|
12
17
|
|
|
13
|
-
export const Page: FC<Props> = ({ article, project, meta }) => {
|
|
18
|
+
export const Page: FC<Props> = ({ article, project, meta, keyframes }) => {
|
|
14
19
|
const afterBodyOpen = HTMLReactParser(project.html.afterBodyOpen);
|
|
15
20
|
const beforeBodyClose = HTMLReactParser(project.html.beforeBodyClose);
|
|
21
|
+
const keyframesRepo = useMemo(() => new Keyframes(keyframes), [keyframes]);
|
|
22
|
+
const { typePresets, layouts } = useCntrlContext();
|
|
16
23
|
return (
|
|
17
24
|
<>
|
|
18
25
|
<CNTRLHead project={project} meta={meta} />
|
|
19
26
|
{afterBodyOpen}
|
|
20
|
-
<
|
|
27
|
+
<KeyframesContext.Provider value={keyframesRepo}>
|
|
28
|
+
<Article article={article} />
|
|
29
|
+
</KeyframesContext.Provider>
|
|
21
30
|
{beforeBodyClose}
|
|
31
|
+
{typePresets && typePresets.presets.length > 0 && (
|
|
32
|
+
<style>{generateTypePresetStyles(typePresets, layouts)}</style>
|
|
33
|
+
)}
|
|
22
34
|
</>
|
|
23
35
|
);
|
|
24
36
|
};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { FC, ReactElement } from 'react';
|
|
2
|
-
import { getLayoutMediaQuery, getLayoutStyles, TArticleSection,
|
|
2
|
+
import { getLayoutMediaQuery, getLayoutStyles, TArticleSection, TSectionHeight, SectionHeightMode } from '@cntrl-site/sdk';
|
|
3
|
+
import { useCntrlContext } from '../provider/useCntrlContext';
|
|
3
4
|
|
|
4
5
|
type SectionChild = ReactElement<any, any>;
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
section: TArticleSection;
|
|
8
|
-
layouts: TLayout[];
|
|
9
9
|
children: SectionChild[];
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export const Section: FC<Props> = ({ section,
|
|
12
|
+
export const Section: FC<Props> = ({ section, children }) => {
|
|
13
|
+
const { layouts } = useCntrlContext();
|
|
13
14
|
const getSectionVisibilityStyles = () => {
|
|
14
15
|
return layouts
|
|
15
16
|
.sort((a, b) => a.startsWith - b.startsWith)
|
|
@@ -2,15 +2,25 @@ import { FC } from 'react';
|
|
|
2
2
|
import { getLayoutStyles, TImageItem } from '@cntrl-site/sdk';
|
|
3
3
|
import { ItemProps } from '../Item';
|
|
4
4
|
import { LinkWrapper } from '../LinkWrapper';
|
|
5
|
+
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
6
|
+
import { useFileItem } from './useFileItem';
|
|
5
7
|
|
|
6
|
-
export const ImageItem: FC<ItemProps<TImageItem>> = ({ item
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
export const ImageItem: FC<ItemProps<TImageItem>> = ({ item }) => {
|
|
9
|
+
const { layouts } = useCntrlContext();
|
|
10
|
+
const { radius, strokeWidth } = useFileItem(item);
|
|
11
|
+
return (
|
|
12
|
+
<LinkWrapper url={item.link?.url}>
|
|
13
|
+
<>
|
|
14
|
+
<div className={`image-wrapper-${item.id}`}
|
|
15
|
+
style={{
|
|
16
|
+
borderRadius: `${radius * 100}vw`,
|
|
17
|
+
borderWidth: `${strokeWidth * 100}vw`
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
<img className="image" src={item.commonParams.url} />
|
|
21
|
+
</div>
|
|
22
|
+
<style jsx>{`
|
|
23
|
+
${getLayoutStyles(layouts, [item.layoutParams], ([{ strokeColor, opacity }]) => (`
|
|
14
24
|
.image-wrapper-${item.id} {
|
|
15
25
|
position: absolute;
|
|
16
26
|
overflow: hidden;
|
|
@@ -19,11 +29,9 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, layouts }) => (
|
|
|
19
29
|
border-style: solid;
|
|
20
30
|
box-sizing: border-box;
|
|
21
31
|
border-color: ${strokeColor};
|
|
22
|
-
border-radius: ${radius * 100}vw;
|
|
23
32
|
opacity: ${opacity};
|
|
24
|
-
border-width: ${strokeWidth * 100}vw;
|
|
25
33
|
}`
|
|
26
|
-
|
|
34
|
+
))
|
|
27
35
|
}
|
|
28
36
|
.image {
|
|
29
37
|
width: 100%;
|
|
@@ -33,6 +41,7 @@ export const ImageItem: FC<ItemProps<TImageItem>> = ({ item, layouts }) => (
|
|
|
33
41
|
pointer-events: none;
|
|
34
42
|
}
|
|
35
43
|
`}</style>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
);
|
|
44
|
+
</>
|
|
45
|
+
</LinkWrapper>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
@@ -2,13 +2,24 @@ import { FC } from 'react';
|
|
|
2
2
|
import { TRectangleItem, getLayoutStyles } from '@cntrl-site/sdk';
|
|
3
3
|
import { ItemProps } from '../Item';
|
|
4
4
|
import { LinkWrapper } from '../LinkWrapper';
|
|
5
|
+
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
6
|
+
import { useRectangleItem } from './useRectangleItem';
|
|
5
7
|
|
|
6
|
-
export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item }) => {
|
|
9
|
+
const { layouts } = useCntrlContext();
|
|
10
|
+
const { fillColor, radius, strokeWidth } = useRectangleItem(item);
|
|
11
|
+
return (
|
|
12
|
+
<LinkWrapper url={item.link?.url}>
|
|
13
|
+
<>
|
|
14
|
+
<div className={`rectangle-${item.id}`}
|
|
15
|
+
style={{
|
|
16
|
+
backgroundColor: `${fillColor}`,
|
|
17
|
+
borderRadius: `${radius * 100}vw`,
|
|
18
|
+
borderWidth: `${strokeWidth * 100}vw`
|
|
19
|
+
}}
|
|
20
|
+
/>
|
|
21
|
+
<style jsx>{`
|
|
22
|
+
${getLayoutStyles(layouts, [item.layoutParams], ([{ strokeColor }]) => (`
|
|
12
23
|
.rectangle-${item.id} {
|
|
13
24
|
position: absolute;
|
|
14
25
|
width: 100%;
|
|
@@ -16,12 +27,10 @@ export const RectangleItem: FC<ItemProps<TRectangleItem>> = ({ item, layouts })
|
|
|
16
27
|
border-style: solid;
|
|
17
28
|
box-sizing: border-box;
|
|
18
29
|
border-color: ${strokeColor};
|
|
19
|
-
background-color: ${fillColor};
|
|
20
|
-
border-radius: ${radius * 100}vw;
|
|
21
|
-
border-width: ${strokeWidth * 100}vw;
|
|
22
30
|
}`
|
|
23
31
|
))}
|
|
24
32
|
`}</style>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
);
|
|
33
|
+
</>
|
|
34
|
+
</LinkWrapper>
|
|
35
|
+
);
|
|
36
|
+
};
|
|
@@ -1,20 +1,31 @@
|
|
|
1
|
-
import { FC } from 'react';
|
|
1
|
+
import { FC, createElement } from 'react';
|
|
2
2
|
import { TRichTextItem } from '@cntrl-site/sdk';
|
|
3
3
|
//@ts-ignore
|
|
4
4
|
import JSXStyle from 'styled-jsx/style';
|
|
5
5
|
import { ItemProps } from '../Item';
|
|
6
|
-
import { RichTextConverter } from '../../utils/RichTextConverter';
|
|
6
|
+
import { RichTextConverter } from '../../utils/RichTextConverter/RichTextConverter';
|
|
7
|
+
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
7
8
|
|
|
8
9
|
const richTextConv = new RichTextConverter();
|
|
9
10
|
|
|
10
|
-
export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
export const RichTextItem: FC<ItemProps<TRichTextItem>> = ({ item }) => {
|
|
12
|
+
const { layouts, typePresets } = useCntrlContext();
|
|
13
|
+
const preset = item.commonParams.preset
|
|
14
|
+
? typePresets?.presets.find(p => p.id === item.commonParams.preset)
|
|
15
|
+
: null;
|
|
16
|
+
const [content, styles] = richTextConv.toHtml(item, layouts, !!preset);
|
|
17
|
+
return createElement(
|
|
18
|
+
preset?.tag ?? 'div',
|
|
19
|
+
{
|
|
20
|
+
className: preset ? `cntrl-preset-${preset.id}` : undefined
|
|
21
|
+
},
|
|
22
|
+
(
|
|
23
|
+
<>
|
|
24
|
+
{content}
|
|
25
|
+
<JSXStyle id={item.id}>
|
|
26
|
+
{styles}
|
|
27
|
+
</JSXStyle>
|
|
28
|
+
</>
|
|
29
|
+
)
|
|
19
30
|
);
|
|
20
31
|
};
|
|
@@ -3,39 +3,46 @@ import { TVideoItem } from '@cntrl-site/sdk';
|
|
|
3
3
|
import { ItemProps } from '../Item';
|
|
4
4
|
import { LinkWrapper } from '../LinkWrapper';
|
|
5
5
|
import { getLayoutStyles } from '@cntrl-site/sdk';
|
|
6
|
+
import { useCntrlContext } from '../../provider/useCntrlContext';
|
|
7
|
+
import { useFileItem } from './useFileItem';
|
|
6
8
|
|
|
7
|
-
export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
export const VideoItem: FC<ItemProps<TVideoItem>> = ({ item }) => {
|
|
10
|
+
const { layouts } = useCntrlContext();
|
|
11
|
+
const { radius, strokeWidth } = useFileItem(item);
|
|
12
|
+
return (
|
|
13
|
+
<LinkWrapper url={item.link?.url}>
|
|
14
|
+
<div className={`video-wrapper-${item.id}`}
|
|
15
|
+
style={{
|
|
16
|
+
borderRadius: `${radius * 100}vw`,
|
|
17
|
+
borderWidth: `${strokeWidth * 100}vw`
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
11
20
|
<video autoPlay muted loop playsInline className="video">
|
|
12
21
|
<source src={item.commonParams.url} />
|
|
13
22
|
</video>
|
|
14
23
|
</div>
|
|
15
24
|
<style jsx>{`
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
</LinkWrapper>
|
|
41
|
-
);
|
|
25
|
+
${getLayoutStyles(layouts, [item.layoutParams], ([{ strokeColor, opacity }]) => (`
|
|
26
|
+
.video-wrapper-${item.id} {
|
|
27
|
+
position: absolute;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
width: 100%;
|
|
30
|
+
height: 100%;
|
|
31
|
+
border-style: solid;
|
|
32
|
+
box-sizing: border-box;
|
|
33
|
+
border-color: ${strokeColor};
|
|
34
|
+
opacity: ${opacity};
|
|
35
|
+
}`
|
|
36
|
+
))
|
|
37
|
+
}
|
|
38
|
+
.video {
|
|
39
|
+
width: 100%;
|
|
40
|
+
height: 100%;
|
|
41
|
+
opacity: 1;
|
|
42
|
+
object-fit: cover;
|
|
43
|
+
pointer-events: none;
|
|
44
|
+
}
|
|
45
|
+
`}</style>
|
|
46
|
+
</LinkWrapper>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
-
import { getLayoutStyles } from '@cntrl-site/sdk';
|
|
3
2
|
import { TVimeoEmbedItem } from '@cntrl-site/core';
|
|
4
3
|
import { ItemProps } from '../Item';
|
|
5
4
|
import { LinkWrapper } from '../LinkWrapper';
|
|
5
|
+
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
6
6
|
|
|
7
|
-
export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item
|
|
8
|
-
|
|
7
|
+
export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item }) => {
|
|
8
|
+
const { radius } = useEmbedVideoItem(item);
|
|
9
|
+
const { autoplay, controls, loop, muted, pictureInPicture, url } = item.commonParams;
|
|
9
10
|
const getValidVimeoUrl = (url: string): string => {
|
|
10
11
|
const validURL = new URL(url);
|
|
11
12
|
validURL.searchParams.append('controls', String(controls));
|
|
@@ -24,7 +25,11 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, layouts }
|
|
|
24
25
|
|
|
25
26
|
return (
|
|
26
27
|
<LinkWrapper url={item.link?.url}>
|
|
27
|
-
<div className={`embed-video-wrapper-${item.id}`}
|
|
28
|
+
<div className={`embed-video-wrapper-${item.id}`}
|
|
29
|
+
style={{
|
|
30
|
+
borderRadius: `${radius * 100}vw`
|
|
31
|
+
}}
|
|
32
|
+
>
|
|
28
33
|
<iframe
|
|
29
34
|
className="embedVideo"
|
|
30
35
|
src={validUrl || ''}
|
|
@@ -33,18 +38,15 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, layouts }
|
|
|
33
38
|
/>
|
|
34
39
|
</div>
|
|
35
40
|
<style jsx>{`
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
border-radius: ${radius * 100}vw;
|
|
46
|
-
}`
|
|
47
|
-
))}
|
|
41
|
+
.embed-video-wrapper-${item.id} {
|
|
42
|
+
position: absolute;
|
|
43
|
+
overflow: hidden;
|
|
44
|
+
width: 100%;
|
|
45
|
+
height: 100%;
|
|
46
|
+
top: 50%;
|
|
47
|
+
left: 50%;
|
|
48
|
+
transform: translate(-50%, -50%);
|
|
49
|
+
}
|
|
48
50
|
.embedVideo {
|
|
49
51
|
width: 100%;
|
|
50
52
|
height: 100%;
|
|
@@ -53,5 +55,5 @@ export const VimeoEmbedItem: FC<ItemProps<TVimeoEmbedItem>> = ({ item, layouts }
|
|
|
53
55
|
}
|
|
54
56
|
`}</style>
|
|
55
57
|
</LinkWrapper>
|
|
56
|
-
)
|
|
58
|
+
);
|
|
57
59
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { FC } from 'react';
|
|
2
|
-
import { getLayoutStyles } from '@cntrl-site/sdk';
|
|
3
2
|
import { TYoutubeEmbedItem } from '@cntrl-site/core';
|
|
4
3
|
import { ItemProps } from '../Item';
|
|
5
4
|
import { LinkWrapper } from '../LinkWrapper';
|
|
6
5
|
import { getYoutubeId } from '../../utils/getValidYoutubeUrl';
|
|
6
|
+
import { useEmbedVideoItem } from './useEmbedVideoItem';
|
|
7
7
|
|
|
8
|
-
export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item
|
|
8
|
+
export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item }) => {
|
|
9
9
|
const { autoplay, controls, url } = item.commonParams;
|
|
10
|
+
const { radius } = useEmbedVideoItem(item);
|
|
10
11
|
|
|
11
12
|
const getValidYoutubeUrl = (url: string): string => {
|
|
12
13
|
const newUrl = new URL(url);
|
|
@@ -22,7 +23,11 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, layou
|
|
|
22
23
|
|
|
23
24
|
return (
|
|
24
25
|
<LinkWrapper url={item.link?.url}>
|
|
25
|
-
<div className={`embed-youtube-video-wrapper-${item.id}`}
|
|
26
|
+
<div className={`embed-youtube-video-wrapper-${item.id}`}
|
|
27
|
+
style={{
|
|
28
|
+
borderRadius: `${radius * 100}vw`
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
26
31
|
<iframe
|
|
27
32
|
className="embedYoutubeVideo"
|
|
28
33
|
src={validUrl || ''}
|
|
@@ -31,18 +36,15 @@ export const YoutubeEmbedItem: FC<ItemProps<TYoutubeEmbedItem>> = ({ item, layou
|
|
|
31
36
|
/>
|
|
32
37
|
</div>
|
|
33
38
|
<style jsx>{`
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
border-radius: ${radius * 100}vw;
|
|
44
|
-
}`
|
|
45
|
-
))}
|
|
39
|
+
.embed-youtube-video-wrapper-${item.id} {
|
|
40
|
+
position: absolute;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
width: 100%;
|
|
43
|
+
height: 100%;
|
|
44
|
+
top: 50%;
|
|
45
|
+
left: 50%;
|
|
46
|
+
transform: translate(-50%, -50%);
|
|
47
|
+
}
|
|
46
48
|
.embedYoutubeVideo {
|
|
47
49
|
width: 100%;
|
|
48
50
|
height: 100%;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { TVimeoEmbedItem, TYoutubeEmbedItem } from '@cntrl-site/core';
|
|
2
|
+
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
3
|
+
import { useKeyframeValue } from '../../common/useKeyframeValue';
|
|
4
|
+
|
|
5
|
+
export const useEmbedVideoItem = (item: TVimeoEmbedItem | TYoutubeEmbedItem) => {
|
|
6
|
+
const layoutId = useCurrentLayout();
|
|
7
|
+
const radius = useKeyframeValue(
|
|
8
|
+
item,
|
|
9
|
+
(item, layoutId) => {
|
|
10
|
+
if (!layoutId) return 0;
|
|
11
|
+
const layoutParams = item.layoutParams[layoutId];
|
|
12
|
+
return 'radius' in layoutParams ? layoutParams.radius : 0;
|
|
13
|
+
},
|
|
14
|
+
(animator, scroll, value) => animator.getRadius({ radius: value }, scroll).radius,
|
|
15
|
+
[layoutId]
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
return { radius };
|
|
19
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { TImageItem, TVideoItem } from '@cntrl-site/sdk';
|
|
2
|
+
import { useKeyframeValue } from '../../common/useKeyframeValue';
|
|
3
|
+
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
4
|
+
|
|
5
|
+
export const useFileItem = (item: TImageItem | TVideoItem) => {
|
|
6
|
+
const layoutId = useCurrentLayout();
|
|
7
|
+
const radius = useKeyframeValue(
|
|
8
|
+
item,
|
|
9
|
+
(item, layoutId) => {
|
|
10
|
+
if (!layoutId) return 0;
|
|
11
|
+
const layoutParams = item.layoutParams[layoutId];
|
|
12
|
+
return 'radius' in layoutParams ? layoutParams.radius : 0;
|
|
13
|
+
},
|
|
14
|
+
(animator, scroll, value) => animator.getRadius({ radius: value }, scroll).radius,
|
|
15
|
+
[layoutId]
|
|
16
|
+
);
|
|
17
|
+
const strokeWidth = useKeyframeValue(
|
|
18
|
+
item,
|
|
19
|
+
(item, layoutId) => {
|
|
20
|
+
if (!layoutId) return 0;
|
|
21
|
+
const layoutParams = item.layoutParams[layoutId];
|
|
22
|
+
return 'strokeWidth' in layoutParams ? layoutParams.strokeWidth : 0;
|
|
23
|
+
},
|
|
24
|
+
(animator, scroll, value) => animator.getBorderWidth({ borderWidth: value }, scroll).borderWidth,
|
|
25
|
+
[layoutId]
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
return { radius, strokeWidth };
|
|
29
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { TRectangleItem } from '@cntrl-site/sdk';
|
|
2
|
+
import { useKeyframeValue } from '../../common/useKeyframeValue';
|
|
3
|
+
import { useCurrentLayout } from '../../common/useCurrentLayout';
|
|
4
|
+
|
|
5
|
+
const defaultColor = 'rgba(0, 0, 0, 1)';
|
|
6
|
+
|
|
7
|
+
export const useRectangleItem = (item: TRectangleItem) => {
|
|
8
|
+
const layoutId = useCurrentLayout();
|
|
9
|
+
const radius = useKeyframeValue(
|
|
10
|
+
item,
|
|
11
|
+
(item, layoutId) => {
|
|
12
|
+
if (!layoutId) return 0;
|
|
13
|
+
const layoutParams = item.layoutParams[layoutId];
|
|
14
|
+
return 'radius' in layoutParams ? layoutParams.radius : 0;
|
|
15
|
+
},
|
|
16
|
+
(animator, scroll, value) => animator.getRadius({ radius: value }, scroll).radius,
|
|
17
|
+
[layoutId]
|
|
18
|
+
);
|
|
19
|
+
const strokeWidth = useKeyframeValue(
|
|
20
|
+
item,
|
|
21
|
+
(item, layoutId) => {
|
|
22
|
+
if (!layoutId) return 0;
|
|
23
|
+
const layoutParams = item.layoutParams[layoutId];
|
|
24
|
+
return 'strokeWidth' in layoutParams ? layoutParams.strokeWidth : 0;
|
|
25
|
+
},
|
|
26
|
+
(animator, scroll, value) => animator.getBorderWidth({ borderWidth: value }, scroll).borderWidth,
|
|
27
|
+
[layoutId]
|
|
28
|
+
);
|
|
29
|
+
const fillColor = useKeyframeValue(
|
|
30
|
+
item,
|
|
31
|
+
(item, layoutId) => {
|
|
32
|
+
if (!layoutId) return defaultColor;
|
|
33
|
+
const layoutParams = item.layoutParams[layoutId];
|
|
34
|
+
return 'fillColor' in layoutParams ? layoutParams.fillColor : defaultColor;
|
|
35
|
+
},
|
|
36
|
+
(animator, scroll, value) => animator.getColor({ color: value }, scroll).color
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return { fillColor, strokeWidth, radius };
|
|
40
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TArticleItemAny } from '@cntrl-site/sdk';
|
|
2
|
+
import { useKeyframeValue } from '../common/useKeyframeValue';
|
|
3
|
+
|
|
4
|
+
export const useItemAngle = (item: TArticleItemAny) => {
|
|
5
|
+
const { angle } = useKeyframeValue(
|
|
6
|
+
item,
|
|
7
|
+
(item, layoutId) => ({ angle: layoutId ? item.area[layoutId].angle : 0 }),
|
|
8
|
+
(animator, scroll, value) => animator.getRotation(value, scroll)
|
|
9
|
+
);
|
|
10
|
+
return angle;
|
|
11
|
+
};
|
|
12
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { TArticleItemAny } from '@cntrl-site/sdk';
|
|
2
|
+
import { useCurrentLayout } from '../common/useCurrentLayout';
|
|
3
|
+
import { useKeyframeValue } from '../common/useKeyframeValue';
|
|
4
|
+
|
|
5
|
+
const defaultArea = {
|
|
6
|
+
left: 0,
|
|
7
|
+
top: 0,
|
|
8
|
+
width: 0,
|
|
9
|
+
height: 0,
|
|
10
|
+
angle: 0,
|
|
11
|
+
zIndex: 0
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const useItemDimensions = (item: TArticleItemAny) => {
|
|
15
|
+
const layoutId = useCurrentLayout();
|
|
16
|
+
const { width, height } = useKeyframeValue<{ width: number; height: number }>(
|
|
17
|
+
item,
|
|
18
|
+
(item, layoutId) => layoutId ? item.area[layoutId] : defaultArea,
|
|
19
|
+
(animator, scroll, value) => animator.getDimensions(value, scroll),
|
|
20
|
+
[layoutId]
|
|
21
|
+
);
|
|
22
|
+
return { width, height };
|
|
23
|
+
};
|