Merge pull request #4728 from h3poteto/iss-4653/image-description
refs #4653 Add edit media to apply description for the media
This commit is contained in:
commit
77d47478aa
|
@ -96,6 +96,11 @@
|
||||||
"3d": "3 days",
|
"3d": "3 days",
|
||||||
"7d": "7 days",
|
"7d": "7 days",
|
||||||
"multiple": "multiple"
|
"multiple": "multiple"
|
||||||
|
},
|
||||||
|
"edit_media": {
|
||||||
|
"title": "Edit media",
|
||||||
|
"label": "Describe for people who are blind or have low vision",
|
||||||
|
"submit": "Apply"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"alert": {
|
"alert": {
|
||||||
|
|
|
@ -14,11 +14,23 @@ import {
|
||||||
} from 'flowbite-react'
|
} from 'flowbite-react'
|
||||||
import { ChangeEvent, Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'
|
import { ChangeEvent, Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { FormattedMessage, useIntl } from 'react-intl'
|
import { FormattedMessage, useIntl } from 'react-intl'
|
||||||
import { FaEnvelope, FaFaceLaughBeam, FaGlobe, FaListCheck, FaLock, FaLockOpen, FaPaperPlane, FaPaperclip, FaXmark } from 'react-icons/fa6'
|
import {
|
||||||
|
FaEnvelope,
|
||||||
|
FaFaceLaughBeam,
|
||||||
|
FaGlobe,
|
||||||
|
FaListCheck,
|
||||||
|
FaLock,
|
||||||
|
FaLockOpen,
|
||||||
|
FaPaperPlane,
|
||||||
|
FaPaperclip,
|
||||||
|
FaPencil,
|
||||||
|
FaXmark
|
||||||
|
} from 'react-icons/fa6'
|
||||||
import { Entity, MegalodonInterface } from 'megalodon'
|
import { Entity, MegalodonInterface } from 'megalodon'
|
||||||
import { useToast } from '@/utils/toast'
|
import { useToast } from '@/utils/toast'
|
||||||
import Picker from '@emoji-mart/react'
|
import Picker from '@emoji-mart/react'
|
||||||
import { data } from '@/utils/emojiData'
|
import { data } from '@/utils/emojiData'
|
||||||
|
import EditMedia from './EditMedia'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
client: MegalodonInterface
|
client: MegalodonInterface
|
||||||
|
@ -50,6 +62,7 @@ export default function Compose(props: Props) {
|
||||||
const [attachments, setAttachments] = useState<Array<Entity.Attachment | Entity.AsyncAttachment>>([])
|
const [attachments, setAttachments] = useState<Array<Entity.Attachment | Entity.AsyncAttachment>>([])
|
||||||
const [poll, setPoll] = useState<Poll | null>(null)
|
const [poll, setPoll] = useState<Poll | null>(null)
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [editMedia, setEditMedia] = useState<Entity.Attachment>()
|
||||||
|
|
||||||
const { formatMessage } = useIntl()
|
const { formatMessage } = useIntl()
|
||||||
const uploaderRef = useRef(null)
|
const uploaderRef = useRef(null)
|
||||||
|
@ -164,6 +177,14 @@ export default function Compose(props: Props) {
|
||||||
setAttachments(current => current.filter((_, i) => i !== index))
|
setAttachments(current => current.filter((_, i) => i !== index))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const openDescription = (index: number) => {
|
||||||
|
setEditMedia(attachments[index])
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeDescription = () => {
|
||||||
|
setEditMedia(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
const togglePoll = () => {
|
const togglePoll = () => {
|
||||||
if (poll) {
|
if (poll) {
|
||||||
setPoll(null)
|
setPoll(null)
|
||||||
|
@ -233,6 +254,9 @@ export default function Compose(props: Props) {
|
||||||
<button className="absolute bg-gray-600 rounded" onClick={() => removeFile(index)}>
|
<button className="absolute bg-gray-600 rounded" onClick={() => removeFile(index)}>
|
||||||
<FaXmark className="text-gray-200" />
|
<FaXmark className="text-gray-200" />
|
||||||
</button>
|
</button>
|
||||||
|
<button className="absolute right-0 bg-gray-600 rounded" onClick={() => openDescription(index)}>
|
||||||
|
<FaPencil className="text-gray-200" />
|
||||||
|
</button>
|
||||||
<img src={f.preview_url} style={{ width: '80px', height: '80px' }} className="rounded-md" />
|
<img src={f.preview_url} style={{ width: '80px', height: '80px' }} className="rounded-md" />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -281,6 +305,7 @@ export default function Compose(props: Props) {
|
||||||
{loading ? <Spinner size="sm" /> : <FaPaperPlane className="text-gray-400 hover:text-gray-600 cursor-pointer" onClick={post} />}
|
{loading ? <Spinner size="sm" /> : <FaPaperPlane className="text-gray-400 hover:text-gray-600 cursor-pointer" onClick={post} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<EditMedia media={editMedia} close={closeDescription} client={props.client} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { Label, Modal, Textarea, Button } from 'flowbite-react'
|
||||||
|
import { Entity, MegalodonInterface } from 'megalodon'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { FormattedMessage } from 'react-intl'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
media: Entity.Attachment | undefined
|
||||||
|
close: () => void
|
||||||
|
client: MegalodonInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function EditMedia(props: Props) {
|
||||||
|
const [description, setDescription] = useState('')
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.media) {
|
||||||
|
const f = async () => {
|
||||||
|
const res = await props.client.getMedia(props.media.id)
|
||||||
|
if (res.data.description) {
|
||||||
|
setDescription(res.data.description)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}, [props.media, props.client])
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
if (!props.media || !props.client) return
|
||||||
|
await props.client.updateMedia(props.media.id, {
|
||||||
|
description: description
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClose = () => {
|
||||||
|
setDescription('')
|
||||||
|
props.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal show={props.media !== undefined} onClose={onClose} size="2xl">
|
||||||
|
{props.media && (
|
||||||
|
<>
|
||||||
|
<Modal.Header>
|
||||||
|
<FormattedMessage id="compose.edit_media.title" />
|
||||||
|
</Modal.Header>
|
||||||
|
<Modal.Body className="max-h-full max-w-full">
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div className="w-1/4">
|
||||||
|
<Label htmlFor="description" className="mb-2 block">
|
||||||
|
<FormattedMessage id="compose.edit_media.label" />
|
||||||
|
</Label>
|
||||||
|
<Textarea id="description" rows={4} value={description} onChange={ev => setDescription(ev.target.value)} />
|
||||||
|
<Button className="mt-2" onClick={submit}>
|
||||||
|
<FormattedMessage id="compose.edit_media.submit" />
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div className="w-3/4">
|
||||||
|
<img src={props.media.preview_url} className="object-cover m-auto" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal.Body>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue