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:
AkiraFukushima 2023-12-29 12:47:28 +09:00 committed by GitHub
commit 77d47478aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 97 additions and 1 deletions

View File

@ -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": {

View File

@ -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>
) )
} }

View File

@ -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>
)
}