From 83e428d10b886f20de81ef9646a69fffbbbb1f19 Mon Sep 17 00:00:00 2001 From: Scott Feeney Date: Fri, 11 Oct 2024 18:06:19 -0700 Subject: [PATCH] Drag-drop to reorder media --- src/components/compose.css | 3 + src/components/compose.jsx | 51 ++++++++++- src/locales/en.po | 174 ++++++++++++++++++------------------- 3 files changed, 140 insertions(+), 88 deletions(-) diff --git a/src/components/compose.css b/src/components/compose.css index d62de4701f..f27d83bd06 100644 --- a/src/components/compose.css +++ b/src/components/compose.css @@ -377,6 +377,9 @@ background-size: 10px 10px; background-position: 0 0, 0 5px, 5px -5px, -5px 0px; } +#compose-container .media-preview.dragging-over { + opacity: 0.5; +} #compose-container .media-preview > * { width: 80px; height: 80px; diff --git a/src/components/compose.jsx b/src/components/compose.jsx index ea7574aff8..04a0e1ac47 100644 --- a/src/components/compose.jsx +++ b/src/components/compose.jsx @@ -254,6 +254,8 @@ function Compose({ ); const prevLanguage = useRef(language); const [mediaAttachments, setMediaAttachments] = useState([]); + const [draggingAttachment, setDraggingAttachment] = useState(null); + const [draggingOver, setDraggingOver] = useState(null); const [poll, setPoll] = useState(null); const prefs = store.account.get('preferences') || {}; @@ -1252,6 +1254,40 @@ function Compose({ return newAttachments; }); }} + draggingOver={draggingOver === i} + onDragStart={(e) => { + setDraggingAttachment(i); + e.dataTransfer.dropEffect = 'move'; + }} + onDragEnter={() => setDraggingOver(i)} + onDragLeave={() => setDraggingOver(null)} + onDragEnd={() => { + setDraggingAttachment(null); + setDraggingOver(null); + }} + onDrop={(e) => { + const from = draggingAttachment; + const to = i; + if (from == null || from === to) return; + setMediaAttachments((attachments) => { + if (to < from) { + return [ + ...attachments.slice(0, to), + attachments[from], + ...attachments.slice(to, from), + ...attachments.slice(from + 1), + ]; + } else { + return [ + ...attachments.slice(0, from), + ...attachments.slice(from + 1, to + 1), + attachments[from], + ...attachments.slice(to + 1), + ]; + } + }); + e.stopPropagation(); + }} onRemove={() => { setMediaAttachments((attachments) => { return attachments.filter((_, j) => j !== i); @@ -2114,6 +2150,12 @@ function MediaAttachment({ disabled, lang, onDescriptionChange = () => {}, + draggingOver, + onDragStart, + onDragEnd, + onDragEnter, + onDragLeave, + onDrop, onRemove = () => {}, }) { const { i18n } = useLingui(); @@ -2329,8 +2371,15 @@ function MediaAttachment({ <>
e.preventDefault()} + onDrop={onDrop} onClick={() => { setShowModal(true); }} diff --git a/src/locales/en.po b/src/locales/en.po index cd31af4ab0..2ca38b538a 100644 --- a/src/locales/en.po +++ b/src/locales/en.po @@ -105,7 +105,7 @@ msgstr "" #: src/components/account-info.jsx:427 #: src/components/account-info.jsx:1115 -#: src/components/compose.jsx:2463 +#: src/components/compose.jsx:2512 #: src/components/media-alt-modal.jsx:45 #: src/components/media-modal.jsx:283 #: src/components/status.jsx:1703 @@ -400,11 +400,11 @@ msgstr "" #: src/components/account-info.jsx:1989 #: src/components/account-info.jsx:2089 #: src/components/account-sheet.jsx:37 -#: src/components/compose.jsx:797 -#: src/components/compose.jsx:2419 -#: src/components/compose.jsx:2892 -#: src/components/compose.jsx:3100 -#: src/components/compose.jsx:3330 +#: src/components/compose.jsx:799 +#: src/components/compose.jsx:2468 +#: src/components/compose.jsx:2941 +#: src/components/compose.jsx:3149 +#: src/components/compose.jsx:3379 #: src/components/drafts.jsx:58 #: src/components/embed-modal.jsx:12 #: src/components/generic-accounts.jsx:142 @@ -541,135 +541,135 @@ msgstr "" msgid "Compose" msgstr "" -#: src/components/compose.jsx:392 +#: src/components/compose.jsx:394 msgid "You have unsaved changes. Discard this post?" msgstr "" -#: src/components/compose.jsx:614 -#: src/components/compose.jsx:630 -#: src/components/compose.jsx:1337 -#: src/components/compose.jsx:1598 +#: src/components/compose.jsx:616 +#: src/components/compose.jsx:632 +#: src/components/compose.jsx:1373 +#: src/components/compose.jsx:1634 msgid "{maxMediaAttachments, plural, one {You can only attach up to 1 file.} other {You can only attach up to # files.}}" msgstr "" -#: src/components/compose.jsx:778 +#: src/components/compose.jsx:780 msgid "Pop out" msgstr "" -#: src/components/compose.jsx:785 +#: src/components/compose.jsx:787 msgid "Minimize" msgstr "" -#: src/components/compose.jsx:821 +#: src/components/compose.jsx:823 msgid "Looks like you closed the parent window." msgstr "" -#: src/components/compose.jsx:828 +#: src/components/compose.jsx:830 msgid "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later." msgstr "" -#: src/components/compose.jsx:833 +#: src/components/compose.jsx:835 msgid "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?" msgstr "" -#: src/components/compose.jsx:875 +#: src/components/compose.jsx:877 msgid "Pop in" msgstr "" -#: src/components/compose.jsx:885 +#: src/components/compose.jsx:887 msgid "Replying to @{0}’s post (<0>{1})" msgstr "" -#: src/components/compose.jsx:895 +#: src/components/compose.jsx:897 msgid "Replying to @{0}’s post" msgstr "" -#: src/components/compose.jsx:908 +#: src/components/compose.jsx:910 msgid "Editing source post" msgstr "" -#: src/components/compose.jsx:955 +#: src/components/compose.jsx:957 msgid "Poll must have at least 2 options" msgstr "" -#: src/components/compose.jsx:959 +#: src/components/compose.jsx:961 msgid "Some poll choices are empty" msgstr "" -#: src/components/compose.jsx:972 +#: src/components/compose.jsx:974 msgid "Some media have no descriptions. Continue?" msgstr "" -#: src/components/compose.jsx:1024 +#: src/components/compose.jsx:1026 msgid "Attachment #{i} failed" msgstr "" -#: src/components/compose.jsx:1118 +#: src/components/compose.jsx:1120 #: src/components/status.jsx:2029 #: src/components/timeline.jsx:984 msgid "Content warning" msgstr "" -#: src/components/compose.jsx:1134 +#: src/components/compose.jsx:1136 msgid "Content warning or sensitive media" msgstr "" -#: src/components/compose.jsx:1170 +#: src/components/compose.jsx:1172 #: src/components/status.jsx:93 #: src/pages/settings.jsx:304 msgid "Public" msgstr "" -#: src/components/compose.jsx:1175 +#: src/components/compose.jsx:1177 #: src/components/nav-menu.jsx:386 #: src/components/shortcuts-settings.jsx:162 #: src/components/status.jsx:94 msgid "Local" msgstr "" -#: src/components/compose.jsx:1179 +#: src/components/compose.jsx:1181 #: src/components/status.jsx:95 #: src/pages/settings.jsx:307 msgid "Unlisted" msgstr "" -#: src/components/compose.jsx:1182 +#: src/components/compose.jsx:1184 #: src/components/status.jsx:96 #: src/pages/settings.jsx:310 msgid "Followers only" msgstr "" -#: src/components/compose.jsx:1185 +#: src/components/compose.jsx:1187 #: src/components/status.jsx:97 #: src/components/status.jsx:1907 msgid "Private mention" msgstr "" -#: src/components/compose.jsx:1194 +#: src/components/compose.jsx:1196 msgid "Post your reply" msgstr "" -#: src/components/compose.jsx:1196 +#: src/components/compose.jsx:1198 msgid "Edit your post" msgstr "" -#: src/components/compose.jsx:1197 +#: src/components/compose.jsx:1199 msgid "What are you doing?" msgstr "" -#: src/components/compose.jsx:1275 +#: src/components/compose.jsx:1311 msgid "Mark media as sensitive" msgstr "" -#: src/components/compose.jsx:1373 +#: src/components/compose.jsx:1409 msgid "Add poll" msgstr "" -#: src/components/compose.jsx:1395 +#: src/components/compose.jsx:1431 msgid "Add custom emoji" msgstr "" -#: src/components/compose.jsx:1479 +#: src/components/compose.jsx:1515 #: src/components/keyboard-shortcuts-help.jsx:143 #: src/components/status.jsx:895 #: src/components/status.jsx:1683 @@ -678,195 +678,195 @@ msgstr "" msgid "Reply" msgstr "" -#: src/components/compose.jsx:1481 +#: src/components/compose.jsx:1517 msgid "Update" msgstr "" -#: src/components/compose.jsx:1482 +#: src/components/compose.jsx:1518 msgctxt "Submit button in composer" msgid "Post" msgstr "" -#: src/components/compose.jsx:1610 +#: src/components/compose.jsx:1646 msgid "Downloading GIF…" msgstr "" -#: src/components/compose.jsx:1638 +#: src/components/compose.jsx:1674 msgid "Failed to download GIF" msgstr "" -#: src/components/compose.jsx:1750 -#: src/components/compose.jsx:1827 +#: src/components/compose.jsx:1786 +#: src/components/compose.jsx:1863 #: src/components/nav-menu.jsx:287 msgid "More…" msgstr "" -#: src/components/compose.jsx:2232 +#: src/components/compose.jsx:2274 msgid "Uploaded" msgstr "" -#: src/components/compose.jsx:2245 +#: src/components/compose.jsx:2287 msgid "Image description" msgstr "" -#: src/components/compose.jsx:2246 +#: src/components/compose.jsx:2288 msgid "Video description" msgstr "" -#: src/components/compose.jsx:2247 +#: src/components/compose.jsx:2289 msgid "Audio description" msgstr "" -#: src/components/compose.jsx:2283 -#: src/components/compose.jsx:2303 +#: src/components/compose.jsx:2325 +#: src/components/compose.jsx:2345 msgid "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower." msgstr "" -#: src/components/compose.jsx:2295 -#: src/components/compose.jsx:2315 +#: src/components/compose.jsx:2337 +#: src/components/compose.jsx:2357 msgid "Dimension too large. Uploading might encounter issues. Try reduce dimension from {0}×{1}px to {2}×{3}px." msgstr "" -#: src/components/compose.jsx:2323 +#: src/components/compose.jsx:2365 msgid "Frame rate too high. Uploading might encounter issues." msgstr "" -#: src/components/compose.jsx:2383 -#: src/components/compose.jsx:2633 +#: src/components/compose.jsx:2432 +#: src/components/compose.jsx:2682 #: src/components/shortcuts-settings.jsx:723 #: src/pages/catchup.jsx:1074 #: src/pages/filters.jsx:412 msgid "Remove" msgstr "" -#: src/components/compose.jsx:2400 +#: src/components/compose.jsx:2449 #: src/compose.jsx:83 msgid "Error" msgstr "" -#: src/components/compose.jsx:2425 +#: src/components/compose.jsx:2474 msgid "Edit image description" msgstr "" -#: src/components/compose.jsx:2426 +#: src/components/compose.jsx:2475 msgid "Edit video description" msgstr "" -#: src/components/compose.jsx:2427 +#: src/components/compose.jsx:2476 msgid "Edit audio description" msgstr "" -#: src/components/compose.jsx:2472 #: src/components/compose.jsx:2521 +#: src/components/compose.jsx:2570 msgid "Generating description. Please wait…" msgstr "" -#: src/components/compose.jsx:2492 +#: src/components/compose.jsx:2541 msgid "Failed to generate description: {0}" msgstr "" -#: src/components/compose.jsx:2493 +#: src/components/compose.jsx:2542 msgid "Failed to generate description" msgstr "" -#: src/components/compose.jsx:2505 -#: src/components/compose.jsx:2511 -#: src/components/compose.jsx:2557 +#: src/components/compose.jsx:2554 +#: src/components/compose.jsx:2560 +#: src/components/compose.jsx:2606 msgid "Generate description…" msgstr "" -#: src/components/compose.jsx:2544 +#: src/components/compose.jsx:2593 msgid "Failed to generate description{0}" msgstr "" -#: src/components/compose.jsx:2559 +#: src/components/compose.jsx:2608 msgid "({0}) <0>— experimental" msgstr "" -#: src/components/compose.jsx:2578 +#: src/components/compose.jsx:2627 msgid "Done" msgstr "" -#: src/components/compose.jsx:2614 +#: src/components/compose.jsx:2663 msgid "Choice {0}" msgstr "" -#: src/components/compose.jsx:2661 +#: src/components/compose.jsx:2710 msgid "Multiple choices" msgstr "" -#: src/components/compose.jsx:2664 +#: src/components/compose.jsx:2713 msgid "Duration" msgstr "" -#: src/components/compose.jsx:2695 +#: src/components/compose.jsx:2744 msgid "Remove poll" msgstr "" -#: src/components/compose.jsx:2909 +#: src/components/compose.jsx:2958 msgid "Search accounts" msgstr "" -#: src/components/compose.jsx:2950 +#: src/components/compose.jsx:2999 #: src/components/shortcuts-settings.jsx:712 #: src/pages/list.jsx:359 msgid "Add" msgstr "" -#: src/components/compose.jsx:2963 +#: src/components/compose.jsx:3012 #: src/components/generic-accounts.jsx:227 msgid "Error loading accounts" msgstr "" -#: src/components/compose.jsx:3106 +#: src/components/compose.jsx:3155 msgid "Custom emojis" msgstr "" -#: src/components/compose.jsx:3126 +#: src/components/compose.jsx:3175 msgid "Search emoji" msgstr "" -#: src/components/compose.jsx:3157 +#: src/components/compose.jsx:3206 msgid "Error loading custom emojis" msgstr "" -#: src/components/compose.jsx:3168 +#: src/components/compose.jsx:3217 msgid "Recently used" msgstr "" -#: src/components/compose.jsx:3169 +#: src/components/compose.jsx:3218 msgid "Others" msgstr "" -#: src/components/compose.jsx:3207 +#: src/components/compose.jsx:3256 msgid "{0} more…" msgstr "" -#: src/components/compose.jsx:3345 +#: src/components/compose.jsx:3394 msgid "Search GIFs" msgstr "" -#: src/components/compose.jsx:3360 +#: src/components/compose.jsx:3409 msgid "Powered by GIPHY" msgstr "" -#: src/components/compose.jsx:3368 +#: src/components/compose.jsx:3417 msgid "Type to search GIFs" msgstr "" -#: src/components/compose.jsx:3466 +#: src/components/compose.jsx:3515 #: src/components/media-modal.jsx:387 #: src/components/timeline.jsx:889 msgid "Previous" msgstr "" -#: src/components/compose.jsx:3484 +#: src/components/compose.jsx:3533 #: src/components/media-modal.jsx:406 #: src/components/timeline.jsx:906 msgid "Next" msgstr "" -#: src/components/compose.jsx:3501 +#: src/components/compose.jsx:3550 msgid "Error loading GIFs" msgstr ""