add video embed to description pane
This commit is contained in:
parent
c93f65153c
commit
5e01e56dec
3 changed files with 48 additions and 11 deletions
|
|
@ -52,7 +52,7 @@
|
||||||
import Button from '$lib/components/ui/Button.svelte'
|
import Button from '$lib/components/ui/Button.svelte'
|
||||||
import Icon from '$lib/components/Icon.svelte'
|
import Icon from '$lib/components/Icon.svelte'
|
||||||
import DescriptionRenderer from '$lib/components/DescriptionRenderer.svelte'
|
import DescriptionRenderer from '$lib/components/DescriptionRenderer.svelte'
|
||||||
import { openDescriptionSidebar } from '$lib/features/description/openDescriptionSidebar.svelte'
|
import { openDescriptionPane } from '$lib/features/description/openDescriptionPane.svelte'
|
||||||
import {
|
import {
|
||||||
openPartyEditSidebar,
|
openPartyEditSidebar,
|
||||||
type PartyEditValues
|
type PartyEditValues
|
||||||
|
|
@ -407,9 +407,10 @@
|
||||||
let deleting = $state(false)
|
let deleting = $state(false)
|
||||||
|
|
||||||
function openDescriptionPanel() {
|
function openDescriptionPanel() {
|
||||||
openDescriptionSidebar({
|
openDescriptionPane({
|
||||||
title: party.name || '(untitled party)',
|
title: party.name || '(untitled party)',
|
||||||
description: party.description,
|
description: party.description,
|
||||||
|
videoUrl: party.videoUrl,
|
||||||
canEdit: canEdit(),
|
canEdit: canEdit(),
|
||||||
partyId: party.id,
|
partyId: party.id,
|
||||||
partyShortcode: party.shortcode,
|
partyShortcode: party.shortcode,
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,24 @@
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
description?: string
|
description?: string
|
||||||
|
videoUrl?: string
|
||||||
canEdit?: boolean
|
canEdit?: boolean
|
||||||
partyId?: string
|
partyId?: string
|
||||||
partyShortcode?: string
|
partyShortcode?: string
|
||||||
onSave?: (description: string) => Promise<void>
|
onSave?: (description: string) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
let { description, canEdit = false, partyId, partyShortcode, onSave }: Props = $props()
|
let { description, videoUrl, canEdit = false, partyId, partyShortcode, onSave }: Props = $props()
|
||||||
|
|
||||||
|
/** Extract YouTube video ID from various URL formats */
|
||||||
|
function extractVideoId(url?: string): string | null {
|
||||||
|
if (!url) return null
|
||||||
|
// Match youtube.com/watch?v=ID, youtu.be/ID, youtube.com/embed/ID
|
||||||
|
const match = url.match(/(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]{11})/)
|
||||||
|
return match?.[1] ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoId = $derived(extractVideoId(videoUrl))
|
||||||
|
|
||||||
const paneStack = usePaneStack()
|
const paneStack = usePaneStack()
|
||||||
|
|
||||||
|
|
@ -43,9 +54,20 @@
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="description-sidebar">
|
<div class="description-pane">
|
||||||
<div class="content-section">
|
<div class="content-section">
|
||||||
<div class="content-inner">
|
<div class="content-inner">
|
||||||
|
{#if videoId}
|
||||||
|
<div class="video-embed">
|
||||||
|
<iframe
|
||||||
|
src="https://www.youtube.com/embed/{videoId}"
|
||||||
|
title="YouTube video"
|
||||||
|
frameborder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowfullscreen
|
||||||
|
></iframe>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
{#if description}
|
{#if description}
|
||||||
<div class="description-content">
|
<div class="description-content">
|
||||||
<DescriptionRenderer content={description} truncate={false} />
|
<DescriptionRenderer content={description} truncate={false} />
|
||||||
|
|
@ -65,13 +87,25 @@
|
||||||
@use '$src/themes/typography' as *;
|
@use '$src/themes/typography' as *;
|
||||||
@use '$src/themes/effects' as *;
|
@use '$src/themes/effects' as *;
|
||||||
|
|
||||||
.description-sidebar {
|
.description-pane {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-embed {
|
||||||
|
margin-bottom: $unit-2x;
|
||||||
|
border-radius: $unit;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
iframe {
|
||||||
|
width: 100%;
|
||||||
|
aspect-ratio: 16 / 9;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.content-section {
|
.content-section {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
import { sidebar } from '$lib/stores/sidebar.svelte'
|
import { sidebar } from '$lib/stores/sidebar.svelte'
|
||||||
import DescriptionSidebar from '$lib/components/sidebar/DescriptionSidebar.svelte'
|
import DescriptionPane from '$lib/components/sidebar/DescriptionPane.svelte'
|
||||||
|
|
||||||
interface DescriptionSidebarOptions {
|
interface DescriptionPaneOptions {
|
||||||
title?: string | undefined
|
title?: string | undefined
|
||||||
description?: string | undefined
|
description?: string | undefined
|
||||||
|
videoUrl?: string | undefined
|
||||||
canEdit?: boolean | undefined
|
canEdit?: boolean | undefined
|
||||||
partyId?: string | undefined
|
partyId?: string | undefined
|
||||||
partyShortcode?: string | undefined
|
partyShortcode?: string | undefined
|
||||||
onSave?: ((description: string) => Promise<void>) | undefined
|
onSave?: ((description: string) => Promise<void>) | undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
export function openDescriptionSidebar(options: DescriptionSidebarOptions) {
|
export function openDescriptionPane(options: DescriptionPaneOptions) {
|
||||||
const { title, description, canEdit, partyId, partyShortcode, onSave } = options
|
const { title, description, videoUrl, canEdit, partyId, partyShortcode, onSave } = options
|
||||||
|
|
||||||
sidebar.openWithComponent(title ?? '', DescriptionSidebar, {
|
sidebar.openWithComponent(title ?? '', DescriptionPane, {
|
||||||
description,
|
description,
|
||||||
|
videoUrl,
|
||||||
canEdit,
|
canEdit,
|
||||||
partyId,
|
partyId,
|
||||||
partyShortcode,
|
partyShortcode,
|
||||||
|
|
@ -22,6 +24,6 @@ export function openDescriptionSidebar(options: DescriptionSidebarOptions) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function closeDescriptionSidebar() {
|
export function closeDescriptionPane() {
|
||||||
sidebar.close()
|
sidebar.close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue