1
0
Fork 0
freesewing/sites/org/components/github/inputs.mjs
2023-08-15 18:45:25 +02:00

147 lines
4 KiB
JavaScript

// Dependencies
import { slugify, slugifyNoTrim, cloudflareImageUrl } from 'shared/utils.mjs'
// Hooks
import { useTranslation } from 'react-i18next'
import { useEffect, useState, useCallback } from 'react'
import { useBackend } from 'shared/hooks/use-backend.mjs'
import { useToast } from 'shared/hooks/use-toast.mjs'
import { useDropzone } from 'react-dropzone'
import { Popout } from 'shared/components/popout/index.mjs'
import { Loading } from 'shared/components/spinner.mjs'
export const ns = ['account']
export const CaptionInput = ({ caption, setCaption }) => (
<input
className="input input-text input-bordered input-lg w-full"
value={caption}
placeholder="Type your caption here"
onChange={(evt) => setCaption(evt.target.value)}
/>
)
export const IntroInput = ({ intro, setIntro }) => (
<input
className="input input-text input-bordered input-lg w-full"
value={intro}
placeholder="Type your intro here"
onChange={(evt) => setIntro(evt.target.value)}
/>
)
export const BodyInput = ({ body, setBody }) => (
<textarea
className="input input-text input-bordered input-lg w-full h-96"
placeholder="Type your post body here"
onChange={(evt) => setBody(evt.target.value)}
rows={16}
>
{body}
</textarea>
)
export const TitleInput = ({ title, setTitle }) => (
<input
className="input input-text input-bordered input-lg w-full"
value={title}
placeholder="Type your title here"
onChange={(evt) => setTitle(evt.target.value)}
/>
)
export const SlugInput = ({ slug, setSlug, title }) => {
useEffect(() => {
if (title !== slug) setSlug(slugify(title))
}, [title])
return (
<input
className="input input-text input-bordered input-lg w-full mb-2"
value={slug}
placeholder="Type your title here"
onChange={(evt) => setSlug(slugifyNoTrim(evt.target.value))}
/>
)
}
export const ImageInput = ({ slug = false, setImg, img, type = 'showcase', subId = false }) => {
const backend = useBackend()
const toast = useToast()
const { t } = useTranslation(ns)
const [uploading, setUploading] = useState(false)
const onDrop = useCallback(
(acceptedFiles) => {
const reader = new FileReader()
reader.onload = async () => {
setUploading(true)
const result = await backend.uploadImage({ type, subId, slug, img: reader.result })
setUploading(false)
if (result.success) setImg(result.data.imgId)
}
acceptedFiles.forEach((file) => reader.readAsDataURL(file))
},
[slug]
)
const { getRootProps, getInputProps } = useDropzone({ onDrop })
const removeImage = async () => {
setUploading(true)
const result = await backend.removeImage(img)
setUploading(false)
if (result.response.status === 204) setImg('')
}
if (!slug)
return (
<Popout note compact>
A <b>slug</b> is mandatory
</Popout>
)
if (!subId)
return (
<Popout note compact>
A <b>subId</b> prop is mandatory
</Popout>
)
if (uploading) return <Loading />
if (img)
return (
<div>
<div
className="bg-base-100 w-full h-36 mb-2"
style={{
backgroundImage: `url(${cloudflareImageUrl({
id: img,
variant: 'sq500',
})})`,
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
}}
></div>
<button className="btn btn-error btn-sm" onClick={removeImage}>
Remove Image
</button>
</div>
)
return (
<div>
<div
{...getRootProps()}
className={`
flex rounded-lg w-full flex-col items-center justify-center
lg:h-64 lg:border-4 lg:border-secondary lg:border-dashed
`}
>
<input {...getInputProps()} />
<p className="hidden lg:block p-0 m-0">{t('imgDragAndDropImageHere')}</p>
<p className="hidden lg:block p-0 my-2">{t('or')}</p>
<button className={`btn btn-secondary btn-outline mt-4 px-8`}>{t('imgSelectImage')}</button>
</div>
</div>
)
}