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
package/README.md
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# payload-plugin-decks
|
|
2
|
+
|
|
3
|
+
`payload-plugin-decks` adds reusable deck blocks to Payload collections. Today it ships a `decks` block: a slide-based, Remotion-powered deck with background images, headlines, subtext, text positioning, transitions, autoplay, looping, and optional playback controls.
|
|
4
|
+
|
|
5
|
+
The plugin adds the editing fields to Payload. Your frontend decides where and how to render the saved deck blocks.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Payload `^3.84.0`
|
|
10
|
+
- React / Next.js frontend capable of rendering client components
|
|
11
|
+
- A Payload upload collection with slug `media`
|
|
12
|
+
|
|
13
|
+
The decks block's image field is currently configured with `relationTo: 'media'`, so your Payload app must define a `media` collection.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
pnpm add payload-plugin-decks
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The package includes its Remotion runtime dependencies:
|
|
22
|
+
|
|
23
|
+
- `@remotion/player`
|
|
24
|
+
- `remotion`
|
|
25
|
+
|
|
26
|
+
## Configure Payload
|
|
27
|
+
|
|
28
|
+
Add `payloadDecks` to your Payload config and choose the collections that should receive the decks field.
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { buildConfig } from 'payload'
|
|
32
|
+
import { payloadDecks } from 'payload-plugin-decks'
|
|
33
|
+
|
|
34
|
+
export default buildConfig({
|
|
35
|
+
collections: [
|
|
36
|
+
{
|
|
37
|
+
slug: 'pages',
|
|
38
|
+
fields: [
|
|
39
|
+
// your fields
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
slug: 'media',
|
|
44
|
+
upload: true,
|
|
45
|
+
fields: [],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
plugins: [
|
|
49
|
+
payloadDecks({
|
|
50
|
+
collections: {
|
|
51
|
+
pages: true,
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
54
|
+
],
|
|
55
|
+
})
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This adds a `decks` blocks field to the configured collection. Editors can add one or more `decks` blocks inside that field.
|
|
59
|
+
|
|
60
|
+
## Options
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
type PayloadDecksConfig = {
|
|
64
|
+
collections?: Partial<Record<CollectionSlug, true>>
|
|
65
|
+
disabled?: boolean
|
|
66
|
+
fieldName?: string
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
| Option | Default | Description |
|
|
71
|
+
| ------------- | ----------- | ------------------------------------------------------------------- |
|
|
72
|
+
| `collections` | `undefined` | Collections that should receive the decks blocks field. |
|
|
73
|
+
| `fieldName` | `'decks'` | Name of the blocks field added to each configured collection. |
|
|
74
|
+
| `disabled` | `false` | Leaves schema additions in place but skips runtime plugin behavior. |
|
|
75
|
+
|
|
76
|
+
### Custom field name
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
payloadDecks({
|
|
80
|
+
collections: {
|
|
81
|
+
pages: true,
|
|
82
|
+
posts: true,
|
|
83
|
+
},
|
|
84
|
+
fieldName: 'heroDecks',
|
|
85
|
+
})
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Alternative: add the block to an existing blocks field
|
|
89
|
+
|
|
90
|
+
If your collection already has a `blocks` field (for example a page `layout` builder), you usually do **not** want the `payloadDecks()` plugin — it would add a second, separate `decks` field disconnected from your existing one. Instead, import the `DecksBlock` block config and add it to the field you already manage, alongside your other blocks:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { DecksBlock } from 'payload-plugin-decks'
|
|
94
|
+
|
|
95
|
+
export const Pages = {
|
|
96
|
+
slug: 'pages',
|
|
97
|
+
fields: [
|
|
98
|
+
{
|
|
99
|
+
name: 'layout',
|
|
100
|
+
type: 'blocks',
|
|
101
|
+
blocks: [
|
|
102
|
+
// ...your existing blocks
|
|
103
|
+
DecksBlock,
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Editors then pick **Decks** as one block among the others in that field, and you render it from the same array using the client renderer (see [Render Decks](#render-decks)).
|
|
111
|
+
|
|
112
|
+
Use `payloadDecks()` when you want a brand-new, dedicated decks field added for you; use the `DecksBlock` config directly when decks should be one choice within a blocks field you already have.
|
|
113
|
+
|
|
114
|
+
## Render Decks
|
|
115
|
+
|
|
116
|
+
The plugin does not automatically render decks in your frontend. Render the blocks from the field you added, usually inside your existing page or post block renderer.
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import dynamic from 'next/dynamic'
|
|
120
|
+
import type { DecksBlockProps } from 'payload-plugin-decks'
|
|
121
|
+
|
|
122
|
+
const DecksBlock = dynamic(
|
|
123
|
+
() => import('payload-plugin-decks/client').then((mod) => mod.DecksBlock),
|
|
124
|
+
{ ssr: false },
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
type DecksBlockData = DecksBlockProps & {
|
|
128
|
+
blockType: 'decks'
|
|
129
|
+
id?: string
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
type DeckBlock = DecksBlockData
|
|
133
|
+
|
|
134
|
+
export function DecksRenderer({ decks = [] }: { decks?: DeckBlock[] }) {
|
|
135
|
+
return (
|
|
136
|
+
<>
|
|
137
|
+
{decks.map((deck, index) => {
|
|
138
|
+
switch (deck.blockType) {
|
|
139
|
+
case 'decks':
|
|
140
|
+
return <DecksBlock key={deck.id || index} {...deck} />
|
|
141
|
+
default:
|
|
142
|
+
return null
|
|
143
|
+
}
|
|
144
|
+
})}
|
|
145
|
+
</>
|
|
146
|
+
)
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
If you generate Payload types, prefer using the generated collection type for your renderer props.
|
|
151
|
+
|
|
152
|
+
## Decks Fields
|
|
153
|
+
|
|
154
|
+
Each `decks` block supports:
|
|
155
|
+
|
|
156
|
+
| Field | Description |
|
|
157
|
+
| -------------------- | ----------------------------------------------------- |
|
|
158
|
+
| `title` | Optional internal reference for editors. |
|
|
159
|
+
| `fps` | Video frame rate. Defaults to `30`. |
|
|
160
|
+
| `durationPerSlide` | Seconds each slide is displayed. Defaults to `3`. |
|
|
161
|
+
| `transitionDuration` | Fade transition duration in frames. Defaults to `15`. |
|
|
162
|
+
| `backgroundColor` | Composition background color. Defaults to `#000000`. |
|
|
163
|
+
| `autoPlay` | Starts playback automatically. Defaults to `true`. |
|
|
164
|
+
| `loop` | Loops playback. Defaults to `true`. |
|
|
165
|
+
| `showControls` | Shows Remotion player controls. Defaults to `false`. |
|
|
166
|
+
| `slides` | Ordered slide array. Requires at least one slide. |
|
|
167
|
+
|
|
168
|
+
Each slide supports:
|
|
169
|
+
|
|
170
|
+
| Field | Description |
|
|
171
|
+
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
172
|
+
| `image` | Optional background image from the `media` collection. |
|
|
173
|
+
| `headline` | Optional headline text. |
|
|
174
|
+
| `subtext` | Optional supporting text. |
|
|
175
|
+
| `textColor` | Text color. Defaults to `#ffffff`. |
|
|
176
|
+
| `textPosition` | One of `top-left`, `top-center`, `top-right`, `center-left`, `center`, `center-right`, `bottom-left`, `bottom-center`, `bottom-right`. |
|
|
177
|
+
| `animationType` | One of `fadeIn`, `slideUp`, `slideDown`, `scaleIn`, `none`. |
|
|
178
|
+
| `imageZoom` | Enables a slow Ken Burns-style image zoom. Defaults to `true`. |
|
|
179
|
+
|
|
180
|
+
## Exports
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
import { DecksBlock, payloadDecks } from 'payload-plugin-decks'
|
|
184
|
+
import { DecksBlock as DecksRenderer } from 'payload-plugin-decks/client'
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Export | Description |
|
|
188
|
+
| ----------------------------------------------- | ---------------------------------------------------------------- |
|
|
189
|
+
| `payloadDecks` | Payload plugin factory. |
|
|
190
|
+
| `DecksBlock` from `payload-plugin-decks` | Payload block config for advanced composition. |
|
|
191
|
+
| `DecksBlock` from `payload-plugin-decks/client` | Client renderer for saved decks block data. |
|
|
192
|
+
| `DecksBlockProps` | Renderer prop type. |
|
|
193
|
+
| `DecksSlide` | Slide prop type. |
|
|
194
|
+
| `normalizeDecksBlock` | Normalizes saved Payload block data into the renderer interface. |
|
|
195
|
+
|
|
196
|
+
## Development
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
pnpm install
|
|
200
|
+
pnpm build
|
|
201
|
+
pnpm test:int
|
|
202
|
+
pnpm lint
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The integration test uses `mongodb-memory-server`, so it needs permission to bind a local port in sandboxed environments.
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { DECKS_DEFAULTS, decksAnimationOptions, decksTextPositionOptions } from '../../decks/schema.js';
|
|
2
|
+
export const DecksBlock = {
|
|
3
|
+
slug: 'decks',
|
|
4
|
+
fields: [
|
|
5
|
+
{
|
|
6
|
+
name: 'title',
|
|
7
|
+
type: 'text',
|
|
8
|
+
admin: {
|
|
9
|
+
description: 'Optional title for internal reference'
|
|
10
|
+
},
|
|
11
|
+
label: 'Title (internal reference)',
|
|
12
|
+
required: false
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: 'fps',
|
|
16
|
+
type: 'number',
|
|
17
|
+
admin: {
|
|
18
|
+
description: 'Video frame rate (default: 30 FPS)'
|
|
19
|
+
},
|
|
20
|
+
defaultValue: DECKS_DEFAULTS.fps,
|
|
21
|
+
label: 'Frames per Second',
|
|
22
|
+
max: 60,
|
|
23
|
+
min: 1
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: 'durationPerSlide',
|
|
27
|
+
type: 'number',
|
|
28
|
+
admin: {
|
|
29
|
+
description: 'How long each slide is displayed'
|
|
30
|
+
},
|
|
31
|
+
defaultValue: DECKS_DEFAULTS.durationPerSlide,
|
|
32
|
+
label: 'Duration per Slide (seconds)',
|
|
33
|
+
max: 30,
|
|
34
|
+
min: 1
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'transitionDuration',
|
|
38
|
+
type: 'number',
|
|
39
|
+
admin: {
|
|
40
|
+
description: 'Duration of fade transition between slides'
|
|
41
|
+
},
|
|
42
|
+
defaultValue: DECKS_DEFAULTS.transitionDuration,
|
|
43
|
+
label: 'Transition Duration (frames)',
|
|
44
|
+
max: 60,
|
|
45
|
+
min: 0
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
name: 'backgroundColor',
|
|
49
|
+
type: 'text',
|
|
50
|
+
admin: {
|
|
51
|
+
description: 'Background color in hex format (e.g., #000000)'
|
|
52
|
+
},
|
|
53
|
+
defaultValue: DECKS_DEFAULTS.backgroundColor,
|
|
54
|
+
label: 'Background Color'
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'autoPlay',
|
|
58
|
+
type: 'checkbox',
|
|
59
|
+
defaultValue: DECKS_DEFAULTS.autoPlay,
|
|
60
|
+
label: 'Auto Play'
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
name: 'loop',
|
|
64
|
+
type: 'checkbox',
|
|
65
|
+
defaultValue: DECKS_DEFAULTS.loop,
|
|
66
|
+
label: 'Loop Video'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'showControls',
|
|
70
|
+
type: 'checkbox',
|
|
71
|
+
defaultValue: DECKS_DEFAULTS.showControls,
|
|
72
|
+
label: 'Show Playback Controls'
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'slides',
|
|
76
|
+
type: 'array',
|
|
77
|
+
fields: [
|
|
78
|
+
{
|
|
79
|
+
name: 'image',
|
|
80
|
+
type: 'upload',
|
|
81
|
+
filterOptions: {
|
|
82
|
+
mimeType: {
|
|
83
|
+
contains: 'image'
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
label: 'Background Image',
|
|
87
|
+
relationTo: 'media',
|
|
88
|
+
required: false
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'headline',
|
|
92
|
+
type: 'text',
|
|
93
|
+
label: 'Headline',
|
|
94
|
+
maxLength: 100
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'subtext',
|
|
98
|
+
type: 'textarea',
|
|
99
|
+
label: 'Subtext',
|
|
100
|
+
maxLength: 300
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'textColor',
|
|
104
|
+
type: 'text',
|
|
105
|
+
admin: {
|
|
106
|
+
description: 'Text color in hex format (e.g., #ffffff)'
|
|
107
|
+
},
|
|
108
|
+
defaultValue: DECKS_DEFAULTS.textColor,
|
|
109
|
+
label: 'Text Color'
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: 'textPosition',
|
|
113
|
+
type: 'select',
|
|
114
|
+
defaultValue: DECKS_DEFAULTS.textPosition,
|
|
115
|
+
label: 'Text Position',
|
|
116
|
+
options: [
|
|
117
|
+
...decksTextPositionOptions
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'animationType',
|
|
122
|
+
type: 'select',
|
|
123
|
+
defaultValue: DECKS_DEFAULTS.animationType,
|
|
124
|
+
label: 'Text Animation',
|
|
125
|
+
options: [
|
|
126
|
+
...decksAnimationOptions
|
|
127
|
+
]
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'imageZoom',
|
|
131
|
+
type: 'checkbox',
|
|
132
|
+
defaultValue: DECKS_DEFAULTS.imageZoom,
|
|
133
|
+
label: 'Enable Ken Burns Effect (slow zoom)'
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
label: 'Slides',
|
|
137
|
+
minRows: 1,
|
|
138
|
+
required: true
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
interfaceName: 'DecksBlock',
|
|
142
|
+
labels: {
|
|
143
|
+
plural: 'Decks',
|
|
144
|
+
singular: 'Decks'
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/decks/config.ts"],"sourcesContent":["import type { Block } from 'payload'\n\nimport {\n DECKS_DEFAULTS,\n decksAnimationOptions,\n decksTextPositionOptions,\n} from '../../decks/schema.js'\n\nexport const DecksBlock: Block = {\n slug: 'decks',\n fields: [\n {\n name: 'title',\n type: 'text',\n admin: {\n description: 'Optional title for internal reference',\n },\n label: 'Title (internal reference)',\n required: false,\n },\n {\n name: 'fps',\n type: 'number',\n admin: {\n description: 'Video frame rate (default: 30 FPS)',\n },\n defaultValue: DECKS_DEFAULTS.fps,\n label: 'Frames per Second',\n max: 60,\n min: 1,\n },\n {\n name: 'durationPerSlide',\n type: 'number',\n admin: {\n description: 'How long each slide is displayed',\n },\n defaultValue: DECKS_DEFAULTS.durationPerSlide,\n label: 'Duration per Slide (seconds)',\n max: 30,\n min: 1,\n },\n {\n name: 'transitionDuration',\n type: 'number',\n admin: {\n description: 'Duration of fade transition between slides',\n },\n defaultValue: DECKS_DEFAULTS.transitionDuration,\n label: 'Transition Duration (frames)',\n max: 60,\n min: 0,\n },\n {\n name: 'backgroundColor',\n type: 'text',\n admin: {\n description: 'Background color in hex format (e.g., #000000)',\n },\n defaultValue: DECKS_DEFAULTS.backgroundColor,\n label: 'Background Color',\n },\n {\n name: 'autoPlay',\n type: 'checkbox',\n defaultValue: DECKS_DEFAULTS.autoPlay,\n label: 'Auto Play',\n },\n {\n name: 'loop',\n type: 'checkbox',\n defaultValue: DECKS_DEFAULTS.loop,\n label: 'Loop Video',\n },\n {\n name: 'showControls',\n type: 'checkbox',\n defaultValue: DECKS_DEFAULTS.showControls,\n label: 'Show Playback Controls',\n },\n {\n name: 'slides',\n type: 'array',\n fields: [\n {\n name: 'image',\n type: 'upload',\n filterOptions: {\n mimeType: { contains: 'image' },\n },\n label: 'Background Image',\n relationTo: 'media',\n required: false,\n },\n {\n name: 'headline',\n type: 'text',\n label: 'Headline',\n maxLength: 100,\n },\n {\n name: 'subtext',\n type: 'textarea',\n label: 'Subtext',\n maxLength: 300,\n },\n {\n name: 'textColor',\n type: 'text',\n admin: {\n description: 'Text color in hex format (e.g., #ffffff)',\n },\n defaultValue: DECKS_DEFAULTS.textColor,\n label: 'Text Color',\n },\n {\n name: 'textPosition',\n type: 'select',\n defaultValue: DECKS_DEFAULTS.textPosition,\n label: 'Text Position',\n options: [...decksTextPositionOptions],\n },\n {\n name: 'animationType',\n type: 'select',\n defaultValue: DECKS_DEFAULTS.animationType,\n label: 'Text Animation',\n options: [...decksAnimationOptions],\n },\n {\n name: 'imageZoom',\n type: 'checkbox',\n defaultValue: DECKS_DEFAULTS.imageZoom,\n label: 'Enable Ken Burns Effect (slow zoom)',\n },\n ],\n label: 'Slides',\n minRows: 1,\n required: true,\n },\n ],\n interfaceName: 'DecksBlock',\n labels: {\n plural: 'Decks',\n singular: 'Decks',\n },\n}\n"],"names":["DECKS_DEFAULTS","decksAnimationOptions","decksTextPositionOptions","DecksBlock","slug","fields","name","type","admin","description","label","required","defaultValue","fps","max","min","durationPerSlide","transitionDuration","backgroundColor","autoPlay","loop","showControls","filterOptions","mimeType","contains","relationTo","maxLength","textColor","textPosition","options","animationType","imageZoom","minRows","interfaceName","labels","plural","singular"],"mappings":"AAEA,SACEA,cAAc,EACdC,qBAAqB,EACrBC,wBAAwB,QACnB,wBAAuB;AAE9B,OAAO,MAAMC,aAAoB;IAC/BC,MAAM;IACNC,QAAQ;QACN;YACEC,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAC,OAAO;YACPC,UAAU;QACZ;QACA;YACEL,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAG,cAAcZ,eAAea,GAAG;YAChCH,OAAO;YACPI,KAAK;YACLC,KAAK;QACP;QACA;YACET,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAG,cAAcZ,eAAegB,gBAAgB;YAC7CN,OAAO;YACPI,KAAK;YACLC,KAAK;QACP;QACA;YACET,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAG,cAAcZ,eAAeiB,kBAAkB;YAC/CP,OAAO;YACPI,KAAK;YACLC,KAAK;QACP;QACA;YACET,MAAM;YACNC,MAAM;YACNC,OAAO;gBACLC,aAAa;YACf;YACAG,cAAcZ,eAAekB,eAAe;YAC5CR,OAAO;QACT;QACA;YACEJ,MAAM;YACNC,MAAM;YACNK,cAAcZ,eAAemB,QAAQ;YACrCT,OAAO;QACT;QACA;YACEJ,MAAM;YACNC,MAAM;YACNK,cAAcZ,eAAeoB,IAAI;YACjCV,OAAO;QACT;QACA;YACEJ,MAAM;YACNC,MAAM;YACNK,cAAcZ,eAAeqB,YAAY;YACzCX,OAAO;QACT;QACA;YACEJ,MAAM;YACNC,MAAM;YACNF,QAAQ;gBACN;oBACEC,MAAM;oBACNC,MAAM;oBACNe,eAAe;wBACbC,UAAU;4BAAEC,UAAU;wBAAQ;oBAChC;oBACAd,OAAO;oBACPe,YAAY;oBACZd,UAAU;gBACZ;gBACA;oBACEL,MAAM;oBACNC,MAAM;oBACNG,OAAO;oBACPgB,WAAW;gBACb;gBACA;oBACEpB,MAAM;oBACNC,MAAM;oBACNG,OAAO;oBACPgB,WAAW;gBACb;gBACA;oBACEpB,MAAM;oBACNC,MAAM;oBACNC,OAAO;wBACLC,aAAa;oBACf;oBACAG,cAAcZ,eAAe2B,SAAS;oBACtCjB,OAAO;gBACT;gBACA;oBACEJ,MAAM;oBACNC,MAAM;oBACNK,cAAcZ,eAAe4B,YAAY;oBACzClB,OAAO;oBACPmB,SAAS;2BAAI3B;qBAAyB;gBACxC;gBACA;oBACEI,MAAM;oBACNC,MAAM;oBACNK,cAAcZ,eAAe8B,aAAa;oBAC1CpB,OAAO;oBACPmB,SAAS;2BAAI5B;qBAAsB;gBACrC;gBACA;oBACEK,MAAM;oBACNC,MAAM;oBACNK,cAAcZ,eAAe+B,SAAS;oBACtCrB,OAAO;gBACT;aACD;YACDA,OAAO;YACPsB,SAAS;YACTrB,UAAU;QACZ;KACD;IACDsB,eAAe;IACfC,QAAQ;QACNC,QAAQ;QACRC,UAAU;IACZ;AACF,EAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DecksBlock as DecksBlockComponent, type DecksBlockProps, type DecksSlide, } from '../../components/decks/DecksBlock.js';
|
|
2
|
+
export { DecksComposition, type DecksCompositionProps, } from '../../components/decks/DecksComposition.js';
|
|
3
|
+
export { type NormalizedDecksBlock, type NormalizedDecksSlide, normalizeDecksBlock, } from '../../decks/model.js';
|
|
4
|
+
export { DecksBlock } from './config.js';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { DecksBlock as DecksBlockComponent } from '../../components/decks/DecksBlock.js';
|
|
2
|
+
export { DecksComposition } from '../../components/decks/DecksComposition.js';
|
|
3
|
+
export { normalizeDecksBlock } from '../../decks/model.js';
|
|
4
|
+
export { DecksBlock } from './config.js';
|
|
5
|
+
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/blocks/decks/index.ts"],"sourcesContent":["export {\n DecksBlock as DecksBlockComponent,\n type DecksBlockProps,\n type DecksSlide,\n} from '../../components/decks/DecksBlock.js'\nexport {\n DecksComposition,\n type DecksCompositionProps,\n} from '../../components/decks/DecksComposition.js'\nexport {\n type NormalizedDecksBlock,\n type NormalizedDecksSlide,\n normalizeDecksBlock,\n} from '../../decks/model.js'\nexport { DecksBlock } from './config.js'\n"],"names":["DecksBlock","DecksBlockComponent","DecksComposition","normalizeDecksBlock"],"mappings":"AAAA,SACEA,cAAcC,mBAAmB,QAG5B,uCAAsC;AAC7C,SACEC,gBAAgB,QAEX,6CAA4C;AACnD,SAGEC,mBAAmB,QACd,uBAAsB;AAC7B,SAASH,UAAU,QAAQ,cAAa"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DecksBlockProps } from '../../decks/model.js';
|
|
2
|
+
import './styles.css';
|
|
3
|
+
export type { DecksBlockProps, DecksSlide } from '../../decks/model.js';
|
|
4
|
+
export declare const DecksBlock: (props: DecksBlockProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
5
|
+
export default DecksBlock;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Player } from '@remotion/player';
|
|
4
|
+
import { useCallback, useMemo, useSyncExternalStore } from 'react';
|
|
5
|
+
import { normalizeDecksBlock } from '../../decks/model.js';
|
|
6
|
+
import { getSlideDurationFrames } from '../../decks/timeline.js';
|
|
7
|
+
import { DecksComposition } from './DecksComposition.js';
|
|
8
|
+
import { SnapContainer } from './SnapContainer.js';
|
|
9
|
+
import './styles.css';
|
|
10
|
+
const emptySubscribe = ()=>()=>{};
|
|
11
|
+
export const DecksBlock = (props)=>{
|
|
12
|
+
const isClient = useSyncExternalStore(emptySubscribe, ()=>true, ()=>false);
|
|
13
|
+
const deck = useMemo(()=>normalizeDecksBlock(props), [
|
|
14
|
+
props
|
|
15
|
+
]);
|
|
16
|
+
const totalDurationInFrames = useMemo(()=>{
|
|
17
|
+
return deck.slides.length * getSlideDurationFrames({
|
|
18
|
+
durationPerSlide: deck.durationPerSlide,
|
|
19
|
+
fps: deck.fps
|
|
20
|
+
});
|
|
21
|
+
}, [
|
|
22
|
+
deck.durationPerSlide,
|
|
23
|
+
deck.fps,
|
|
24
|
+
deck.slides.length
|
|
25
|
+
]);
|
|
26
|
+
const inputProps = useMemo(()=>({
|
|
27
|
+
backgroundColor: deck.backgroundColor,
|
|
28
|
+
durationPerSlide: deck.durationPerSlide,
|
|
29
|
+
slides: deck.slides,
|
|
30
|
+
transitionDuration: deck.transitionDuration
|
|
31
|
+
}), [
|
|
32
|
+
deck.backgroundColor,
|
|
33
|
+
deck.durationPerSlide,
|
|
34
|
+
deck.slides,
|
|
35
|
+
deck.transitionDuration
|
|
36
|
+
]);
|
|
37
|
+
const renderLoading = useCallback(()=>{
|
|
38
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
39
|
+
className: "decks-loading",
|
|
40
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
41
|
+
className: "decks-spinner"
|
|
42
|
+
})
|
|
43
|
+
});
|
|
44
|
+
}, []);
|
|
45
|
+
const errorFallback = useCallback(({ error })=>{
|
|
46
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
47
|
+
className: "decks-error",
|
|
48
|
+
children: /*#__PURE__*/ _jsxs("p", {
|
|
49
|
+
children: [
|
|
50
|
+
"Failed to load video: ",
|
|
51
|
+
error.message
|
|
52
|
+
]
|
|
53
|
+
})
|
|
54
|
+
});
|
|
55
|
+
}, []);
|
|
56
|
+
if (!isClient) {
|
|
57
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
58
|
+
className: "decks-wrapper",
|
|
59
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
60
|
+
className: "decks-container",
|
|
61
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
62
|
+
className: "decks-loading",
|
|
63
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
64
|
+
className: "decks-spinner"
|
|
65
|
+
})
|
|
66
|
+
})
|
|
67
|
+
})
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
if (deck.slides.length === 0) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return /*#__PURE__*/ _jsx(SnapContainer, {
|
|
74
|
+
children: /*#__PURE__*/ _jsx(Player, {
|
|
75
|
+
autoPlay: deck.autoPlay,
|
|
76
|
+
clickToPlay: !deck.autoPlay,
|
|
77
|
+
component: DecksComposition,
|
|
78
|
+
compositionHeight: 1080,
|
|
79
|
+
compositionWidth: 1920,
|
|
80
|
+
controls: deck.showControls,
|
|
81
|
+
doubleClickToFullscreen: true,
|
|
82
|
+
durationInFrames: totalDurationInFrames,
|
|
83
|
+
errorFallback: errorFallback,
|
|
84
|
+
fps: deck.fps,
|
|
85
|
+
// Deck compositions have no audio. Muting plus opting out of Remotion's
|
|
86
|
+
// shared audio tags stops the Player from creating a gated AudioContext,
|
|
87
|
+
// which strict browsers (e.g. Brave) block until a user gesture — that
|
|
88
|
+
// block stalls the playback clock so autoPlay never advances (black /
|
|
89
|
+
// frozen on the first frame until you pause-play or refocus the tab).
|
|
90
|
+
initiallyMuted: true,
|
|
91
|
+
inputProps: inputProps,
|
|
92
|
+
loop: deck.loop,
|
|
93
|
+
numberOfSharedAudioTags: 0,
|
|
94
|
+
renderLoading: renderLoading,
|
|
95
|
+
style: {
|
|
96
|
+
height: '100%',
|
|
97
|
+
width: '100%'
|
|
98
|
+
}
|
|
99
|
+
})
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
export default DecksBlock;
|
|
103
|
+
|
|
104
|
+
//# sourceMappingURL=DecksBlock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/decks/DecksBlock.tsx"],"sourcesContent":["'use client'\n\nimport { Player } from '@remotion/player'\nimport { useCallback, useMemo, useSyncExternalStore } from 'react'\n\nimport type { DecksBlockProps } from '../../decks/model.js'\n\nimport { normalizeDecksBlock } from '../../decks/model.js'\nimport { getSlideDurationFrames } from '../../decks/timeline.js'\nimport { DecksComposition } from './DecksComposition.js'\nimport { SnapContainer } from './SnapContainer.js'\nimport './styles.css'\n\nexport type { DecksBlockProps, DecksSlide } from '../../decks/model.js'\n\nconst emptySubscribe = () => () => {}\n\nexport const DecksBlock = (props: DecksBlockProps) => {\n const isClient = useSyncExternalStore(\n emptySubscribe,\n () => true,\n () => false,\n )\n const deck = useMemo(() => normalizeDecksBlock(props), [props])\n\n const totalDurationInFrames = useMemo(() => {\n return (\n deck.slides.length *\n getSlideDurationFrames({\n durationPerSlide: deck.durationPerSlide,\n fps: deck.fps,\n })\n )\n }, [deck.durationPerSlide, deck.fps, deck.slides.length])\n\n const inputProps = useMemo(\n () => ({\n backgroundColor: deck.backgroundColor,\n durationPerSlide: deck.durationPerSlide,\n slides: deck.slides,\n transitionDuration: deck.transitionDuration,\n }),\n [deck.backgroundColor, deck.durationPerSlide, deck.slides, deck.transitionDuration],\n )\n\n const renderLoading = useCallback(() => {\n return (\n <div className=\"decks-loading\">\n <div className=\"decks-spinner\" />\n </div>\n )\n }, [])\n\n const errorFallback = useCallback(({ error }: { error: Error }) => {\n return (\n <div className=\"decks-error\">\n <p>Failed to load video: {error.message}</p>\n </div>\n )\n }, [])\n\n if (!isClient) {\n return (\n <div className=\"decks-wrapper\">\n <div className=\"decks-container\">\n <div className=\"decks-loading\">\n <div className=\"decks-spinner\" />\n </div>\n </div>\n </div>\n )\n }\n\n if (deck.slides.length === 0) {\n return null\n }\n\n return (\n <SnapContainer>\n <Player\n autoPlay={deck.autoPlay}\n clickToPlay={!deck.autoPlay}\n component={DecksComposition}\n compositionHeight={1080}\n compositionWidth={1920}\n controls={deck.showControls}\n doubleClickToFullscreen\n durationInFrames={totalDurationInFrames}\n errorFallback={errorFallback}\n fps={deck.fps}\n // Deck compositions have no audio. Muting plus opting out of Remotion's\n // shared audio tags stops the Player from creating a gated AudioContext,\n // which strict browsers (e.g. Brave) block until a user gesture — that\n // block stalls the playback clock so autoPlay never advances (black /\n // frozen on the first frame until you pause-play or refocus the tab).\n initiallyMuted\n inputProps={inputProps}\n loop={deck.loop}\n numberOfSharedAudioTags={0}\n renderLoading={renderLoading}\n style={{\n height: '100%',\n width: '100%',\n }}\n />\n </SnapContainer>\n )\n}\n\nexport default DecksBlock\n"],"names":["Player","useCallback","useMemo","useSyncExternalStore","normalizeDecksBlock","getSlideDurationFrames","DecksComposition","SnapContainer","emptySubscribe","DecksBlock","props","isClient","deck","totalDurationInFrames","slides","length","durationPerSlide","fps","inputProps","backgroundColor","transitionDuration","renderLoading","div","className","errorFallback","error","p","message","autoPlay","clickToPlay","component","compositionHeight","compositionWidth","controls","showControls","doubleClickToFullscreen","durationInFrames","initiallyMuted","loop","numberOfSharedAudioTags","style","height","width"],"mappings":"AAAA;;AAEA,SAASA,MAAM,QAAQ,mBAAkB;AACzC,SAASC,WAAW,EAAEC,OAAO,EAAEC,oBAAoB,QAAQ,QAAO;AAIlE,SAASC,mBAAmB,QAAQ,uBAAsB;AAC1D,SAASC,sBAAsB,QAAQ,0BAAyB;AAChE,SAASC,gBAAgB,QAAQ,wBAAuB;AACxD,SAASC,aAAa,QAAQ,qBAAoB;AAClD,OAAO,eAAc;AAIrB,MAAMC,iBAAiB,IAAM,KAAO;AAEpC,OAAO,MAAMC,aAAa,CAACC;IACzB,MAAMC,WAAWR,qBACfK,gBACA,IAAM,MACN,IAAM;IAER,MAAMI,OAAOV,QAAQ,IAAME,oBAAoBM,QAAQ;QAACA;KAAM;IAE9D,MAAMG,wBAAwBX,QAAQ;QACpC,OACEU,KAAKE,MAAM,CAACC,MAAM,GAClBV,uBAAuB;YACrBW,kBAAkBJ,KAAKI,gBAAgB;YACvCC,KAAKL,KAAKK,GAAG;QACf;IAEJ,GAAG;QAACL,KAAKI,gBAAgB;QAAEJ,KAAKK,GAAG;QAAEL,KAAKE,MAAM,CAACC,MAAM;KAAC;IAExD,MAAMG,aAAahB,QACjB,IAAO,CAAA;YACLiB,iBAAiBP,KAAKO,eAAe;YACrCH,kBAAkBJ,KAAKI,gBAAgB;YACvCF,QAAQF,KAAKE,MAAM;YACnBM,oBAAoBR,KAAKQ,kBAAkB;QAC7C,CAAA,GACA;QAACR,KAAKO,eAAe;QAAEP,KAAKI,gBAAgB;QAAEJ,KAAKE,MAAM;QAAEF,KAAKQ,kBAAkB;KAAC;IAGrF,MAAMC,gBAAgBpB,YAAY;QAChC,qBACE,KAACqB;YAAIC,WAAU;sBACb,cAAA,KAACD;gBAAIC,WAAU;;;IAGrB,GAAG,EAAE;IAEL,MAAMC,gBAAgBvB,YAAY,CAAC,EAAEwB,KAAK,EAAoB;QAC5D,qBACE,KAACH;YAAIC,WAAU;sBACb,cAAA,MAACG;;oBAAE;oBAAuBD,MAAME,OAAO;;;;IAG7C,GAAG,EAAE;IAEL,IAAI,CAAChB,UAAU;QACb,qBACE,KAACW;YAAIC,WAAU;sBACb,cAAA,KAACD;gBAAIC,WAAU;0BACb,cAAA,KAACD;oBAAIC,WAAU;8BACb,cAAA,KAACD;wBAAIC,WAAU;;;;;IAKzB;IAEA,IAAIX,KAAKE,MAAM,CAACC,MAAM,KAAK,GAAG;QAC5B,OAAO;IACT;IAEA,qBACE,KAACR;kBACC,cAAA,KAACP;YACC4B,UAAUhB,KAAKgB,QAAQ;YACvBC,aAAa,CAACjB,KAAKgB,QAAQ;YAC3BE,WAAWxB;YACXyB,mBAAmB;YACnBC,kBAAkB;YAClBC,UAAUrB,KAAKsB,YAAY;YAC3BC,uBAAuB;YACvBC,kBAAkBvB;YAClBW,eAAeA;YACfP,KAAKL,KAAKK,GAAG;YACb,wEAAwE;YACxE,yEAAyE;YACzE,uEAAuE;YACvE,sEAAsE;YACtE,sEAAsE;YACtEoB,cAAc;YACdnB,YAAYA;YACZoB,MAAM1B,KAAK0B,IAAI;YACfC,yBAAyB;YACzBlB,eAAeA;YACfmB,OAAO;gBACLC,QAAQ;gBACRC,OAAO;YACT;;;AAIR,EAAC;AAED,eAAejC,WAAU"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { NormalizedDecksBlock } from '../../decks/model.js';
|
|
2
|
+
export interface DecksCompositionProps {
|
|
3
|
+
backgroundColor: NormalizedDecksBlock['backgroundColor'];
|
|
4
|
+
durationPerSlide: NormalizedDecksBlock['durationPerSlide'];
|
|
5
|
+
slides: NormalizedDecksBlock['slides'];
|
|
6
|
+
transitionDuration: NormalizedDecksBlock['transitionDuration'];
|
|
7
|
+
}
|
|
8
|
+
export declare const DecksComposition: ({ backgroundColor, durationPerSlide, slides, transitionDuration, }: DecksCompositionProps) => import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export default DecksComposition;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { AbsoluteFill, Img, Sequence, useCurrentFrame, useVideoConfig } from 'remotion';
|
|
4
|
+
import { getSlideDurationFrames, getSlideStyles } from '../../decks/timeline.js';
|
|
5
|
+
const Slide = ({ slide, slideDuration, transitionDuration })=>{
|
|
6
|
+
const frame = useCurrentFrame();
|
|
7
|
+
const { imageScale, opacity, position: positionStyles, textAnimation: textAnimationStyles } = getSlideStyles({
|
|
8
|
+
animationType: slide.animationType,
|
|
9
|
+
frame,
|
|
10
|
+
imageZoom: slide.imageZoom,
|
|
11
|
+
slideDuration,
|
|
12
|
+
textPosition: slide.textPosition,
|
|
13
|
+
transitionDuration
|
|
14
|
+
});
|
|
15
|
+
return /*#__PURE__*/ _jsxs(AbsoluteFill, {
|
|
16
|
+
style: {
|
|
17
|
+
opacity
|
|
18
|
+
},
|
|
19
|
+
children: [
|
|
20
|
+
slide.image?.url && /*#__PURE__*/ _jsx(AbsoluteFill, {
|
|
21
|
+
children: /*#__PURE__*/ _jsx(Img, {
|
|
22
|
+
alt: slide.image.alt || '',
|
|
23
|
+
src: slide.image.url,
|
|
24
|
+
style: {
|
|
25
|
+
height: '100%',
|
|
26
|
+
objectFit: 'cover',
|
|
27
|
+
transform: `scale(${imageScale})`,
|
|
28
|
+
width: '100%'
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}),
|
|
32
|
+
/*#__PURE__*/ _jsx(AbsoluteFill, {
|
|
33
|
+
style: {
|
|
34
|
+
backgroundColor: 'rgba(0, 0, 0, 0.3)'
|
|
35
|
+
}
|
|
36
|
+
}),
|
|
37
|
+
(slide.headline || slide.subtext) && /*#__PURE__*/ _jsxs("div", {
|
|
38
|
+
style: {
|
|
39
|
+
...positionStyles,
|
|
40
|
+
...textAnimationStyles
|
|
41
|
+
},
|
|
42
|
+
children: [
|
|
43
|
+
slide.headline && /*#__PURE__*/ _jsx("h1", {
|
|
44
|
+
style: {
|
|
45
|
+
color: slide.textColor,
|
|
46
|
+
fontSize: '3.5rem',
|
|
47
|
+
fontWeight: 700,
|
|
48
|
+
lineHeight: 1.2,
|
|
49
|
+
margin: 0,
|
|
50
|
+
marginBottom: slide.subtext ? '1rem' : 0,
|
|
51
|
+
textShadow: '2px 2px 4px rgba(0, 0, 0, 0.5)'
|
|
52
|
+
},
|
|
53
|
+
children: slide.headline
|
|
54
|
+
}),
|
|
55
|
+
slide.subtext && /*#__PURE__*/ _jsx("p", {
|
|
56
|
+
style: {
|
|
57
|
+
color: slide.textColor,
|
|
58
|
+
fontSize: '1.5rem',
|
|
59
|
+
fontWeight: 400,
|
|
60
|
+
lineHeight: 1.5,
|
|
61
|
+
margin: 0,
|
|
62
|
+
textShadow: '1px 1px 2px rgba(0, 0, 0, 0.5)'
|
|
63
|
+
},
|
|
64
|
+
children: slide.subtext
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
})
|
|
68
|
+
]
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
export const DecksComposition = ({ backgroundColor, durationPerSlide, slides, transitionDuration })=>{
|
|
72
|
+
const { fps } = useVideoConfig();
|
|
73
|
+
const slideDurationFrames = getSlideDurationFrames({
|
|
74
|
+
durationPerSlide,
|
|
75
|
+
fps
|
|
76
|
+
});
|
|
77
|
+
return /*#__PURE__*/ _jsx(AbsoluteFill, {
|
|
78
|
+
style: {
|
|
79
|
+
backgroundColor
|
|
80
|
+
},
|
|
81
|
+
children: slides.map((slide, index)=>/*#__PURE__*/ _jsx(Sequence, {
|
|
82
|
+
durationInFrames: slideDurationFrames,
|
|
83
|
+
from: index * slideDurationFrames,
|
|
84
|
+
children: /*#__PURE__*/ _jsx(Slide, {
|
|
85
|
+
slide: slide,
|
|
86
|
+
slideDuration: slideDurationFrames,
|
|
87
|
+
transitionDuration: transitionDuration
|
|
88
|
+
})
|
|
89
|
+
}, index))
|
|
90
|
+
});
|
|
91
|
+
};
|
|
92
|
+
export default DecksComposition;
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=DecksComposition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/components/decks/DecksComposition.tsx"],"sourcesContent":["'use client'\n\nimport { AbsoluteFill, Img, Sequence, useCurrentFrame, useVideoConfig } from 'remotion'\n\nimport type {\n NormalizedDecksBlock,\n NormalizedDecksSlide,\n} from '../../decks/model.js'\n\nimport {\n getSlideDurationFrames,\n getSlideStyles,\n} from '../../decks/timeline.js'\n\nexport interface DecksCompositionProps {\n backgroundColor: NormalizedDecksBlock['backgroundColor']\n durationPerSlide: NormalizedDecksBlock['durationPerSlide']\n slides: NormalizedDecksBlock['slides']\n transitionDuration: NormalizedDecksBlock['transitionDuration']\n}\n\ninterface SlideProps {\n slide: NormalizedDecksSlide\n slideDuration: number\n transitionDuration: number\n}\n\nconst Slide = ({ slide, slideDuration, transitionDuration }: SlideProps) => {\n const frame = useCurrentFrame()\n\n const { imageScale, opacity, position: positionStyles, textAnimation: textAnimationStyles } = getSlideStyles({\n animationType: slide.animationType,\n frame,\n imageZoom: slide.imageZoom,\n slideDuration,\n textPosition: slide.textPosition,\n transitionDuration,\n })\n\n return (\n <AbsoluteFill style={{ opacity }}>\n {slide.image?.url && (\n <AbsoluteFill>\n <Img\n alt={slide.image.alt || ''}\n src={slide.image.url}\n style={{\n height: '100%',\n objectFit: 'cover',\n transform: `scale(${imageScale})`,\n width: '100%',\n }}\n />\n </AbsoluteFill>\n )}\n\n <AbsoluteFill\n style={{\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n }}\n />\n\n {(slide.headline || slide.subtext) && (\n <div style={{ ...positionStyles, ...textAnimationStyles }}>\n {slide.headline && (\n <h1\n style={{\n color: slide.textColor,\n fontSize: '3.5rem',\n fontWeight: 700,\n lineHeight: 1.2,\n margin: 0,\n marginBottom: slide.subtext ? '1rem' : 0,\n textShadow: '2px 2px 4px rgba(0, 0, 0, 0.5)',\n }}\n >\n {slide.headline}\n </h1>\n )}\n {slide.subtext && (\n <p\n style={{\n color: slide.textColor,\n fontSize: '1.5rem',\n fontWeight: 400,\n lineHeight: 1.5,\n margin: 0,\n textShadow: '1px 1px 2px rgba(0, 0, 0, 0.5)',\n }}\n >\n {slide.subtext}\n </p>\n )}\n </div>\n )}\n </AbsoluteFill>\n )\n}\n\nexport const DecksComposition = ({\n backgroundColor,\n durationPerSlide,\n slides,\n transitionDuration,\n}: DecksCompositionProps) => {\n const { fps } = useVideoConfig()\n const slideDurationFrames = getSlideDurationFrames({ durationPerSlide, fps })\n\n return (\n <AbsoluteFill style={{ backgroundColor }}>\n {slides.map((slide, index) => (\n <Sequence\n durationInFrames={slideDurationFrames}\n from={index * slideDurationFrames}\n key={index}\n >\n <Slide\n slide={slide}\n slideDuration={slideDurationFrames}\n transitionDuration={transitionDuration}\n />\n </Sequence>\n ))}\n </AbsoluteFill>\n )\n}\n\nexport default DecksComposition\n"],"names":["AbsoluteFill","Img","Sequence","useCurrentFrame","useVideoConfig","getSlideDurationFrames","getSlideStyles","Slide","slide","slideDuration","transitionDuration","frame","imageScale","opacity","position","positionStyles","textAnimation","textAnimationStyles","animationType","imageZoom","textPosition","style","image","url","alt","src","height","objectFit","transform","width","backgroundColor","headline","subtext","div","h1","color","textColor","fontSize","fontWeight","lineHeight","margin","marginBottom","textShadow","p","DecksComposition","durationPerSlide","slides","fps","slideDurationFrames","map","index","durationInFrames","from"],"mappings":"AAAA;;AAEA,SAASA,YAAY,EAAEC,GAAG,EAAEC,QAAQ,EAAEC,eAAe,EAAEC,cAAc,QAAQ,WAAU;AAOvF,SACEC,sBAAsB,EACtBC,cAAc,QACT,0BAAyB;AAehC,MAAMC,QAAQ,CAAC,EAAEC,KAAK,EAAEC,aAAa,EAAEC,kBAAkB,EAAc;IACrE,MAAMC,QAAQR;IAEd,MAAM,EAAES,UAAU,EAAEC,OAAO,EAAEC,UAAUC,cAAc,EAAEC,eAAeC,mBAAmB,EAAE,GAAGX,eAAe;QAC3GY,eAAeV,MAAMU,aAAa;QAClCP;QACAQ,WAAWX,MAAMW,SAAS;QAC1BV;QACAW,cAAcZ,MAAMY,YAAY;QAChCV;IACF;IAEA,qBACE,MAACV;QAAaqB,OAAO;YAAER;QAAQ;;YAC5BL,MAAMc,KAAK,EAAEC,qBACZ,KAACvB;0BACC,cAAA,KAACC;oBACCuB,KAAKhB,MAAMc,KAAK,CAACE,GAAG,IAAI;oBACxBC,KAAKjB,MAAMc,KAAK,CAACC,GAAG;oBACpBF,OAAO;wBACLK,QAAQ;wBACRC,WAAW;wBACXC,WAAW,CAAC,MAAM,EAAEhB,WAAW,CAAC,CAAC;wBACjCiB,OAAO;oBACT;;;0BAKN,KAAC7B;gBACCqB,OAAO;oBACLS,iBAAiB;gBACnB;;YAGAtB,CAAAA,MAAMuB,QAAQ,IAAIvB,MAAMwB,OAAO,AAAD,mBAC9B,MAACC;gBAAIZ,OAAO;oBAAE,GAAGN,cAAc;oBAAE,GAAGE,mBAAmB;gBAAC;;oBACrDT,MAAMuB,QAAQ,kBACb,KAACG;wBACCb,OAAO;4BACLc,OAAO3B,MAAM4B,SAAS;4BACtBC,UAAU;4BACVC,YAAY;4BACZC,YAAY;4BACZC,QAAQ;4BACRC,cAAcjC,MAAMwB,OAAO,GAAG,SAAS;4BACvCU,YAAY;wBACd;kCAEClC,MAAMuB,QAAQ;;oBAGlBvB,MAAMwB,OAAO,kBACZ,KAACW;wBACCtB,OAAO;4BACLc,OAAO3B,MAAM4B,SAAS;4BACtBC,UAAU;4BACVC,YAAY;4BACZC,YAAY;4BACZC,QAAQ;4BACRE,YAAY;wBACd;kCAEClC,MAAMwB,OAAO;;;;;;AAO5B;AAEA,OAAO,MAAMY,mBAAmB,CAAC,EAC/Bd,eAAe,EACfe,gBAAgB,EAChBC,MAAM,EACNpC,kBAAkB,EACI;IACtB,MAAM,EAAEqC,GAAG,EAAE,GAAG3C;IAChB,MAAM4C,sBAAsB3C,uBAAuB;QAAEwC;QAAkBE;IAAI;IAE3E,qBACE,KAAC/C;QAAaqB,OAAO;YAAES;QAAgB;kBACpCgB,OAAOG,GAAG,CAAC,CAACzC,OAAO0C,sBAClB,KAAChD;gBACCiD,kBAAkBH;gBAClBI,MAAMF,QAAQF;0BAGd,cAAA,KAACzC;oBACCC,OAAOA;oBACPC,eAAeuC;oBACftC,oBAAoBA;;eALjBwC;;AAWf,EAAC;AAED,eAAeN,iBAAgB"}
|