diff --git a/package.json b/package.json index ca713de..09fb155 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@cyntler/react-doc-viewer": "^1.14.1", "@tauri-apps/api": "^1", "@tauri-apps/plugin-updater": "^2.0.0-beta.2", + "@types/react-beautiful-dnd": "^13.1.8", "@types/react-highlight": "^0.12.8", "@types/react-syntax-highlighter": "^15.5.11", "antd": "^5.14.2", @@ -25,6 +26,7 @@ "libarchive.js": "^2.0.2", "pdf-merger-js": "^5.1.1", "react": "^18.2.0", + "react-beautiful-dnd": "^13.1.1", "react-chat-elements": "^12.0.14", "react-dom": "^18.2.0", "react-highlight": "^0.15.0", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 957c777..eb6745f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3339,7 +3339,7 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "sjtu_canvas_helper" -version = "1.3.10" +version = "1.3.11" dependencies = [ "bardecoder", "base64 0.22.1", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index a877be4..ebf7791 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sjtu_canvas_helper" -version = "1.3.10" +version = "1.3.11" description = "SJTU Canvas Helper" authors = ["Okabe"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 4548c28..8ca7dda 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -7,7 +7,7 @@ }, "package": { "productName": "SJTU Canvas Helper", - "version": "1.3.10" + "version": "1.3.11" }, "tauri": { "allowlist": { diff --git a/src/components/change_log_modal.tsx b/src/components/change_log_modal.tsx index 0b364e0..860a06c 100644 --- a/src/components/change_log_modal.tsx +++ b/src/components/change_log_modal.tsx @@ -11,6 +11,12 @@ export function ChangeLogModal({ open, onCancel, onOk }: { overflow: "scroll", }}> + v1.3.11 2024/6/18 + + + v1.3.10 2024/6/12 - + } \ No newline at end of file diff --git a/src/components/draggable_list.tsx b/src/components/draggable_list.tsx new file mode 100644 index 0000000..9ca3b93 --- /dev/null +++ b/src/components/draggable_list.tsx @@ -0,0 +1,32 @@ +import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd"; +import DraggableListItem from "./draggable_list_item"; +import { DraggableItem } from "../lib/model"; + +export default function DraggableList({ items, onDragEnd }: { items: DraggableItem[], onDragEnd?: (newItems: DraggableItem[]) => void }) { + const onDragEndWrapper = (result: any) => { + const newItems = Array.from(items); + const [removed] = newItems.splice(result.source.index, 1); + newItems.splice(result.destination.index, 0, removed); + onDragEnd?.(newItems); + }; + return + + {(provided) => ( +
+ {items.map((item, index) => ( + + {(provided) => ( + + )} + + ))} + {provided.placeholder} +
+ )} +
+
+} + diff --git a/src/components/draggable_list_item.tsx b/src/components/draggable_list_item.tsx new file mode 100644 index 0000000..40c1d9e --- /dev/null +++ b/src/components/draggable_list_item.tsx @@ -0,0 +1,14 @@ +import { Card } from "antd"; +import { DraggableItem } from "../lib/model"; + +export default function DraggableListItem({ item, provided }: { item: DraggableItem, provided: any }) { + return
+ +

{item.content}

+
+
+} \ No newline at end of file diff --git a/src/components/file_order_select_modal.tsx b/src/components/file_order_select_modal.tsx new file mode 100644 index 0000000..cc9dd13 --- /dev/null +++ b/src/components/file_order_select_modal.tsx @@ -0,0 +1,36 @@ +import { DraggableItem, File } from "../lib/model"; +import { Alert, Modal, Space } from "antd"; +import DraggableList from "./draggable_list"; +import { useEffect, useState } from "react"; + +export default function FileOrderSelectModal({ files, open, handleOk, handleCancel }: { + files: File[], + open: boolean, + handleOk: (items: DraggableItem[]) => void, + handleCancel: () => void +}) { + const [items, setItems] = useState([]); + useEffect(() => { + setItems(files.map(f => ({ + id: f.id.toString(), + content: f.display_name, + data: f + }))); + }, [files]) + return handleOk(items)} + title={"指定合并顺序"} + styles={{ body: { padding: "20px" } }} + > + + + + + +} \ No newline at end of file diff --git a/src/lib/model.ts b/src/lib/model.ts index 1b6f82d..eba7685 100644 --- a/src/lib/model.ts +++ b/src/lib/model.ts @@ -488,3 +488,9 @@ export interface Reply { rating_sum: number | null; message: string | null; } + +export interface DraggableItem { + id: string; + content: string; + data: any; +} diff --git a/src/page/files.tsx b/src/page/files.tsx index 92c608b..e552106 100644 --- a/src/page/files.tsx +++ b/src/page/files.tsx @@ -9,6 +9,7 @@ import FileDownloadTable from "../components/file_download_table"; import { useCourses, useLoginModal, useMerger, usePreview } from "../lib/hooks"; import { FolderOutlined, HomeOutlined, LeftOutlined } from "@ant-design/icons" import { scrollToTop, getFileIcon } from "../lib/utils"; +import FileOrderSelectModal from "../components/file_order_select_modal"; interface DownloadInfo { course?: Course; @@ -34,6 +35,7 @@ export default function FilesPage() { const [currentFolderFullName, setCurrentFolderFullName] = useState(''); const [parentFolderId, setParentFolderId] = useState(null); const [keyword, setKeyword] = useState(""); + const [openFileOrderSelectModal, setOpenFileOrderSelectModal] = useState(false); const { previewer, onHoverEntry, onLeaveEntry, setPreviewEntry, setEntries } = usePreview(); const { merger, mergePDFs } = useMerger({ setPreviewEntry, onHoverEntry, onLeaveEntry }); const courses = useCourses(); @@ -410,10 +412,6 @@ export default function FilesPage() { } } - const handleMergePDFs = () => { - mergePDFs(selectedEntries.filter(isFile) as File[]); - } - const backToParentDir = async () => { setFiles([]); setFolders([]); @@ -454,10 +452,21 @@ export default function FilesPage() { } ] + const getSupportedMergeFiles = () => { + return (selectedEntries as File[]).filter(f => f.display_name.endsWith(".pptx") || f.display_name.endsWith(".pdf")); + } + return {contextHolder} {previewer} {modal} + { + setOpenFileOrderSelectModal(false); + const files = items.map(item => item.data as File); + mergePDFs(files); + }} + handleCancel={() => setOpenFileOrderSelectModal(false)} files={getSupportedMergeFiles()} /> @@ -496,7 +505,7 @@ export default function FilesPage() { /> - + PDF/PPTX (混合)合并 {merger} diff --git a/yarn.lock b/yarn.lock index 97087b3..66ab3b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -247,6 +247,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.15.4", "@babel/runtime@^7.9.2": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12" + integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.22.15", "@babel/template@^7.24.0": version "7.24.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" @@ -923,6 +930,14 @@ dependencies: "@types/unist" "*" +"@types/hoist-non-react-statics@^3.3.0": + version "3.3.5" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494" + integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + "@types/mdast@^4.0.0": version "4.0.3" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-4.0.3.tgz#1e011ff013566e919a4232d1701ad30d70cab333" @@ -964,6 +979,13 @@ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6" integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q== +"@types/react-beautiful-dnd@^13.1.8": + version "13.1.8" + resolved "https://registry.yarnpkg.com/@types/react-beautiful-dnd/-/react-beautiful-dnd-13.1.8.tgz#f52d3ea07e1e19159d6c3c4a48c8da3d855e60b4" + integrity sha512-E3TyFsro9pQuK4r8S/OL6G99eq7p8v29sX0PM7oT8Z+PJfZvSQTx4zTQbUJ+QZXioAF0e7TGBEcA1XhYhCweyQ== + dependencies: + "@types/react" "*" + "@types/react-dom@^18.2.7": version "18.2.23" resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.23.tgz#112338760f622a16d64271b408355f2f27f6302c" @@ -978,6 +1000,16 @@ dependencies: "@types/react" "*" +"@types/react-redux@^7.1.20": + version "7.1.33" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.33.tgz#53c5564f03f1ded90904e3c90f77e4bd4dc20b15" + integrity sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg== + dependencies: + "@types/hoist-non-react-statics" "^3.3.0" + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + redux "^4.0.0" + "@types/react-syntax-highlighter@^15.5.11": version "15.5.11" resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-15.5.11.tgz#e050745b22eff81fc13cb0c763dd0d063413bbf1" @@ -1383,6 +1415,13 @@ crc-32@~1.2.0, crc-32@~1.2.1: resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== +css-box-model@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/css-box-model/-/css-box-model-1.2.1.tgz#59951d3b81fd6b2074a62d49444415b0d2b4d7c1" + integrity sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw== + dependencies: + tiny-invariant "^1.0.6" + css-color-keywords@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" @@ -1758,6 +1797,13 @@ highlight.js@^10.4.1, highlight.js@^10.5.0, highlight.js@~10.7.0: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + html-url-attributes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/html-url-attributes/-/html-url-attributes-3.0.0.tgz#fc4abf0c3fb437e2329c678b80abb3c62cff6f08" @@ -2207,6 +2253,11 @@ mdast-util-to-string@^4.0.0: dependencies: "@types/mdast" "^4.0.0" +memoize-one@^5.1.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + merge-refs@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.2.2.tgz#6142633398dd0d10a37626cae77ddeb1db26db0c" @@ -2741,7 +2792,7 @@ progressbar.js@^1.1.0: lodash.merge "^4.6.2" shifty "^2.8.3" -prop-types@^15.5.8, prop-types@^15.6.2: +prop-types@^15.5.8, prop-types@^15.6.2, prop-types@^15.7.2: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -2772,6 +2823,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +raf-schd@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/raf-schd/-/raf-schd-4.0.3.tgz#5d6c34ef46f8b2a0e880a8fcdb743efc5bfdbc1a" + integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== + rc-cascader@~3.24.0: version "3.24.0" resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-3.24.0.tgz#f43f06233b89b7b46005c19f3233068c5b379b24" @@ -3123,6 +3179,19 @@ rc-virtual-list@^3.11.1, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2: rc-resize-observer "^1.0.0" rc-util "^5.36.0" +react-beautiful-dnd@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/react-beautiful-dnd/-/react-beautiful-dnd-13.1.1.tgz#b0f3087a5840920abf8bb2325f1ffa46d8c4d0a2" + integrity sha512-0Lvs4tq2VcrEjEgDXHjT98r+63drkKEgqyxdA7qD3mvKwga6a5SscbdLPO2IExotU1jW8L0Ksdl0Cj2AF67nPQ== + dependencies: + "@babel/runtime" "^7.9.2" + css-box-model "^1.2.0" + memoize-one "^5.1.1" + raf-schd "^4.0.2" + react-redux "^7.2.0" + redux "^4.0.4" + use-memo-one "^1.1.1" + react-chat-elements@^12.0.14: version "12.0.14" resolved "https://registry.yarnpkg.com/react-chat-elements/-/react-chat-elements-12.0.14.tgz#b1d13be3ba46a4f123ab8b2f5de42a3dbfe9bae1" @@ -3159,11 +3228,16 @@ react-icons@^5.0.1: resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.0.1.tgz#1694e11bfa2a2888cab47dcc30154ce90485feee" integrity sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw== -react-is@^16.13.1: +react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-is@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + react-is@^18.2.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -3199,6 +3273,18 @@ react-pdf@7.5.0: tiny-invariant "^1.0.0" tiny-warning "^1.0.0" +react-redux@^7.2.0: + version "7.2.9" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d" + integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/react-redux" "^7.1.20" + hoist-non-react-statics "^3.3.2" + loose-envify "^1.4.0" + prop-types "^15.7.2" + react-is "^17.0.2" + react-refresh@^0.14.0: version "0.14.0" resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e" @@ -3281,6 +3367,13 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +redux@^4.0.0, redux@^4.0.4: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + refractor@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/refractor/-/refractor-3.6.0.tgz#ac318f5a0715ead790fcfb0c71f4dd83d977935a" @@ -3604,7 +3697,7 @@ timeago.js@^4.0.2: resolved "https://registry.yarnpkg.com/timeago.js/-/timeago.js-4.0.2.tgz#724e8c8833e3490676c7bb0a75f5daf20e558028" integrity sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w== -tiny-invariant@^1.0.0: +tiny-invariant@^1.0.0, tiny-invariant@^1.0.6: version "1.3.3" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== @@ -3770,6 +3863,11 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" +use-memo-one@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.3.tgz#2fd2e43a2169eabc7496960ace8c79efef975e99" + integrity sha512-g66/K7ZQGYrI6dy8GLpVcMsBp4s17xNkYJVSMvTEevGy3nDxHOfE6z8BVE22+5G5x7t3+bhzrlTDB7ObrEE0cQ== + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"