payload-plugin-decks 1.0.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/README.md +205 -0
- package/dist/blocks/decks/config.d.ts +2 -0
- package/dist/blocks/decks/config.js +148 -0
- package/dist/blocks/decks/config.js.map +1 -0
- package/dist/blocks/decks/index.d.ts +4 -0
- package/dist/blocks/decks/index.js +6 -0
- package/dist/blocks/decks/index.js.map +1 -0
- package/dist/components/decks/DecksBlock.d.ts +5 -0
- package/dist/components/decks/DecksBlock.js +104 -0
- package/dist/components/decks/DecksBlock.js.map +1 -0
- package/dist/components/decks/DecksComposition.d.ts +9 -0
- package/dist/components/decks/DecksComposition.js +94 -0
- package/dist/components/decks/DecksComposition.js.map +1 -0
- package/dist/components/decks/SnapContainer.d.ts +6 -0
- package/dist/components/decks/SnapContainer.js +61 -0
- package/dist/components/decks/SnapContainer.js.map +1 -0
- package/dist/components/decks/styles.css +167 -0
- package/dist/components/decks/useDecksSnap.d.ts +8 -0
- package/dist/components/decks/useDecksSnap.js +101 -0
- package/dist/components/decks/useDecksSnap.js.map +1 -0
- package/dist/decks/install.d.ts +16 -0
- package/dist/decks/install.js +36 -0
- package/dist/decks/install.js.map +1 -0
- package/dist/decks/install.spec.d.ts +1 -0
- package/dist/decks/install.spec.js +65 -0
- package/dist/decks/install.spec.js.map +1 -0
- package/dist/decks/model.d.ts +48 -0
- package/dist/decks/model.js +36 -0
- package/dist/decks/model.js.map +1 -0
- package/dist/decks/model.spec.d.ts +1 -0
- package/dist/decks/model.spec.js +55 -0
- package/dist/decks/model.spec.js.map +1 -0
- package/dist/decks/schema.d.ts +59 -0
- package/dist/decks/schema.js +75 -0
- package/dist/decks/schema.js.map +1 -0
- package/dist/decks/timeline.d.ts +37 -0
- package/dist/decks/timeline.js +205 -0
- package/dist/decks/timeline.js.map +1 -0
- package/dist/decks/timeline.spec.d.ts +1 -0
- package/dist/decks/timeline.spec.js +75 -0
- package/dist/decks/timeline.spec.js.map +1 -0
- package/dist/exports/client.d.ts +1 -0
- package/dist/exports/client.js +3 -0
- package/dist/exports/client.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/package.json +135 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useSyncExternalStore } from 'react';
|
|
4
|
+
import './styles.css';
|
|
5
|
+
import { useDecksSnap } from './useDecksSnap.js';
|
|
6
|
+
const emptySubscribe = ()=>()=>{};
|
|
7
|
+
export const SnapContainer = ({ children })=>{
|
|
8
|
+
const isClient = useSyncExternalStore(emptySubscribe, ()=>true, ()=>false);
|
|
9
|
+
const { closeSnap, containerRef, isCursorActive, isSnapped } = useDecksSnap({
|
|
10
|
+
isClient
|
|
11
|
+
});
|
|
12
|
+
return /*#__PURE__*/ _jsxs(_Fragment, {
|
|
13
|
+
children: [
|
|
14
|
+
isSnapped && /*#__PURE__*/ _jsx("div", {
|
|
15
|
+
"aria-hidden": "true",
|
|
16
|
+
className: "decks-overlay",
|
|
17
|
+
onClick: closeSnap
|
|
18
|
+
}),
|
|
19
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
20
|
+
className: `decks-wrapper ${isSnapped ? 'decks-snapped' : ''}`,
|
|
21
|
+
ref: containerRef,
|
|
22
|
+
children: [
|
|
23
|
+
/*#__PURE__*/ _jsx("div", {
|
|
24
|
+
className: "decks-container",
|
|
25
|
+
children: children
|
|
26
|
+
}),
|
|
27
|
+
isSnapped && /*#__PURE__*/ _jsx("button", {
|
|
28
|
+
"aria-label": "Close fullscreen video",
|
|
29
|
+
className: `decks-close ${isCursorActive ? 'decks-close-visible' : ''}`,
|
|
30
|
+
onClick: closeSnap,
|
|
31
|
+
type: "button",
|
|
32
|
+
children: /*#__PURE__*/ _jsxs("svg", {
|
|
33
|
+
fill: "none",
|
|
34
|
+
height: "24",
|
|
35
|
+
stroke: "currentColor",
|
|
36
|
+
strokeWidth: "2",
|
|
37
|
+
viewBox: "0 0 24 24",
|
|
38
|
+
width: "24",
|
|
39
|
+
children: [
|
|
40
|
+
/*#__PURE__*/ _jsx("line", {
|
|
41
|
+
x1: "18",
|
|
42
|
+
x2: "6",
|
|
43
|
+
y1: "6",
|
|
44
|
+
y2: "18"
|
|
45
|
+
}),
|
|
46
|
+
/*#__PURE__*/ _jsx("line", {
|
|
47
|
+
x1: "6",
|
|
48
|
+
x2: "18",
|
|
49
|
+
y1: "6",
|
|
50
|
+
y2: "18"
|
|
51
|
+
})
|
|
52
|
+
]
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
]
|
|
56
|
+
})
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=SnapContainer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/decks/SnapContainer.tsx"],"sourcesContent":["'use client'\n\nimport type { ReactNode } from 'react'\n\nimport { useSyncExternalStore } from 'react'\n\nimport './styles.css'\nimport { useDecksSnap } from './useDecksSnap.js'\n\nconst emptySubscribe = () => () => {}\n\nexport interface SnapContainerProps {\n children: ReactNode\n}\n\nexport const SnapContainer = ({ children }: SnapContainerProps) => {\n const isClient = useSyncExternalStore(\n emptySubscribe,\n () => true,\n () => false,\n )\n const { closeSnap, containerRef, isCursorActive, isSnapped } = useDecksSnap({\n isClient,\n })\n\n return (\n <>\n {isSnapped && (\n <div aria-hidden=\"true\" className=\"decks-overlay\" onClick={closeSnap} />\n )}\n\n <div\n className={`decks-wrapper ${isSnapped ? 'decks-snapped' : ''}`}\n ref={containerRef}\n >\n <div className=\"decks-container\">\n {children}\n </div>\n\n {isSnapped && (\n <button\n aria-label=\"Close fullscreen video\"\n className={`decks-close ${\n isCursorActive ? 'decks-close-visible' : ''\n }`}\n onClick={closeSnap}\n type=\"button\"\n >\n <svg\n fill=\"none\"\n height=\"24\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"24\"\n >\n <line x1=\"18\" x2=\"6\" y1=\"6\" y2=\"18\" />\n <line x1=\"6\" x2=\"18\" y1=\"6\" y2=\"18\" />\n </svg>\n </button>\n )}\n </div>\n </>\n )\n}\n"],"names":["useSyncExternalStore","useDecksSnap","emptySubscribe","SnapContainer","children","isClient","closeSnap","containerRef","isCursorActive","isSnapped","div","aria-hidden","className","onClick","ref","button","aria-label","type","svg","fill","height","stroke","strokeWidth","viewBox","width","line","x1","x2","y1","y2"],"mappings":"AAAA;;AAIA,SAASA,oBAAoB,QAAQ,QAAO;AAE5C,OAAO,eAAc;AACrB,SAASC,YAAY,QAAQ,oBAAmB;AAEhD,MAAMC,iBAAiB,IAAM,KAAO;AAMpC,OAAO,MAAMC,gBAAgB,CAAC,EAAEC,QAAQ,EAAsB;IAC5D,MAAMC,WAAWL,qBACfE,gBACA,IAAM,MACN,IAAM;IAER,MAAM,EAAEI,SAAS,EAAEC,YAAY,EAAEC,cAAc,EAAEC,SAAS,EAAE,GAAGR,aAAa;QAC1EI;IACF;IAEA,qBACE;;YACGI,2BACC,KAACC;gBAAIC,eAAY;gBAAOC,WAAU;gBAAgBC,SAASP;;0BAG7D,MAACI;gBACCE,WAAW,CAAC,cAAc,EAAEH,YAAY,kBAAkB,IAAI;gBAC9DK,KAAKP;;kCAEL,KAACG;wBAAIE,WAAU;kCACZR;;oBAGFK,2BACC,KAACM;wBACCC,cAAW;wBACXJ,WAAW,CAAC,YAAY,EACtBJ,iBAAiB,wBAAwB,IACzC;wBACFK,SAASP;wBACTW,MAAK;kCAEL,cAAA,MAACC;4BACCC,MAAK;4BACLC,QAAO;4BACPC,QAAO;4BACPC,aAAY;4BACZC,SAAQ;4BACRC,OAAM;;8CAEN,KAACC;oCAAKC,IAAG;oCAAKC,IAAG;oCAAIC,IAAG;oCAAIC,IAAG;;8CAC/B,KAACJ;oCAAKC,IAAG;oCAAIC,IAAG;oCAAKC,IAAG;oCAAIC,IAAG;;;;;;;;;AAO7C,EAAC"}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
.decks-wrapper {
|
|
2
|
+
position: relative;
|
|
3
|
+
width: 100vw;
|
|
4
|
+
height: 100vh;
|
|
5
|
+
max-width: 100vw;
|
|
6
|
+
margin-left: calc(-50vw + 50%);
|
|
7
|
+
margin-right: calc(-50vw + 50%);
|
|
8
|
+
scroll-snap-align: center;
|
|
9
|
+
scroll-snap-stop: always;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.decks-snapped {
|
|
13
|
+
position: fixed;
|
|
14
|
+
top: 0;
|
|
15
|
+
left: 0;
|
|
16
|
+
width: 100vw;
|
|
17
|
+
height: 100vh;
|
|
18
|
+
margin: 0;
|
|
19
|
+
z-index: 9999;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.decks-container {
|
|
23
|
+
position: relative;
|
|
24
|
+
width: 100%;
|
|
25
|
+
height: 100%;
|
|
26
|
+
overflow: hidden;
|
|
27
|
+
background-color: #000;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.decks-container * {
|
|
31
|
+
max-width: unset;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.decks-overlay {
|
|
35
|
+
position: fixed;
|
|
36
|
+
top: 0;
|
|
37
|
+
left: 0;
|
|
38
|
+
width: 100vw;
|
|
39
|
+
height: 100vh;
|
|
40
|
+
background-color: rgba(0, 0, 0, 0.95);
|
|
41
|
+
z-index: 9998;
|
|
42
|
+
cursor: pointer;
|
|
43
|
+
animation: decks-fade-in 0.3s ease-out;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@keyframes decks-fade-in {
|
|
47
|
+
from {
|
|
48
|
+
opacity: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
to {
|
|
52
|
+
opacity: 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.decks-close {
|
|
57
|
+
position: absolute;
|
|
58
|
+
top: 1.5rem;
|
|
59
|
+
right: 1.5rem;
|
|
60
|
+
width: 48px;
|
|
61
|
+
height: 48px;
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
background-color: rgba(0, 0, 0, 0.6);
|
|
66
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
67
|
+
border-radius: 50%;
|
|
68
|
+
color: #fff;
|
|
69
|
+
cursor: pointer;
|
|
70
|
+
z-index: 10000;
|
|
71
|
+
backdrop-filter: blur(4px);
|
|
72
|
+
opacity: 0;
|
|
73
|
+
pointer-events: none;
|
|
74
|
+
transform: scale(0.9);
|
|
75
|
+
transition:
|
|
76
|
+
opacity 0.3s ease,
|
|
77
|
+
transform 0.3s ease,
|
|
78
|
+
background-color 0.2s ease,
|
|
79
|
+
border-color 0.2s ease;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.decks-close-visible {
|
|
83
|
+
opacity: 1;
|
|
84
|
+
pointer-events: auto;
|
|
85
|
+
transform: scale(1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.decks-close-visible:hover {
|
|
89
|
+
background-color: rgba(0, 0, 0, 0.8);
|
|
90
|
+
border-color: rgba(255, 255, 255, 0.6);
|
|
91
|
+
transform: scale(1.1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.decks-close:focus {
|
|
95
|
+
opacity: 1;
|
|
96
|
+
pointer-events: auto;
|
|
97
|
+
transform: scale(1);
|
|
98
|
+
outline: 2px solid #fff;
|
|
99
|
+
outline-offset: 2px;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.decks-loading {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: center;
|
|
106
|
+
width: 100%;
|
|
107
|
+
height: 100%;
|
|
108
|
+
background-color: #000;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.decks-spinner {
|
|
112
|
+
width: 48px;
|
|
113
|
+
height: 48px;
|
|
114
|
+
border: 4px solid rgba(255, 255, 255, 0.2);
|
|
115
|
+
border-top-color: #fff;
|
|
116
|
+
border-radius: 50%;
|
|
117
|
+
animation: decks-spin 1s linear infinite;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
@keyframes decks-spin {
|
|
121
|
+
to {
|
|
122
|
+
transform: rotate(360deg);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.decks-error {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
justify-content: center;
|
|
130
|
+
width: 100%;
|
|
131
|
+
height: 100%;
|
|
132
|
+
background-color: #1a1a1a;
|
|
133
|
+
color: #ff6b6b;
|
|
134
|
+
padding: 2rem;
|
|
135
|
+
text-align: center;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@media (max-width: 768px) {
|
|
139
|
+
.decks-wrapper:not(.decks-snapped) {
|
|
140
|
+
height: 60vh;
|
|
141
|
+
min-height: 400px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.decks-close {
|
|
145
|
+
top: 1rem;
|
|
146
|
+
right: 1rem;
|
|
147
|
+
width: 40px;
|
|
148
|
+
height: 40px;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@media (max-width: 480px) {
|
|
153
|
+
.decks-wrapper:not(.decks-snapped) {
|
|
154
|
+
height: 50vh;
|
|
155
|
+
min-height: 300px;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.decks-close {
|
|
159
|
+
width: 36px;
|
|
160
|
+
height: 36px;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.decks-close svg {
|
|
164
|
+
width: 18px;
|
|
165
|
+
height: 18px;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
const CURSOR_HIDE_DELAY = 2000;
|
|
4
|
+
export const useDecksSnap = ({ isClient })=>{
|
|
5
|
+
const [isSnapped, setIsSnapped] = useState(false);
|
|
6
|
+
const [isCursorActive, setIsCursorActive] = useState(false);
|
|
7
|
+
const containerRef = useRef(null);
|
|
8
|
+
const cursorTimeoutRef = useRef(null);
|
|
9
|
+
useEffect(()=>{
|
|
10
|
+
if (!isClient || !containerRef.current) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const observer = new IntersectionObserver((entries)=>{
|
|
14
|
+
entries.forEach((entry)=>{
|
|
15
|
+
if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {
|
|
16
|
+
setIsSnapped(true);
|
|
17
|
+
containerRef.current?.scrollIntoView({
|
|
18
|
+
behavior: 'smooth',
|
|
19
|
+
block: 'center'
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}, {
|
|
24
|
+
rootMargin: '-10% 0px -10% 0px',
|
|
25
|
+
threshold: [
|
|
26
|
+
0.5
|
|
27
|
+
]
|
|
28
|
+
});
|
|
29
|
+
observer.observe(containerRef.current);
|
|
30
|
+
return ()=>{
|
|
31
|
+
observer.disconnect();
|
|
32
|
+
};
|
|
33
|
+
}, [
|
|
34
|
+
isClient
|
|
35
|
+
]);
|
|
36
|
+
useEffect(()=>{
|
|
37
|
+
if (!isSnapped) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const handleKeyDown = (event)=>{
|
|
41
|
+
if (event.key === 'Escape') {
|
|
42
|
+
setIsSnapped(false);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
const handleScroll = ()=>{
|
|
46
|
+
if (!containerRef.current) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
50
|
+
const viewportHeight = window.innerHeight;
|
|
51
|
+
if (rect.bottom < viewportHeight * 0.2 || rect.top > viewportHeight * 0.8) {
|
|
52
|
+
setIsSnapped(false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const handleMouseMove = ()=>{
|
|
56
|
+
setIsCursorActive(true);
|
|
57
|
+
if (cursorTimeoutRef.current) {
|
|
58
|
+
clearTimeout(cursorTimeoutRef.current);
|
|
59
|
+
}
|
|
60
|
+
cursorTimeoutRef.current = setTimeout(()=>{
|
|
61
|
+
setIsCursorActive(false);
|
|
62
|
+
}, CURSOR_HIDE_DELAY);
|
|
63
|
+
};
|
|
64
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
65
|
+
window.addEventListener('scroll', handleScroll, {
|
|
66
|
+
passive: true
|
|
67
|
+
});
|
|
68
|
+
document.addEventListener('mousemove', handleMouseMove);
|
|
69
|
+
document.body.style.overflow = 'hidden';
|
|
70
|
+
const initialShowTimeout = setTimeout(()=>{
|
|
71
|
+
setIsCursorActive(true);
|
|
72
|
+
cursorTimeoutRef.current = setTimeout(()=>{
|
|
73
|
+
setIsCursorActive(false);
|
|
74
|
+
}, CURSOR_HIDE_DELAY);
|
|
75
|
+
}, 0);
|
|
76
|
+
return ()=>{
|
|
77
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
78
|
+
window.removeEventListener('scroll', handleScroll);
|
|
79
|
+
document.removeEventListener('mousemove', handleMouseMove);
|
|
80
|
+
document.body.style.overflow = '';
|
|
81
|
+
clearTimeout(initialShowTimeout);
|
|
82
|
+
if (cursorTimeoutRef.current) {
|
|
83
|
+
clearTimeout(cursorTimeoutRef.current);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
}, [
|
|
87
|
+
isSnapped
|
|
88
|
+
]);
|
|
89
|
+
const closeSnap = useCallback(()=>{
|
|
90
|
+
setIsSnapped(false);
|
|
91
|
+
setIsCursorActive(false);
|
|
92
|
+
}, []);
|
|
93
|
+
return {
|
|
94
|
+
closeSnap,
|
|
95
|
+
containerRef,
|
|
96
|
+
isCursorActive,
|
|
97
|
+
isSnapped
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
//# sourceMappingURL=useDecksSnap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/decks/useDecksSnap.ts"],"sourcesContent":["'use client'\n\nimport { useCallback, useEffect, useRef, useState } from 'react'\n\nconst CURSOR_HIDE_DELAY = 2000\n\nexport const useDecksSnap = ({ isClient }: { isClient: boolean }) => {\n const [isSnapped, setIsSnapped] = useState(false)\n const [isCursorActive, setIsCursorActive] = useState(false)\n const containerRef = useRef<HTMLDivElement>(null)\n const cursorTimeoutRef = useRef<null | ReturnType<typeof setTimeout>>(null)\n\n useEffect(() => {\n if (!isClient || !containerRef.current) {\n return\n }\n\n const observer = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting && entry.intersectionRatio >= 0.5) {\n setIsSnapped(true)\n containerRef.current?.scrollIntoView({\n behavior: 'smooth',\n block: 'center',\n })\n }\n })\n },\n {\n rootMargin: '-10% 0px -10% 0px',\n threshold: [0.5],\n },\n )\n\n observer.observe(containerRef.current)\n\n return () => {\n observer.disconnect()\n }\n }, [isClient])\n\n useEffect(() => {\n if (!isSnapped) {\n return\n }\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsSnapped(false)\n }\n }\n\n const handleScroll = () => {\n if (!containerRef.current) {\n return\n }\n\n const rect = containerRef.current.getBoundingClientRect()\n const viewportHeight = window.innerHeight\n\n if (rect.bottom < viewportHeight * 0.2 || rect.top > viewportHeight * 0.8) {\n setIsSnapped(false)\n }\n }\n\n const handleMouseMove = () => {\n setIsCursorActive(true)\n\n if (cursorTimeoutRef.current) {\n clearTimeout(cursorTimeoutRef.current)\n }\n\n cursorTimeoutRef.current = setTimeout(() => {\n setIsCursorActive(false)\n }, CURSOR_HIDE_DELAY)\n }\n\n document.addEventListener('keydown', handleKeyDown)\n window.addEventListener('scroll', handleScroll, { passive: true })\n document.addEventListener('mousemove', handleMouseMove)\n document.body.style.overflow = 'hidden'\n\n const initialShowTimeout = setTimeout(() => {\n setIsCursorActive(true)\n cursorTimeoutRef.current = setTimeout(() => {\n setIsCursorActive(false)\n }, CURSOR_HIDE_DELAY)\n }, 0)\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown)\n window.removeEventListener('scroll', handleScroll)\n document.removeEventListener('mousemove', handleMouseMove)\n document.body.style.overflow = ''\n clearTimeout(initialShowTimeout)\n if (cursorTimeoutRef.current) {\n clearTimeout(cursorTimeoutRef.current)\n }\n }\n }, [isSnapped])\n\n const closeSnap = useCallback(() => {\n setIsSnapped(false)\n setIsCursorActive(false)\n }, [])\n\n return {\n closeSnap,\n containerRef,\n isCursorActive,\n isSnapped,\n }\n}\n"],"names":["useCallback","useEffect","useRef","useState","CURSOR_HIDE_DELAY","useDecksSnap","isClient","isSnapped","setIsSnapped","isCursorActive","setIsCursorActive","containerRef","cursorTimeoutRef","current","observer","IntersectionObserver","entries","forEach","entry","isIntersecting","intersectionRatio","scrollIntoView","behavior","block","rootMargin","threshold","observe","disconnect","handleKeyDown","event","key","handleScroll","rect","getBoundingClientRect","viewportHeight","window","innerHeight","bottom","top","handleMouseMove","clearTimeout","setTimeout","document","addEventListener","passive","body","style","overflow","initialShowTimeout","removeEventListener","closeSnap"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,SAAS,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAO;AAEhE,MAAMC,oBAAoB;AAE1B,OAAO,MAAMC,eAAe,CAAC,EAAEC,QAAQ,EAAyB;IAC9D,MAAM,CAACC,WAAWC,aAAa,GAAGL,SAAS;IAC3C,MAAM,CAACM,gBAAgBC,kBAAkB,GAAGP,SAAS;IACrD,MAAMQ,eAAeT,OAAuB;IAC5C,MAAMU,mBAAmBV,OAA6C;IAEtED,UAAU;QACR,IAAI,CAACK,YAAY,CAACK,aAAaE,OAAO,EAAE;YACtC;QACF;QAEA,MAAMC,WAAW,IAAIC,qBACnB,CAACC;YACCA,QAAQC,OAAO,CAAC,CAACC;gBACf,IAAIA,MAAMC,cAAc,IAAID,MAAME,iBAAiB,IAAI,KAAK;oBAC1DZ,aAAa;oBACbG,aAAaE,OAAO,EAAEQ,eAAe;wBACnCC,UAAU;wBACVC,OAAO;oBACT;gBACF;YACF;QACF,GACA;YACEC,YAAY;YACZC,WAAW;gBAAC;aAAI;QAClB;QAGFX,SAASY,OAAO,CAACf,aAAaE,OAAO;QAErC,OAAO;YACLC,SAASa,UAAU;QACrB;IACF,GAAG;QAACrB;KAAS;IAEbL,UAAU;QACR,IAAI,CAACM,WAAW;YACd;QACF;QAEA,MAAMqB,gBAAgB,CAACC;YACrB,IAAIA,MAAMC,GAAG,KAAK,UAAU;gBAC1BtB,aAAa;YACf;QACF;QAEA,MAAMuB,eAAe;YACnB,IAAI,CAACpB,aAAaE,OAAO,EAAE;gBACzB;YACF;YAEA,MAAMmB,OAAOrB,aAAaE,OAAO,CAACoB,qBAAqB;YACvD,MAAMC,iBAAiBC,OAAOC,WAAW;YAEzC,IAAIJ,KAAKK,MAAM,GAAGH,iBAAiB,OAAOF,KAAKM,GAAG,GAAGJ,iBAAiB,KAAK;gBACzE1B,aAAa;YACf;QACF;QAEA,MAAM+B,kBAAkB;YACtB7B,kBAAkB;YAElB,IAAIE,iBAAiBC,OAAO,EAAE;gBAC5B2B,aAAa5B,iBAAiBC,OAAO;YACvC;YAEAD,iBAAiBC,OAAO,GAAG4B,WAAW;gBACpC/B,kBAAkB;YACpB,GAAGN;QACL;QAEAsC,SAASC,gBAAgB,CAAC,WAAWf;QACrCO,OAAOQ,gBAAgB,CAAC,UAAUZ,cAAc;YAAEa,SAAS;QAAK;QAChEF,SAASC,gBAAgB,CAAC,aAAaJ;QACvCG,SAASG,IAAI,CAACC,KAAK,CAACC,QAAQ,GAAG;QAE/B,MAAMC,qBAAqBP,WAAW;YACpC/B,kBAAkB;YAClBE,iBAAiBC,OAAO,GAAG4B,WAAW;gBACpC/B,kBAAkB;YACpB,GAAGN;QACL,GAAG;QAEH,OAAO;YACLsC,SAASO,mBAAmB,CAAC,WAAWrB;YACxCO,OAAOc,mBAAmB,CAAC,UAAUlB;YACrCW,SAASO,mBAAmB,CAAC,aAAaV;YAC1CG,SAASG,IAAI,CAACC,KAAK,CAACC,QAAQ,GAAG;YAC/BP,aAAaQ;YACb,IAAIpC,iBAAiBC,OAAO,EAAE;gBAC5B2B,aAAa5B,iBAAiBC,OAAO;YACvC;QACF;IACF,GAAG;QAACN;KAAU;IAEd,MAAM2C,YAAYlD,YAAY;QAC5BQ,aAAa;QACbE,kBAAkB;IACpB,GAAG,EAAE;IAEL,OAAO;QACLwC;QACAvC;QACAF;QACAF;IACF;AACF,EAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { CollectionSlug, Config } from 'payload';
|
|
2
|
+
export type PayloadDecksConfig = {
|
|
3
|
+
/**
|
|
4
|
+
* List of collections to add a decks blocks field to.
|
|
5
|
+
*/
|
|
6
|
+
collections?: Partial<Record<CollectionSlug, true>>;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Name for the blocks field added to configured collections.
|
|
10
|
+
*
|
|
11
|
+
* @default 'decks'
|
|
12
|
+
*/
|
|
13
|
+
fieldName?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const defaultDecksFieldName = "decks";
|
|
16
|
+
export declare const installDecksField: (config: Config, pluginOptions?: PayloadDecksConfig) => Config;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DecksBlock } from '../blocks/decks/config.js';
|
|
2
|
+
export const defaultDecksFieldName = 'decks';
|
|
3
|
+
export const installDecksField = (config, pluginOptions = {})=>{
|
|
4
|
+
config.collections = config.collections || [];
|
|
5
|
+
if (!pluginOptions.collections) {
|
|
6
|
+
return config;
|
|
7
|
+
}
|
|
8
|
+
const fieldName = pluginOptions.fieldName || defaultDecksFieldName;
|
|
9
|
+
for(const collectionSlug in pluginOptions.collections){
|
|
10
|
+
const collection = config.collections.find((candidate)=>candidate.slug === collectionSlug);
|
|
11
|
+
if (!collection) {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
collection.fields = collection.fields || [];
|
|
15
|
+
const fieldAlreadyInstalled = collection.fields.some((field)=>{
|
|
16
|
+
return 'name' in field && field.name === fieldName;
|
|
17
|
+
});
|
|
18
|
+
if (fieldAlreadyInstalled) {
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
collection.fields.push({
|
|
22
|
+
name: fieldName,
|
|
23
|
+
type: 'blocks',
|
|
24
|
+
admin: {
|
|
25
|
+
description: 'Decks rendered with Remotion.'
|
|
26
|
+
},
|
|
27
|
+
blocks: [
|
|
28
|
+
DecksBlock
|
|
29
|
+
],
|
|
30
|
+
label: 'Decks'
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
return config;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/decks/install.ts"],"sourcesContent":["import type { CollectionSlug, Config } from 'payload'\n\nimport { DecksBlock } from '../blocks/decks/config.js'\n\nexport type PayloadDecksConfig = {\n /**\n * List of collections to add a decks blocks field to.\n */\n collections?: Partial<Record<CollectionSlug, true>>\n disabled?: boolean\n /**\n * Name for the blocks field added to configured collections.\n *\n * @default 'decks'\n */\n fieldName?: string\n}\n\nexport const defaultDecksFieldName = 'decks'\n\nexport const installDecksField = (\n config: Config,\n pluginOptions: PayloadDecksConfig = {},\n): Config => {\n config.collections = config.collections || []\n\n if (!pluginOptions.collections) {\n return config\n }\n\n const fieldName = pluginOptions.fieldName || defaultDecksFieldName\n\n for (const collectionSlug in pluginOptions.collections) {\n const collection = config.collections.find(\n (candidate) => candidate.slug === collectionSlug,\n )\n\n if (!collection) {\n continue\n }\n\n collection.fields = collection.fields || []\n\n const fieldAlreadyInstalled = collection.fields.some((field) => {\n return 'name' in field && field.name === fieldName\n })\n\n if (fieldAlreadyInstalled) {\n continue\n }\n\n collection.fields.push({\n name: fieldName,\n type: 'blocks',\n admin: {\n description: 'Decks rendered with Remotion.',\n },\n blocks: [DecksBlock],\n label: 'Decks',\n })\n }\n\n return config\n}\n"],"names":["DecksBlock","defaultDecksFieldName","installDecksField","config","pluginOptions","collections","fieldName","collectionSlug","collection","find","candidate","slug","fields","fieldAlreadyInstalled","some","field","name","push","type","admin","description","blocks","label"],"mappings":"AAEA,SAASA,UAAU,QAAQ,4BAA2B;AAgBtD,OAAO,MAAMC,wBAAwB,QAAO;AAE5C,OAAO,MAAMC,oBAAoB,CAC/BC,QACAC,gBAAoC,CAAC,CAAC;IAEtCD,OAAOE,WAAW,GAAGF,OAAOE,WAAW,IAAI,EAAE;IAE7C,IAAI,CAACD,cAAcC,WAAW,EAAE;QAC9B,OAAOF;IACT;IAEA,MAAMG,YAAYF,cAAcE,SAAS,IAAIL;IAE7C,IAAK,MAAMM,kBAAkBH,cAAcC,WAAW,CAAE;QACtD,MAAMG,aAAaL,OAAOE,WAAW,CAACI,IAAI,CACxC,CAACC,YAAcA,UAAUC,IAAI,KAAKJ;QAGpC,IAAI,CAACC,YAAY;YACf;QACF;QAEAA,WAAWI,MAAM,GAAGJ,WAAWI,MAAM,IAAI,EAAE;QAE3C,MAAMC,wBAAwBL,WAAWI,MAAM,CAACE,IAAI,CAAC,CAACC;YACpD,OAAO,UAAUA,SAASA,MAAMC,IAAI,KAAKV;QAC3C;QAEA,IAAIO,uBAAuB;YACzB;QACF;QAEAL,WAAWI,MAAM,CAACK,IAAI,CAAC;YACrBD,MAAMV;YACNY,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,QAAQ;gBAACrB;aAAW;YACpBsB,OAAO;QACT;IACF;IAEA,OAAOnB;AACT,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { installDecksField } from './install.js';
|
|
3
|
+
describe('installDecksField', ()=>{
|
|
4
|
+
test('adds a decks blocks field to configured collections', ()=>{
|
|
5
|
+
const config = installDecksField({
|
|
6
|
+
collections: [
|
|
7
|
+
{
|
|
8
|
+
slug: 'pages',
|
|
9
|
+
fields: []
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}, {
|
|
13
|
+
collections: {
|
|
14
|
+
pages: true
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
expect(config.collections?.[0]?.fields).toMatchObject([
|
|
18
|
+
{
|
|
19
|
+
name: 'decks',
|
|
20
|
+
type: 'blocks',
|
|
21
|
+
label: 'Decks'
|
|
22
|
+
}
|
|
23
|
+
]);
|
|
24
|
+
});
|
|
25
|
+
test('does not add duplicate fields when plugin installation runs twice', ()=>{
|
|
26
|
+
const config = {
|
|
27
|
+
collections: [
|
|
28
|
+
{
|
|
29
|
+
slug: 'pages',
|
|
30
|
+
fields: []
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
};
|
|
34
|
+
installDecksField(config, {
|
|
35
|
+
collections: {
|
|
36
|
+
pages: true
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
installDecksField(config, {
|
|
40
|
+
collections: {
|
|
41
|
+
pages: true
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
expect(config.collections?.[0]?.fields).toHaveLength(1);
|
|
45
|
+
});
|
|
46
|
+
test('supports a custom field name', ()=>{
|
|
47
|
+
const config = installDecksField({
|
|
48
|
+
collections: [
|
|
49
|
+
{
|
|
50
|
+
slug: 'pages',
|
|
51
|
+
fields: []
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
}, {
|
|
55
|
+
collections: {
|
|
56
|
+
pages: true
|
|
57
|
+
},
|
|
58
|
+
fieldName: 'heroDecks'
|
|
59
|
+
});
|
|
60
|
+
const field = config.collections?.[0]?.fields[0];
|
|
61
|
+
expect(field?.name).toBe('heroDecks');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
//# sourceMappingURL=install.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/decks/install.spec.ts"],"sourcesContent":["import type { Config } from 'payload'\n\nimport { describe, expect, test } from 'vitest'\n\nimport { installDecksField } from './install.js'\n\ndescribe('installDecksField', () => {\n test('adds a decks blocks field to configured collections', () => {\n const config = installDecksField(\n {\n collections: [\n {\n slug: 'pages',\n fields: [],\n },\n ],\n } as unknown as Config,\n {\n collections: {\n pages: true,\n },\n },\n )\n\n expect(config.collections?.[0]?.fields).toMatchObject([\n {\n name: 'decks',\n type: 'blocks',\n label: 'Decks',\n },\n ])\n })\n\n test('does not add duplicate fields when plugin installation runs twice', () => {\n const config = {\n collections: [\n {\n slug: 'pages',\n fields: [],\n },\n ],\n } as unknown as Config\n\n installDecksField(config, {\n collections: {\n pages: true,\n },\n })\n installDecksField(config, {\n collections: {\n pages: true,\n },\n })\n\n expect(config.collections?.[0]?.fields).toHaveLength(1)\n })\n\n test('supports a custom field name', () => {\n const config = installDecksField(\n {\n collections: [\n {\n slug: 'pages',\n fields: [],\n },\n ],\n } as unknown as Config,\n {\n collections: {\n pages: true,\n },\n fieldName: 'heroDecks',\n },\n )\n\n const field = config.collections?.[0]?.fields[0] as { name?: string } | undefined\n\n expect(field?.name).toBe('heroDecks')\n })\n})\n"],"names":["describe","expect","test","installDecksField","config","collections","slug","fields","pages","toMatchObject","name","type","label","toHaveLength","fieldName","field","toBe"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,IAAI,QAAQ,SAAQ;AAE/C,SAASC,iBAAiB,QAAQ,eAAc;AAEhDH,SAAS,qBAAqB;IAC5BE,KAAK,uDAAuD;QAC1D,MAAME,SAASD,kBACb;YACEE,aAAa;gBACX;oBACEC,MAAM;oBACNC,QAAQ,EAAE;gBACZ;aACD;QACH,GACA;YACEF,aAAa;gBACXG,OAAO;YACT;QACF;QAGFP,OAAOG,OAAOC,WAAW,EAAE,CAAC,EAAE,EAAEE,QAAQE,aAAa,CAAC;YACpD;gBACEC,MAAM;gBACNC,MAAM;gBACNC,OAAO;YACT;SACD;IACH;IAEAV,KAAK,qEAAqE;QACxE,MAAME,SAAS;YACbC,aAAa;gBACX;oBACEC,MAAM;oBACNC,QAAQ,EAAE;gBACZ;aACD;QACH;QAEAJ,kBAAkBC,QAAQ;YACxBC,aAAa;gBACXG,OAAO;YACT;QACF;QACAL,kBAAkBC,QAAQ;YACxBC,aAAa;gBACXG,OAAO;YACT;QACF;QAEAP,OAAOG,OAAOC,WAAW,EAAE,CAAC,EAAE,EAAEE,QAAQM,YAAY,CAAC;IACvD;IAEAX,KAAK,gCAAgC;QACnC,MAAME,SAASD,kBACb;YACEE,aAAa;gBACX;oBACEC,MAAM;oBACNC,QAAQ,EAAE;gBACZ;aACD;QACH,GACA;YACEF,aAAa;gBACXG,OAAO;YACT;YACAM,WAAW;QACb;QAGF,MAAMC,QAAQX,OAAOC,WAAW,EAAE,CAAC,EAAE,EAAEE,MAAM,CAAC,EAAE;QAEhDN,OAAOc,OAAOL,MAAMM,IAAI,CAAC;IAC3B;AACF"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export { DECKS_DEFAULTS } from './schema.js';
|
|
2
|
+
export type DecksMediaImage = {
|
|
3
|
+
alt?: null | string;
|
|
4
|
+
url?: null | string;
|
|
5
|
+
};
|
|
6
|
+
export type DecksUploadValue = DecksMediaImage | null | number | string | undefined;
|
|
7
|
+
export interface DecksSlide {
|
|
8
|
+
animationType?: null | string;
|
|
9
|
+
headline?: null | string;
|
|
10
|
+
image?: DecksUploadValue;
|
|
11
|
+
imageZoom?: boolean | null;
|
|
12
|
+
subtext?: null | string;
|
|
13
|
+
textColor?: null | string;
|
|
14
|
+
textPosition?: null | string;
|
|
15
|
+
}
|
|
16
|
+
export interface DecksBlockProps {
|
|
17
|
+
autoPlay?: boolean | null;
|
|
18
|
+
backgroundColor?: null | string;
|
|
19
|
+
durationPerSlide?: null | number;
|
|
20
|
+
fps?: null | number;
|
|
21
|
+
loop?: boolean | null;
|
|
22
|
+
showControls?: boolean | null;
|
|
23
|
+
slides?: DecksSlide[] | null;
|
|
24
|
+
transitionDuration?: null | number;
|
|
25
|
+
}
|
|
26
|
+
export interface NormalizedDecksSlide {
|
|
27
|
+
animationType: string;
|
|
28
|
+
headline?: string;
|
|
29
|
+
image?: {
|
|
30
|
+
alt?: string;
|
|
31
|
+
url?: string;
|
|
32
|
+
};
|
|
33
|
+
imageZoom: boolean;
|
|
34
|
+
subtext?: string;
|
|
35
|
+
textColor: string;
|
|
36
|
+
textPosition: string;
|
|
37
|
+
}
|
|
38
|
+
export interface NormalizedDecksBlock {
|
|
39
|
+
autoPlay: boolean;
|
|
40
|
+
backgroundColor: string;
|
|
41
|
+
durationPerSlide: number;
|
|
42
|
+
fps: number;
|
|
43
|
+
loop: boolean;
|
|
44
|
+
showControls: boolean;
|
|
45
|
+
slides: NormalizedDecksSlide[];
|
|
46
|
+
transitionDuration: number;
|
|
47
|
+
}
|
|
48
|
+
export declare const normalizeDecksBlock: ({ autoPlay, backgroundColor, durationPerSlide, fps, loop, showControls, slides, transitionDuration, }: DecksBlockProps) => NormalizedDecksBlock;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { DECKS_DEFAULTS } from './schema.js';
|
|
2
|
+
export { DECKS_DEFAULTS } from './schema.js';
|
|
3
|
+
const isMediaImage = (image)=>{
|
|
4
|
+
return Boolean(image && typeof image === 'object');
|
|
5
|
+
};
|
|
6
|
+
const normalizeImage = (image)=>{
|
|
7
|
+
if (!isMediaImage(image)) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
return {
|
|
11
|
+
alt: image.alt || undefined,
|
|
12
|
+
url: image.url || undefined
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
export const normalizeDecksBlock = ({ autoPlay, backgroundColor, durationPerSlide, fps, loop, showControls, slides, transitionDuration })=>{
|
|
16
|
+
return {
|
|
17
|
+
autoPlay: autoPlay ?? DECKS_DEFAULTS.autoPlay,
|
|
18
|
+
backgroundColor: backgroundColor || DECKS_DEFAULTS.backgroundColor,
|
|
19
|
+
durationPerSlide: durationPerSlide ?? DECKS_DEFAULTS.durationPerSlide,
|
|
20
|
+
fps: fps ?? DECKS_DEFAULTS.fps,
|
|
21
|
+
loop: loop ?? DECKS_DEFAULTS.loop,
|
|
22
|
+
showControls: showControls ?? DECKS_DEFAULTS.showControls,
|
|
23
|
+
slides: (slides || []).map((slide)=>({
|
|
24
|
+
animationType: slide.animationType || DECKS_DEFAULTS.animationType,
|
|
25
|
+
headline: slide.headline || undefined,
|
|
26
|
+
image: normalizeImage(slide.image),
|
|
27
|
+
imageZoom: slide.imageZoom ?? DECKS_DEFAULTS.imageZoom,
|
|
28
|
+
subtext: slide.subtext || undefined,
|
|
29
|
+
textColor: slide.textColor || DECKS_DEFAULTS.textColor,
|
|
30
|
+
textPosition: slide.textPosition || DECKS_DEFAULTS.textPosition
|
|
31
|
+
})),
|
|
32
|
+
transitionDuration: transitionDuration ?? DECKS_DEFAULTS.transitionDuration
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/decks/model.ts"],"sourcesContent":["import { DECKS_DEFAULTS } from './schema.js'\n\nexport { DECKS_DEFAULTS } from './schema.js'\n\nexport type DecksMediaImage = {\n alt?: null | string\n url?: null | string\n}\n\nexport type DecksUploadValue =\n | DecksMediaImage\n | null\n | number\n | string\n | undefined\n\nexport interface DecksSlide {\n animationType?: null | string\n headline?: null | string\n image?: DecksUploadValue\n imageZoom?: boolean | null\n subtext?: null | string\n textColor?: null | string\n textPosition?: null | string\n}\n\nexport interface DecksBlockProps {\n autoPlay?: boolean | null\n backgroundColor?: null | string\n durationPerSlide?: null | number\n fps?: null | number\n loop?: boolean | null\n showControls?: boolean | null\n slides?: DecksSlide[] | null\n transitionDuration?: null | number\n}\n\nexport interface NormalizedDecksSlide {\n animationType: string\n headline?: string\n image?: {\n alt?: string\n url?: string\n }\n imageZoom: boolean\n subtext?: string\n textColor: string\n textPosition: string\n}\n\nexport interface NormalizedDecksBlock {\n autoPlay: boolean\n backgroundColor: string\n durationPerSlide: number\n fps: number\n loop: boolean\n showControls: boolean\n slides: NormalizedDecksSlide[]\n transitionDuration: number\n}\n\nconst isMediaImage = (image: DecksUploadValue): image is DecksMediaImage => {\n return Boolean(image && typeof image === 'object')\n}\n\nconst normalizeImage = (\n image: DecksUploadValue,\n): NormalizedDecksSlide['image'] => {\n if (!isMediaImage(image)) {\n return undefined\n }\n\n return {\n alt: image.alt || undefined,\n url: image.url || undefined,\n }\n}\n\nexport const normalizeDecksBlock = ({\n autoPlay,\n backgroundColor,\n durationPerSlide,\n fps,\n loop,\n showControls,\n slides,\n transitionDuration,\n}: DecksBlockProps): NormalizedDecksBlock => {\n return {\n autoPlay: autoPlay ?? DECKS_DEFAULTS.autoPlay,\n backgroundColor: backgroundColor || DECKS_DEFAULTS.backgroundColor,\n durationPerSlide: durationPerSlide ?? DECKS_DEFAULTS.durationPerSlide,\n fps: fps ?? DECKS_DEFAULTS.fps,\n loop: loop ?? DECKS_DEFAULTS.loop,\n showControls: showControls ?? DECKS_DEFAULTS.showControls,\n slides: (slides || []).map((slide) => ({\n animationType: slide.animationType || DECKS_DEFAULTS.animationType,\n headline: slide.headline || undefined,\n image: normalizeImage(slide.image),\n imageZoom: slide.imageZoom ?? DECKS_DEFAULTS.imageZoom,\n subtext: slide.subtext || undefined,\n textColor: slide.textColor || DECKS_DEFAULTS.textColor,\n textPosition: slide.textPosition || DECKS_DEFAULTS.textPosition,\n })),\n transitionDuration: transitionDuration ?? DECKS_DEFAULTS.transitionDuration,\n }\n}\n"],"names":["DECKS_DEFAULTS","isMediaImage","image","Boolean","normalizeImage","undefined","alt","url","normalizeDecksBlock","autoPlay","backgroundColor","durationPerSlide","fps","loop","showControls","slides","transitionDuration","map","slide","animationType","headline","imageZoom","subtext","textColor","textPosition"],"mappings":"AAAA,SAASA,cAAc,QAAQ,cAAa;AAE5C,SAASA,cAAc,QAAQ,cAAa;AA2D5C,MAAMC,eAAe,CAACC;IACpB,OAAOC,QAAQD,SAAS,OAAOA,UAAU;AAC3C;AAEA,MAAME,iBAAiB,CACrBF;IAEA,IAAI,CAACD,aAAaC,QAAQ;QACxB,OAAOG;IACT;IAEA,OAAO;QACLC,KAAKJ,MAAMI,GAAG,IAAID;QAClBE,KAAKL,MAAMK,GAAG,IAAIF;IACpB;AACF;AAEA,OAAO,MAAMG,sBAAsB,CAAC,EAClCC,QAAQ,EACRC,eAAe,EACfC,gBAAgB,EAChBC,GAAG,EACHC,IAAI,EACJC,YAAY,EACZC,MAAM,EACNC,kBAAkB,EACF;IAChB,OAAO;QACLP,UAAUA,YAAYT,eAAeS,QAAQ;QAC7CC,iBAAiBA,mBAAmBV,eAAeU,eAAe;QAClEC,kBAAkBA,oBAAoBX,eAAeW,gBAAgB;QACrEC,KAAKA,OAAOZ,eAAeY,GAAG;QAC9BC,MAAMA,QAAQb,eAAea,IAAI;QACjCC,cAAcA,gBAAgBd,eAAec,YAAY;QACzDC,QAAQ,AAACA,CAAAA,UAAU,EAAE,AAAD,EAAGE,GAAG,CAAC,CAACC,QAAW,CAAA;gBACrCC,eAAeD,MAAMC,aAAa,IAAInB,eAAemB,aAAa;gBAClEC,UAAUF,MAAME,QAAQ,IAAIf;gBAC5BH,OAAOE,eAAec,MAAMhB,KAAK;gBACjCmB,WAAWH,MAAMG,SAAS,IAAIrB,eAAeqB,SAAS;gBACtDC,SAASJ,MAAMI,OAAO,IAAIjB;gBAC1BkB,WAAWL,MAAMK,SAAS,IAAIvB,eAAeuB,SAAS;gBACtDC,cAAcN,MAAMM,YAAY,IAAIxB,eAAewB,YAAY;YACjE,CAAA;QACAR,oBAAoBA,sBAAsBhB,eAAegB,kBAAkB;IAC7E;AACF,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, test } from 'vitest';
|
|
2
|
+
import { normalizeDecksBlock } from './model.js';
|
|
3
|
+
describe('normalizeDecksBlock', ()=>{
|
|
4
|
+
test('fills deck and slide defaults for the renderer interface', ()=>{
|
|
5
|
+
const deck = normalizeDecksBlock({
|
|
6
|
+
slides: [
|
|
7
|
+
{
|
|
8
|
+
headline: 'Opening'
|
|
9
|
+
}
|
|
10
|
+
]
|
|
11
|
+
});
|
|
12
|
+
expect(deck).toEqual({
|
|
13
|
+
autoPlay: true,
|
|
14
|
+
backgroundColor: '#000000',
|
|
15
|
+
durationPerSlide: 3,
|
|
16
|
+
fps: 30,
|
|
17
|
+
loop: true,
|
|
18
|
+
showControls: false,
|
|
19
|
+
slides: [
|
|
20
|
+
{
|
|
21
|
+
animationType: 'fadeIn',
|
|
22
|
+
headline: 'Opening',
|
|
23
|
+
image: undefined,
|
|
24
|
+
imageZoom: true,
|
|
25
|
+
subtext: undefined,
|
|
26
|
+
textColor: '#ffffff',
|
|
27
|
+
textPosition: 'center'
|
|
28
|
+
}
|
|
29
|
+
],
|
|
30
|
+
transitionDuration: 15
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
test('normalizes populated Payload upload images and ignores upload IDs', ()=>{
|
|
34
|
+
const deck = normalizeDecksBlock({
|
|
35
|
+
slides: [
|
|
36
|
+
{
|
|
37
|
+
image: {
|
|
38
|
+
alt: 'Poster',
|
|
39
|
+
url: '/poster.jpg'
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
image: 'media-id'
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
});
|
|
47
|
+
expect(deck.slides[0]?.image).toEqual({
|
|
48
|
+
alt: 'Poster',
|
|
49
|
+
url: '/poster.jpg'
|
|
50
|
+
});
|
|
51
|
+
expect(deck.slides[1]?.image).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
//# sourceMappingURL=model.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/decks/model.spec.ts"],"sourcesContent":["import { describe, expect, test } from 'vitest'\n\nimport { normalizeDecksBlock } from './model.js'\n\ndescribe('normalizeDecksBlock', () => {\n test('fills deck and slide defaults for the renderer interface', () => {\n const deck = normalizeDecksBlock({\n slides: [\n {\n headline: 'Opening',\n },\n ],\n })\n\n expect(deck).toEqual({\n autoPlay: true,\n backgroundColor: '#000000',\n durationPerSlide: 3,\n fps: 30,\n loop: true,\n showControls: false,\n slides: [\n {\n animationType: 'fadeIn',\n headline: 'Opening',\n image: undefined,\n imageZoom: true,\n subtext: undefined,\n textColor: '#ffffff',\n textPosition: 'center',\n },\n ],\n transitionDuration: 15,\n })\n })\n\n test('normalizes populated Payload upload images and ignores upload IDs', () => {\n const deck = normalizeDecksBlock({\n slides: [\n {\n image: {\n alt: 'Poster',\n url: '/poster.jpg',\n },\n },\n {\n image: 'media-id',\n },\n ],\n })\n\n expect(deck.slides[0]?.image).toEqual({\n alt: 'Poster',\n url: '/poster.jpg',\n })\n expect(deck.slides[1]?.image).toBeUndefined()\n })\n})\n"],"names":["describe","expect","test","normalizeDecksBlock","deck","slides","headline","toEqual","autoPlay","backgroundColor","durationPerSlide","fps","loop","showControls","animationType","image","undefined","imageZoom","subtext","textColor","textPosition","transitionDuration","alt","url","toBeUndefined"],"mappings":"AAAA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,IAAI,QAAQ,SAAQ;AAE/C,SAASC,mBAAmB,QAAQ,aAAY;AAEhDH,SAAS,uBAAuB;IAC9BE,KAAK,4DAA4D;QAC/D,MAAME,OAAOD,oBAAoB;YAC/BE,QAAQ;gBACN;oBACEC,UAAU;gBACZ;aACD;QACH;QAEAL,OAAOG,MAAMG,OAAO,CAAC;YACnBC,UAAU;YACVC,iBAAiB;YACjBC,kBAAkB;YAClBC,KAAK;YACLC,MAAM;YACNC,cAAc;YACdR,QAAQ;gBACN;oBACES,eAAe;oBACfR,UAAU;oBACVS,OAAOC;oBACPC,WAAW;oBACXC,SAASF;oBACTG,WAAW;oBACXC,cAAc;gBAChB;aACD;YACDC,oBAAoB;QACtB;IACF;IAEAnB,KAAK,qEAAqE;QACxE,MAAME,OAAOD,oBAAoB;YAC/BE,QAAQ;gBACN;oBACEU,OAAO;wBACLO,KAAK;wBACLC,KAAK;oBACP;gBACF;gBACA;oBACER,OAAO;gBACT;aACD;QACH;QAEAd,OAAOG,KAAKC,MAAM,CAAC,EAAE,EAAEU,OAAOR,OAAO,CAAC;YACpCe,KAAK;YACLC,KAAK;QACP;QACAtB,OAAOG,KAAKC,MAAM,CAAC,EAAE,EAAEU,OAAOS,aAAa;IAC7C;AACF"}
|