feat(frontend): video presentation on property detail page
- VideoPlayer: auto-detects YouTube/Vimeo embed or direct video file - PhotoCarousel: accepts videoUrl prop, shows video as first slide with play icon thumbnail - PropertyDetailPage: renders video in carousel (position=carousel) or as standalone section (position=section) - PriceBox: fix sticky offset for navbar height - PropertyForm: video URL input with live preview + position selector - AdminPropertiesPage: include video fields in edit initial data - types/property: add video_url and video_position to PropertyDetail - utils/getEmbedUrl: helper to resolve YouTube/Vimeo/direct URLs
This commit is contained in:
parent
d363a09f36
commit
2e9f903d06
8 changed files with 252 additions and 35 deletions
38
frontend/src/utils/getEmbedUrl.ts
Normal file
38
frontend/src/utils/getEmbedUrl.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
export type VideoType = 'youtube' | 'vimeo' | 'direct' | 'unknown'
|
||||
|
||||
export interface EmbedResult {
|
||||
type: VideoType
|
||||
embedUrl: string | null
|
||||
}
|
||||
|
||||
export function getEmbedUrl(url: string): EmbedResult {
|
||||
const trimmed = url.trim()
|
||||
if (!trimmed) return { type: 'unknown', embedUrl: null }
|
||||
|
||||
// YouTube — watch?v=, youtu.be/, embed/
|
||||
const ytWatch = trimmed.match(
|
||||
/(?:youtube\.com\/watch\?(?:.*&)?v=|youtu\.be\/)([A-Za-z0-9_-]{11})/
|
||||
)
|
||||
if (ytWatch) {
|
||||
return { type: 'youtube', embedUrl: `https://www.youtube.com/embed/${ytWatch[1]}` }
|
||||
}
|
||||
if (/youtube\.com\/embed\/[A-Za-z0-9_-]{11}/.test(trimmed)) {
|
||||
return { type: 'youtube', embedUrl: trimmed }
|
||||
}
|
||||
|
||||
// Vimeo — vimeo.com/ID ou player.vimeo.com/video/ID
|
||||
const vimeoMatch = trimmed.match(/vimeo\.com\/(?:video\/)?(\d+)/)
|
||||
if (vimeoMatch) {
|
||||
return { type: 'vimeo', embedUrl: `https://player.vimeo.com/video/${vimeoMatch[1]}` }
|
||||
}
|
||||
if (/player\.vimeo\.com\/video\/\d+/.test(trimmed)) {
|
||||
return { type: 'vimeo', embedUrl: trimmed }
|
||||
}
|
||||
|
||||
// Arquivo direto de vídeo (.mp4 ou .webm)
|
||||
if (/\.(mp4|webm)(\?.*)?$/i.test(trimmed)) {
|
||||
return { type: 'direct', embedUrl: trimmed }
|
||||
}
|
||||
|
||||
return { type: 'unknown', embedUrl: null }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue