From f24d0f371f2e1c9cf06c09b3b75e37dc05fbbf2d Mon Sep 17 00:00:00 2001 From: Legrand Thomas Date: Sun, 7 Jun 2026 17:39:58 +0200 Subject: [PATCH 1/7] feat: ajout d'un composant Strapi video --- .gitignore | 1 + backend/src/components/video/video-embed.json | 25 +++++++++++++++++++ .../BannerVideo/BannerVideo.stories.tsx | 19 +++++++++----- .../molecules/BannerVideo/BannerVideo.tsx | 19 ++++++++++++-- frontend/src/lib/strapi-types.d.ts | 6 +++++ 5 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 backend/src/components/video/video-embed.json diff --git a/.gitignore b/.gitignore index 48b49c94..19008f34 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ **node_modules/ .DS_Store .pi/extensions/emdash-hook.ts +.factory/settings.json diff --git a/backend/src/components/video/video-embed.json b/backend/src/components/video/video-embed.json new file mode 100644 index 00000000..748ca394 --- /dev/null +++ b/backend/src/components/video/video-embed.json @@ -0,0 +1,25 @@ +{ + "collectionName": "components_video_video_embeds", + "info": { + "displayName": "video_embed", + "icon": "play", + "description": "" + }, + "options": {}, + "attributes": { + "url": { + "type": "string" + }, + "embed": { + "type": "text" + }, + "orientation": { + "type": "enumeration", + "enum": [ + "horizontal", + "vertical" + ], + "default": "horizontal" + } + } +} diff --git a/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx b/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx index 27750cfa..44c20d51 100644 --- a/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx +++ b/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx @@ -12,33 +12,40 @@ const meta: Meta = { video: { control: { type: 'text' }, }, + format: { + control: { type: 'select' }, + options: ['horizontal', 'vertical'], + }, }, }; export default meta; type Story = StoryObj; -// Story avec contenu principal -export const Default: Story = { +export const Horizontal: Story = { args: { video: ``, + format: 'horizontal', }, }; -export const YoutubeVideo: Story = { +export const Vertical: Story = { args: { - video: ``, + video: ``, + format: 'vertical', }, }; -export const VimeoVideo: Story = { +export const VimeoHorizontal: Story = { args: { video: `
`, + format: 'horizontal', }, }; -export const DailymotionVideo: Story = { +export const DailymotionHorizontal: Story = { args: { video: `
`, + format: 'horizontal', }, }; diff --git a/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx b/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx index f15b8ab0..05c2f4a6 100644 --- a/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx +++ b/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx @@ -3,12 +3,14 @@ import clsx from 'clsx'; export type BannerVideoProps = { video?: string; altVideo?: string; + format?: 'horizontal' | 'vertical'; className?: string; }; const BannerVideo: React.FC = ({ video, altVideo, + format = 'horizontal', className, ...props }) => { @@ -19,12 +21,25 @@ const BannerVideo: React.FC = ({ return (
-
+
iframe]:w-full [&>iframe]:h-full', + { + 'aspect-video': format === 'horizontal', + 'aspect-[9/16]': format === 'vertical', + }, + )} + dangerouslySetInnerHTML={{ __html: `${video}` }} + />
); }; diff --git a/frontend/src/lib/strapi-types.d.ts b/frontend/src/lib/strapi-types.d.ts index 330b4b74..54b5ecdb 100644 --- a/frontend/src/lib/strapi-types.d.ts +++ b/frontend/src/lib/strapi-types.d.ts @@ -3303,6 +3303,12 @@ export interface components { stat?: string; description?: string; }; + VideoVideoEmbedComponent: { + id?: number; + url?: string; + embed?: string; + orientation?: "horizontal" | "vertical"; + }; BlogRequest: { data: { title?: string; From 78c3dd649f983ed2205cfabe87012ce35e8b5c51 Mon Sep 17 00:00:00 2001 From: Legrand Thomas Date: Wed, 24 Jun 2026 18:14:29 +0200 Subject: [PATCH 2/7] feat: rework BannerVideo component --- backend/src/components/video/video-embed.json | 9 +-- .../BannerVideo/BannerVideo.stories.tsx | 32 +++++---- .../molecules/BannerVideo/BannerVideo.tsx | 69 ++++++++++++++----- frontend/src/lib/strapi-types.d.ts | 3 +- 4 files changed, 72 insertions(+), 41 deletions(-) diff --git a/backend/src/components/video/video-embed.json b/backend/src/components/video/video-embed.json index 748ca394..82318e0d 100644 --- a/backend/src/components/video/video-embed.json +++ b/backend/src/components/video/video-embed.json @@ -10,16 +10,13 @@ "url": { "type": "string" }, - "embed": { - "type": "text" - }, "orientation": { "type": "enumeration", "enum": [ - "horizontal", - "vertical" + "paysage", + "portrait" ], - "default": "horizontal" + "default": "paysage" } } } diff --git a/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx b/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx index 44c20d51..22741440 100644 --- a/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx +++ b/frontend/src/components/molecules/BannerVideo/BannerVideo.stories.tsx @@ -9,12 +9,12 @@ const meta: Meta = { }, tags: ['autodocs'], argTypes: { - video: { + url: { control: { type: 'text' }, }, format: { control: { type: 'select' }, - options: ['horizontal', 'vertical'], + options: ['paysage', 'portrait'], }, }, }; @@ -22,30 +22,34 @@ const meta: Meta = { export default meta; type Story = StoryObj; -export const Horizontal: Story = { +export const Youtube: Story = { args: { - video: ``, - format: 'horizontal', + url: 'https://www.youtube.com/watch?v=k6Z1yqrITCc', }, }; -export const Vertical: Story = { +export const YoutubeShort: Story = { args: { - video: ``, - format: 'vertical', + url: 'https://www.youtube.com/shorts/JmK9FgHkq8E', }, }; -export const VimeoHorizontal: Story = { +export const YoutubePaysageForced: Story = { args: { - video: `
`, - format: 'horizontal', + url: 'https://www.youtube.com/watch?v=k6Z1yqrITCc', + format: 'paysage', }, }; -export const DailymotionHorizontal: Story = { +export const YoutubePortraitForced: Story = { args: { - video: `
`, - format: 'horizontal', + url: 'https://www.youtube.com/watch?v=k6Z1yqrITCc', + format: 'portrait', + }, +}; + +export const WithRawEmbed: Story = { + args: { + video: ``, }, }; diff --git a/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx b/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx index 05c2f4a6..a6d23fd7 100644 --- a/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx +++ b/frontend/src/components/molecules/BannerVideo/BannerVideo.tsx @@ -1,44 +1,75 @@ import clsx from 'clsx'; +function getYoutubeVideoId(url: string): string | null { + const patterns = [ + /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})(?:[?&]|$)/, + /youtube\.com\/shorts\/([a-zA-Z0-9_-]{11})(?:[?&]|$)/, + ]; + for (const pattern of patterns) { + const match = url.match(pattern); + if (match) return match[1]; + } + return null; +} + +function isShortsUrl(url: string): boolean { + return /youtube\.com\/shorts\//.test(url); +} + export type BannerVideoProps = { video?: string; + url?: string; altVideo?: string; - format?: 'horizontal' | 'vertical'; + format?: 'paysage' | 'portrait'; className?: string; }; const BannerVideo: React.FC = ({ video, + url, altVideo, - format = 'horizontal', + format, className, ...props }) => { + const resolvedFormat = format ?? (url && isShortsUrl(url) ? 'portrait' : 'paysage'); + + if (url) { + const videoId = getYoutubeVideoId(url); + if (!videoId) return null; + + const embedUrl = `https://www.youtube.com/embed/${videoId}`; + + return ( +
+