add video embed to description pane

This commit is contained in:
Justin Edmund 2025-12-21 17:02:28 -08:00
parent c93f65153c
commit 5e01e56dec
3 changed files with 48 additions and 11 deletions

View file

@ -52,7 +52,7 @@
import Button from '$lib/components/ui/Button.svelte'
import Icon from '$lib/components/Icon.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 {
openPartyEditSidebar,
type PartyEditValues
@ -407,9 +407,10 @@
let deleting = $state(false)
function openDescriptionPanel() {
openDescriptionSidebar({
openDescriptionPane({
title: party.name || '(untitled party)',
description: party.description,
videoUrl: party.videoUrl,
canEdit: canEdit(),
partyId: party.id,
partyShortcode: party.shortcode,

View file

@ -7,13 +7,24 @@
interface Props {
description?: string
videoUrl?: string
canEdit?: boolean
partyId?: string
partyShortcode?: string
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()
@ -43,9 +54,20 @@
})
</script>
<div class="description-sidebar">
<div class="description-pane">
<div class="content-section">
<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}
<div class="description-content">
<DescriptionRenderer content={description} truncate={false} />
@ -65,13 +87,25 @@
@use '$src/themes/typography' as *;
@use '$src/themes/effects' as *;
.description-sidebar {
.description-pane {
display: flex;
flex-direction: column;
height: 100%;
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 {
flex: 1;
overflow-y: auto;

View file

@ -1,20 +1,22 @@
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
description?: string | undefined
videoUrl?: string | undefined
canEdit?: boolean | undefined
partyId?: string | undefined
partyShortcode?: string | undefined
onSave?: ((description: string) => Promise<void>) | undefined
}
export function openDescriptionSidebar(options: DescriptionSidebarOptions) {
const { title, description, canEdit, partyId, partyShortcode, onSave } = options
export function openDescriptionPane(options: DescriptionPaneOptions) {
const { title, description, videoUrl, canEdit, partyId, partyShortcode, onSave } = options
sidebar.openWithComponent(title ?? '', DescriptionSidebar, {
sidebar.openWithComponent(title ?? '', DescriptionPane, {
description,
videoUrl,
canEdit,
partyId,
partyShortcode,
@ -22,6 +24,6 @@ export function openDescriptionSidebar(options: DescriptionSidebarOptions) {
})
}
export function closeDescriptionSidebar() {
export function closeDescriptionPane() {
sidebar.close()
}