Skip to content

Commit

Permalink
feat(template): add template carousel
Browse files Browse the repository at this point in the history
  • Loading branch information
Slashgear committed Sep 27, 2023
1 parent ac2b3f1 commit aecb770
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 0 deletions.
96 changes: 96 additions & 0 deletions app/templates/carousel/carousel/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
'use client';

import React, {SetStateAction, useState} from 'react';
import JSONInput from 'react-json-editor-ajrm';
import locale from 'react-json-editor-ajrm/locale/en';
import {Player} from '@remotion/player';

import {Code} from '../../../../src/app/Code';
import {
DefaultPropsTypes,
} from '../../../../src/app/types/template.types';

import styles from '../../../../styles/app/layout/main.module.css';
import { Carousel } from '../../../../remotion/compositions/templates/carousel/Carousel'
import { useGenerateVideo } from '../../../../src/app/hooks/useGenerateVideo'
import { RenderButton } from '../../../../src/app/forms/RenderButton'

const defaultValues = {
imageUrls: [
'https://secure.meetupstatic.com/photos/event/a/9/9/9/highres_511003417.webp',
'https://secure.meetupstatic.com/photos/event/4/a/c/7/highres_515299143.webp',
'https://secure.meetupstatic.com/photos/event/a/8/1/1/highres_515983025.webp',
'https://secure.meetupstatic.com/photos/event/a/8/0/b/highres_515983019.webp',
],
imageDuration: 90,
logoUrl: '/images/showcases/lyonjs/lyonjsSquaredLogo.png'
}

export default function CarouselTemplate() {
const [data, setData] = useState(
defaultValues,
);
const {getVideoLink, isLoading, videoUrl, error} = useGenerateVideo(
data,
'Carousel',
);

const handleSubmit = (event: React.MouseEvent<Element, MouseEvent>) => {
event.preventDefault();
getVideoLink();
};

return (
<div className={styles.mainContent}>
<section className={styles.videoContainer}>
<h2>Carousel</h2>
<Player
autoPlay
controls
loop
className={styles.video}
style={{
width: '100%',
aspectRatio: '16/9',
}}
durationInFrames={data.imageDuration*data.imageUrls.length}
compositionWidth={800}
compositionHeight={800}
fps={30}
component={Carousel}
inputProps={data || defaultValues}
/>
<RenderButton
compositionId="Carousel"
isLoading={isLoading}
videoUrl={videoUrl}
error={error}
onSubmit={handleSubmit}
/>
<JSONInput
placeholder={defaultValues}
theme="light_mitsuketa_tribute"
locale={locale}
colors={{
string: '#7B2CBF',
}}
style={{
body: {
border: 'solid 3px #c77dff',
borderRadius: '5px',
},
}}
height="300px"
width="100%"
onChange={(event: {jsObject: SetStateAction<DefaultPropsTypes>}) => {
setData(event.jsObject);
}}
/>
<Code
composition="Carousel"
params={data || defaultValues}
/>
</section>
</div>
);
}
2 changes: 2 additions & 0 deletions remotion/compositions/templates/Templates.composition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {MeetupComposition} from './meetup/Meetup.composition';
import {SilhouetteComposition} from './silhouette/Silhouette.composition';
import {SponsorsComposition} from './sponsor/Sponsors.composition';
import {TalksComposition} from './talk/Talks.composition';
import { CarouselComposition } from './carousel/Carousel.composition'

export const TemplatesComposition: React.FC = () => {
return (
Expand All @@ -17,6 +18,7 @@ export const TemplatesComposition: React.FC = () => {
<EventsComposition />
<SilhouetteComposition />
<LayersComposition />
<CarouselComposition />
</Folder>
);
};
36 changes: 36 additions & 0 deletions remotion/compositions/templates/carousel/Carousel.composition.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Composition, Folder, staticFile } from 'remotion'
import { Carousel } from './Carousel'
export const CarouselComposition: React.FC = () => {
const imageUrls = [
'https://secure.meetupstatic.com/photos/event/a/9/9/9/highres_511003417.webp',
'https://secure.meetupstatic.com/photos/event/4/a/c/7/highres_515299143.webp',
'https://secure.meetupstatic.com/photos/event/a/8/1/1/highres_515983025.webp',
'https://secure.meetupstatic.com/photos/event/a/8/0/b/highres_515983019.webp',
]

const imageDuration = 90

return (
<Folder name="Carousel">
<Composition
component={Carousel}
width={800}
height={800}
id="Carousel"
fps={30}
durationInFrames={imageUrls.length * imageDuration}
defaultProps={{
imageUrls,
imageDuration,
logoUrl: staticFile('/images/showcases/lyonjs/lyonjsSquaredLogo.png')
}}
calculateMetadata={(props)=> {

return {
durationInFrames: props.defaultProps.imageDuration * props.defaultProps.imageUrls.length
}
}}
/>
</Folder>
);
};
22 changes: 22 additions & 0 deletions remotion/compositions/templates/carousel/Carousel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AbsoluteFill, Img, Sequence } from 'remotion'
import { AnimationMode, CarouselImage } from './CarouselImage'

