refacor video upload (#138)

* refacor video upload

* remove unused imports
This commit is contained in:
Ilya Y 2023-07-19 14:00:58 +03:00 committed by GitHub
parent 8a2f8d2f98
commit 664adfc2dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 84 additions and 117 deletions

View File

@ -180,7 +180,12 @@ export const FullArticle = (props: ArticleProps) => {
<For each={media() || []}>
{(m: MediaItem) => (
<div class={styles.shoutMediaBody}>
<VideoPlayer videoUrl={m.url} title={m.title} description={m.body} />
<VideoPlayer
articleView={true}
videoUrl={m.url}
title={m.title}
description={m.body}
/>
<Show when={m?.body}>
<MD body={m.body} />
</Show>

View File

@ -2,32 +2,24 @@ import { clsx } from 'clsx'
import styles from './VideoUploader.module.scss'
import { useLocalize } from '../../../context/localize'
import { createDropzone } from '@solid-primitives/upload'
import { createEffect, createSignal, Show } from 'solid-js'
import { createSignal, For, Show } from 'solid-js'
import { useSnackbar } from '../../../context/snackbar'
import { validateUrl } from '../../../utils/validateUrl'
import { VideoPlayer } from '../../_shared/VideoPlayer'
import type { MediaItem } from '../../../pages/types'
// import { handleFileUpload } from '../../../utils/handleFileUpload'
import { composeMediaItems } from '../../../utils/composeMediaItems'
import { VideoPlayer } from '../../_shared/VideoPlayer'
type Props = {
class?: string
data: (value: MediaItem[]) => void
video: MediaItem[]
onVideoAdd: (value: MediaItem[]) => void
onVideoDelete: (mediaItemIndex: number) => void
}
export const VideoUploader = (props: Props) => {
const { t } = useLocalize()
const [dragActive, setDragActive] = createSignal(false)
const [dragError, setDragError] = createSignal<string>()
const [error, setError] = createSignal<string>()
const [incorrectUrl, setIncorrectUrl] = createSignal<boolean>(false)
const [data, setData] = createSignal<MediaItem>()
const updateData = (key, value) => {
setData((prev) => ({ ...prev, [key]: value }))
}
createEffect(() => {
props.data([data()])
})
const {
actions: { showSnackbar }
@ -39,97 +31,84 @@ export const VideoUploader = (props: Props) => {
current: null
}
// const [videoUrl, setVideoUrl] = createSignal<string | undefined>()
// const runUpload = async (file) => {
// try {
// const fileUrl = await handleFileUpload(file)
// setVideoUrl(fileUrl)
// } catch (error) {
// console.error('[runUpload]', error)
// }
// }
const { setRef: dropzoneRef, files: droppedFiles } = createDropzone({
onDrop: async () => {
setDragActive(false)
if (droppedFiles().length > 1) {
setDragError(t('Many files, choose only one'))
setError(t('Many files, choose only one'))
} else if (droppedFiles()[0].file.type.startsWith('video/')) {
await showSnackbar({
body: t(
'This functionality is currently not available, we would like to work on this issue. Use the download link.'
)
})
// await runUpload(droppedFiles()[0])
} else {
setDragError(t('Video format not supported'))
setError(t('Video format not supported'))
}
}
})
const handleDrag = (event) => {
if (event.type === 'dragenter' || event.type === 'dragover') {
setDragActive(true)
setDragError()
setError()
} else if (event.type === 'dragleave') {
setDragActive(false)
}
}
const handleUrlInput = async (value: string) => {
setError()
if (validateUrl(value)) {
updateData('url', value)
props.onVideoAdd(composeMediaItems([{ url: value }]))
} else {
setIncorrectUrl(true)
}
}
return (
<div class={clsx(styles.VideoUploader, props.class)}>
<Show
when={data() && data().url}
fallback={
<>
<div
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
onClick={() =>
showSnackbar({
body: t(
'This functionality is currently not available, we would like to work on this issue. Use the download link.'
)
})
}
ref={dropzoneRef}
class={clsx(styles.dropArea, { [styles.active]: dragActive() })}
>
<div class={styles.text}>{t('Upload video')}</div>
</div>
<Show when={dragError()}>
<div class={styles.error}>{dragError()}</div>
</Show>
<div class={styles.inputHolder}>
<input
class={clsx(styles.urlInput, { [styles.hasError]: incorrectUrl() })}
ref={(el) => (urlInput.current = el)}
type="text"
placeholder={t('Insert video link')}
onChange={(event) => handleUrlInput(event.currentTarget.value)}
/>
</div>
<Show when={incorrectUrl()}>
<div class={styles.error}>{t('It does not look like url')}</div>
</Show>
</>
}
>
<VideoPlayer
deleteAction={() => setData()}
videoUrl={data().url}
title={data().title}
description={data().body}
/>
</Show>
</div>
<Show
when={props.video.length === 0}
fallback={
<For each={props.video}>
{(mi, index) => (
<VideoPlayer onVideoDelete={() => props.onVideoDelete(index())} videoUrl={mi?.url} />
)}
</For>
}
>
<div class={styles.VideoUploader}>
<div
onDragEnter={handleDrag}
onDragLeave={handleDrag}
onDragOver={handleDrag}
onClick={() =>
showSnackbar({
body: t(
'This functionality is currently not available, we would like to work on this issue. Use the download link.'
)
})
}
ref={dropzoneRef}
class={clsx(styles.dropArea, { [styles.active]: dragActive() })}
>
<div class={styles.text}>{t('Upload video')}</div>
</div>
<Show when={error()}>
<div class={styles.error}>{error()}</div>
</Show>
<div class={styles.inputHolder}>
<input
class={clsx(styles.urlInput, { [styles.hasError]: incorrectUrl() })}
ref={(el) => (urlInput.current = el)}
type="text"
placeholder={t('Insert video link')}
onChange={(event) => handleUrlInput(event.currentTarget.value)}
/>
</div>
<Show when={incorrectUrl()}>
<div class={styles.error}>{t('It does not look like url')}</div>
</Show>
</div>
</Show>
)
}

View File

@ -1,9 +1,9 @@
import { For, Show, createSignal, createEffect, onMount, onCleanup } from 'solid-js'
import { Show, createSignal, createEffect, onMount, onCleanup } from 'solid-js'
import { Icon } from '../_shared/Icon'
import { Modal } from './Modal'
import { AuthModal } from './AuthModal'
import { useModalStore } from '../../stores/ui'
import { router, ROUTES, useRouter } from '../../stores/router'
import { router, useRouter } from '../../stores/router'
import styles from './Header.module.scss'
import { getPagePath } from '@nanostores/router'
import { clsx } from 'clsx'

View File

@ -1,4 +1,4 @@
import { Accessor, createMemo, createSignal, For, onCleanup, onMount, Show } from 'solid-js'
import { Accessor, createMemo, createSignal, onCleanup, onMount, Show } from 'solid-js'
import { useLocalize } from '../../context/localize'
import { clsx } from 'clsx'
import { Title } from '@solidjs/meta'
@ -17,7 +17,6 @@ import { imageProxy } from '../../utils/imageProxy'
import { GrowingTextarea } from '../_shared/GrowingTextarea'
import { VideoUploader } from '../Editor/VideoUploader'
import { AudioUploader } from '../Editor/AudioUploader'
import { VideoPlayer } from '../_shared/VideoPlayer'
import { slugify } from '../../utils/slugify'
import { SolidSwiper } from '../_shared/SolidSwiper'
import { DropArea } from '../_shared/DropArea'
@ -136,7 +135,7 @@ export const EditView = (props: Props) => {
setForm('media', JSON.stringify(data))
}
const handleImageDelete = (index) => {
const handleMediaDelete = (index) => {
const copy = [...mediaItems()]
copy.splice(index, 1)
setForm('media', JSON.stringify(copy))
@ -307,36 +306,18 @@ export const EditView = (props: Props) => {
editorMode={true}
images={mediaItems()}
onImageChange={handleMediaChange}
onImageDelete={(index) => handleImageDelete(index)}
onImageDelete={(index) => handleMediaDelete(index)}
onImagesAdd={(value) => handleAddMedia(value)}
onImagesSorted={(value) => handleSortedMedia(value)}
/>
</Show>
<Show when={props.shout.layout === 'video'}>
<Show
when={form.media}
fallback={
<VideoUploader
data={(data) => {
handleAddMedia(data)
}}
/>
}
>
<For each={mediaItems()}>
{(mediaItem) => (
<>
<VideoPlayer
videoUrl={mediaItem?.url}
title={mediaItem?.title}
description={mediaItem?.body}
deleteAction={() => setForm('media', null)}
/>
</>
)}
</For>
</Show>
<VideoUploader
video={mediaItems()}
onVideoAdd={(data) => handleAddMedia(data)}
onVideoDelete={(index) => handleMediaDelete(index)}
/>
</Show>
<Show when={props.shout.layout === 'audio'}>

View File

@ -25,7 +25,6 @@ interface Props {
export const Slider = (props: Props) => {
let el: HTMLDivElement | undefined
let thumbsEl: HTMLDivElement | undefined
let pagEl: HTMLDivElement | undefined
let nextEl: HTMLDivElement | undefined
let prevEl: HTMLDivElement | undefined

View File

@ -3,11 +3,13 @@
flex-direction: column;
align-items: center;
justify-content: center;
margin: 1rem 0;
margin: 1rem auto;
position: relative;
@include media-breakpoint-up(md) {
margin: 1rem -16.6666% 2rem -25%;
&.articleView {
@include media-breakpoint-up(md) {
margin: 1rem -16.6666% 2rem -25%;
}
}
.controls {

View File

@ -11,7 +11,8 @@ type Props = {
title?: string
description?: string
class?: string
deleteAction?: () => void
onVideoDelete?: () => void
articleView?: boolean
}
export const VideoPlayer = (props: Props) => {
@ -37,15 +38,15 @@ export const VideoPlayer = (props: Props) => {
})
return (
<div class={clsx(styles.VideoPlayer, props.class)}>
<Show when={props.deleteAction}>
<div class={clsx(styles.VideoPlayer, props.class, { [styles.articleView]: props.articleView })}>
<Show when={props.onVideoDelete}>
<Popover content={t('Delete')}>
{(triggerRef: (el) => void) => (
<Button
ref={triggerRef}
size="S"
class={styles.deleteAction}
onClick={props.deleteAction}
onClick={() => props.onVideoDelete()}
value={<Icon class={styles.deleteIcon} name="delete" />}
/>
)}

View File

@ -45,5 +45,5 @@ export type MediaItem = {
export type UploadedFile = {
url: string
originalFilename: string
originalFilename?: string
}

View File

@ -9,7 +9,7 @@ export const composeMediaItems = (value: UploadedFile[], optionalParams = {}) =>
return {
url: fileData.url,
source: '',
title: removeFileExtension(fileData.originalFilename),
title: fileData.originalFilename ? removeFileExtension(fileData.originalFilename) : '',
body: '',
...optionalParams
}