2023-07-15 06:18:20 +00:00
|
|
|
import { createSignal, For, Show } from 'solid-js'
|
2023-07-01 13:05:59 +00:00
|
|
|
import { SharePopup, getShareUrl } from '../SharePopup'
|
|
|
|
import { getDescription } from '../../../utils/meta'
|
|
|
|
import { useLocalize } from '../../../context/localize'
|
2023-07-14 13:06:21 +00:00
|
|
|
import type { Audio } from './AudioPlayer'
|
2023-07-01 13:05:59 +00:00
|
|
|
import { Popover } from '../../_shared/Popover'
|
|
|
|
import { Icon } from '../../_shared/Icon'
|
|
|
|
import styles from './AudioPlayer.module.scss'
|
2023-07-14 13:06:21 +00:00
|
|
|
import { GrowingTextarea } from '../../_shared/GrowingTextarea'
|
|
|
|
import MD from '../MD'
|
2023-07-01 13:05:59 +00:00
|
|
|
|
2023-07-14 13:06:21 +00:00
|
|
|
type Props = {
|
|
|
|
tracks: Audio[]
|
|
|
|
currentTrack: Audio
|
|
|
|
playMedia: (audio: Audio) => void
|
|
|
|
articleSlug?: string
|
|
|
|
body?: string
|
|
|
|
editorMode?: boolean
|
|
|
|
onAudioChange?: (index: number, field: string, value: string) => void
|
|
|
|
}
|
|
|
|
|
|
|
|
export const PlayerPlaylist = (props: Props) => {
|
2023-07-01 13:05:59 +00:00
|
|
|
const { t } = useLocalize()
|
2023-07-14 13:06:21 +00:00
|
|
|
const [activeEditIndex, setActiveEditIndex] = createSignal(-1)
|
2023-07-01 13:05:59 +00:00
|
|
|
|
2023-07-14 13:06:21 +00:00
|
|
|
const toggleDropDown = (index) => {
|
|
|
|
setActiveEditIndex(activeEditIndex() === index ? -1 : index)
|
|
|
|
}
|
|
|
|
const updateData = (key, value) => {
|
|
|
|
props.onAudioChange(activeEditIndex(), key, value)
|
|
|
|
}
|
2023-07-01 13:05:59 +00:00
|
|
|
|
|
|
|
return (
|
|
|
|
<ul class={styles.playlist}>
|
2023-07-14 13:06:21 +00:00
|
|
|
<For each={props.tracks}>
|
|
|
|
{(m: Audio, index) => (
|
|
|
|
<li>
|
|
|
|
<div class={styles.playlistItem}>
|
|
|
|
<button
|
|
|
|
class={styles.playlistItemPlayButton}
|
|
|
|
onClick={() => props.playMedia(m)}
|
|
|
|
type="button"
|
|
|
|
aria-label="Play"
|
|
|
|
>
|
|
|
|
<Icon
|
|
|
|
name={
|
|
|
|
props.currentTrack &&
|
|
|
|
props.currentTrack.index === m.index &&
|
|
|
|
props.currentTrack.isPlaying
|
|
|
|
? 'pause'
|
|
|
|
: 'play'
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</button>
|
|
|
|
<div class={styles.playlistItemText}>
|
|
|
|
<Show
|
|
|
|
when={activeEditIndex() === index() && props.editorMode}
|
|
|
|
fallback={
|
|
|
|
<>
|
|
|
|
<div class={styles.title}>
|
|
|
|
{m.title.replace(/\.(wav|flac|mp3|aac)$/i, '') || t('Song title')}
|
|
|
|
</div>
|
|
|
|
<div class={styles.artist}>{m.artist || t('Artist')}</div>
|
|
|
|
</>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
value={m.title}
|
|
|
|
class={styles.title}
|
|
|
|
placeholder={t('Song title')}
|
|
|
|
onChange={(e) => updateData('title', e.target.value)}
|
|
|
|
/>
|
|
|
|
<input
|
|
|
|
type="text"
|
|
|
|
value={m.artist}
|
|
|
|
class={styles.artist}
|
|
|
|
placeholder={t('Artist')}
|
|
|
|
onChange={(e) => updateData('artist', e.target.value)}
|
|
|
|
/>
|
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
<div class={styles.actions}>
|
|
|
|
<Show when={(m.lyrics || m.body) && !props.editorMode}>
|
|
|
|
<Popover content={t('Show lyrics')}>
|
|
|
|
{(triggerRef: (el) => void) => (
|
|
|
|
<button ref={triggerRef} type="button" onClick={() => toggleDropDown(index())}>
|
|
|
|
<Icon name="list" />
|
|
|
|
</button>
|
|
|
|
)}
|
|
|
|
</Popover>
|
|
|
|
</Show>
|
|
|
|
<Popover content={props.editorMode ? t('Edit') : t('Share')}>
|
|
|
|
{(triggerRef: (el) => void) => (
|
|
|
|
<div ref={triggerRef}>
|
|
|
|
<Show
|
|
|
|
when={!props.editorMode}
|
|
|
|
fallback={
|
|
|
|
<button type="button" onClick={() => toggleDropDown(index())}>
|
|
|
|
<Icon name="pencil-stroke" />
|
|
|
|
</button>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<SharePopup
|
|
|
|
title={m.title}
|
|
|
|
description={getDescription(props.body)}
|
|
|
|
imageUrl={m.pic}
|
|
|
|
shareUrl={getShareUrl({ pathname: `/${props.articleSlug}` })}
|
|
|
|
trigger={
|
|
|
|
<div>
|
|
|
|
<Icon name="share-media" />
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
</Popover>
|
|
|
|
</div>
|
2023-07-01 13:05:59 +00:00
|
|
|
</div>
|
2023-07-14 13:06:21 +00:00
|
|
|
<Show when={activeEditIndex() === index()}>
|
|
|
|
<Show
|
|
|
|
when={props.editorMode}
|
|
|
|
fallback={
|
|
|
|
<div class={styles.descriptionBlock}>
|
|
|
|
<Show when={m.body}>
|
|
|
|
<div class={styles.description}>
|
|
|
|
<MD body={m.body} />
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
<Show when={m.lyrics}>
|
|
|
|
<div class={styles.lyrics}>
|
|
|
|
<MD body={m.lyrics} />
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
</div>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<div class={styles.descriptionBlock}>
|
|
|
|
<GrowingTextarea
|
|
|
|
allowEnterKey={true}
|
|
|
|
class={styles.description}
|
|
|
|
placeholder={t('Description')}
|
|
|
|
value={(value) => updateData('body', value)}
|
|
|
|
initialValue={m.body || ''}
|
|
|
|
/>
|
|
|
|
<GrowingTextarea
|
|
|
|
allowEnterKey={true}
|
|
|
|
class={styles.lyrics}
|
|
|
|
placeholder={t('Song lyrics')}
|
|
|
|
value={(value) => updateData('lyrics', value)}
|
|
|
|
initialValue={m.lyrics || ''}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
</Show>
|
|
|
|
</Show>
|
2023-07-01 13:05:59 +00:00
|
|
|
</li>
|
|
|
|
)}
|
|
|
|
</For>
|
|
|
|
</ul>
|
|
|
|
)
|
|
|
|
}
|