export type CarouselType = {
imageUrls: string[]
logoUrl?: string
imageDuration: number
}
export function Carousel({ imageUrls, logoUrl, imageDuration }: CarouselType) {
const delayShift = imageDuration * 0.25;

return <AbsoluteFill style={{ overflow: 'hidden', background: 'black'}}>
{
imageUrls.map((image, index) => {
return <Sequence from={index * (imageDuration - delayShift)} key={image} durationInFrames={index === imageUrls.length - 1? undefined: imageDuration} name={`Image number ${index}`}>
<CarouselImage imageUrl={image} noAnimation={index === imageUrls.length - 1} imageDuration={imageDuration}/>
</Sequence>
})
}
{logoUrl && <Img src={logoUrl} style={{ position: 'absolute', right: '20px', bottom: '20px', height: "100px"}}/>}
</AbsoluteFill>
}
49 changes: 49 additions & 0 deletions remotion/compositions/templates/carousel/CarouselImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Easing, Img, interpolate, useCurrentFrame, useVideoConfig } from 'remotion'
import { CSSProperties } from 'react'

export type AnimationMode = 'slideLeft'
export function CarouselImage({ imageUrl, imageDuration, noAnimation = false }: { imageUrl: string, imageDuration: number, noAnimation?: boolean}) {
const frame = useCurrentFrame();
const { width } = useVideoConfig();
const animationDuration = imageDuration * 0.10;
const slide = interpolate(frame, [imageDuration - animationDuration , imageDuration], [0,width/2], {
easing: Easing.out(Easing.cubic),
extrapolateRight: 'clamp'
})
const opacity = interpolate(frame, [imageDuration - animationDuration , imageDuration], [1,0], {
extrapolateRight: 'clamp'
})


let animation: CSSProperties = {
transform: `translate(-${slide}px)`,
opacity,
}

if(noAnimation) {
animation = {}
}

return <>
<Img src={imageUrl} style={{
position: 'absolute',
inset: 0,
objectFit: 'cover',
width: '100%',
height: '100%',
filter: 'blur(20px)',
transform: 'scale(1.2)',
opacity: 0.3,
...animation
}}/>
<Img src={imageUrl} style={{
position: 'absolute',
inset: 0,
objectFit: 'contain',
width: '100%',
height: '100%',
...animation
}}/>
</>

}
2 changes: 2 additions & 0 deletions src/data/config/compositionsConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from './templates/sponsorConfig';
import {TalkBrandedConfig} from './templates/talkBrandedConfig';
import {TalkConfig} from './templates/talkConfig';
import { CarouselConfig } from './templates/carouselConfig'

export type CompositionProps = {
component: TemplateTypes;
Expand Down Expand Up @@ -52,6 +53,7 @@ export const CompositionsConfig: CompositionsConfigProps = {
Event: EventConfig,
Meetup: MeetupConfig,
Silhouette: SilhouetteConfig,
Carousel: CarouselConfig,
},
showcases: {
Devoxx: DevoxxConfig,
Expand Down
10 changes: 10 additions & 0 deletions src/data/config/sideBarConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ export const sideBarNavConfig: sideBarNavProps = {
},
],
},
{
categoryName: 'carousel',
items: [
{
compositionName: 'Carousel',
compositionId: 'Carousel',
compositionLink: 'carousel',
},
],
},
{
categoryName: 'layers',
items: [
Expand Down
21 changes: 21 additions & 0 deletions src/data/config/templates/carouselConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {CompositionProps} from '../compositionsConfig';
import { Carousel } from '../../../../remotion/compositions/templates/carousel/Carousel'

export const CarouselConfig: CompositionProps = {
compositionName: 'Carousel',
component: Carousel,
width: 800,
height: 800,
durationInFrames: 300,
frameForThumbnail: 90,
defaultProps: {
imageUrls: [
'https://secure.meetupstatic.com/photos/event/a/9/9/9/highres_511003417.webp',
'https://secure.meetupstatic.com/photos/event/4/a/c/7/highres_515299143.webp',
'https://secure.meetupstatic.com/photos/event/a/8/1/1/highres_515983025.webp',
'https://secure.meetupstatic.com/photos/event/a/8/0/b/highres_515983019.webp',
],
imageDuration: 90,
logoUrl: '/images/showcases/lyonjs/lyonjsSquaredLogo.png'
},
};

0 comments on commit aecb770

Please sign in to comment.