Skip to content

Commit

Permalink
feat: Add PDF merge
Browse files Browse the repository at this point in the history
  • Loading branch information
RiverTwilight committed Oct 23, 2024
1 parent 28028e9 commit 9b9298a
Show file tree
Hide file tree
Showing 12 changed files with 210 additions and 9 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"next": "13.1.1",
"next-pwa": "^5.6.0",
"openai": "^3.1.0",
"pdf-lib": "^1.17.1",
"postcss": "^8.4.31",
"qrcode": "^1.4.4",
"raw-loader": "^4.0.1",
Expand Down
3 changes: 2 additions & 1 deletion public/data/article/en-US/about.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ We will insist on the open source of the website. For open source projects, the

If you want to support our work, you can also recommend our website to people in need around you. A good user group will promote our improvement; or, put forward your valuable opinions to help us improve the website.

You are also welcome to join the group chat, communicate, discuss and share with everyone.
For more information about Geekits, please visit [Geekits User Guide](https://www.ygeeker.com/support/geekits/intro).
You are also welcome to join our community.

- Telegram Channel: [@ygeeker](https://t.me/ygeeker)
- QQ Group: [923724755](https://i.ibb.co/BGfwRcX/image.png)
9 changes: 3 additions & 6 deletions public/data/article/zh-CN/about.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
Geekits 始终 100% 免费,如果你想支持我们的工作,你也可以向身边有需要的人推荐我们的产品,良好的用户群体将促进我们的完善;或者,提出你的宝贵意见,帮助我们改进产品。

欲了解更多关于 Geekits 的信息,请访问 [Geekits 用户手册](https://www.ygeeker.com/support/geekits/intro)

也欢迎你加入我们的社区,和大家一起交流,讨论,分享。或前往 YGeeker 官网探索我们创造的更多精彩内容。

- 官网: [www.ygeeker.com](https://www.ygeeker.com)
- QQ 群: [923724755](https://i.ibb.co/BGfwRcX/image.png)
- 小红书: [@RiverTwilight](https://www.xiaohongshu.com/user/profile/608e28ee000000000100bc65?xhsshare=CopyLink&appuid=608e28ee000000000100bc65&apptime=1712575215)
- 小红书: [@RiverTwilight](https://www.xiaohongshu.com/user/profile/608e28ee000000000100bc65)

如果你想将你的产品展示在首页,请前往这个 [Issue](https://github.com/RiverTwilight/Geekits/issues/64) 提交友链。

#### 相关资源

- [三年生生不息:开发云极客工具,我学到了什么?](https://mp.weixin.qq.com/s/cRvj5nGNKLeZMt12CrUuTg)
24 changes: 24 additions & 0 deletions public/sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,18 @@
<priority>0.7</priority>
</url>

<url>
<loc>/app/pdf_merger</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>

<url>
<loc>/app/pdf_merger</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>

<url>
<loc>/app/pomodoro</loc>
<changefreq>monthly</changefreq>
Expand Down Expand Up @@ -733,6 +745,18 @@
<priority>0.7</priority>
</url>

<url>
<loc>/app/pdf_merger</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>

<url>
<loc>/app/pdf_merger</loc>
<changefreq>monthly</changefreq>
<priority>0.7</priority>
</url>

<url>
<loc>/app/pomodoro</loc>
<changefreq>monthly</changefreq>
Expand Down
6 changes: 6 additions & 0 deletions src/apps/pdf_merger/README.en-US.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: "PDF Merge"
status: "beta"
icon: "/api/icon?iconColor=fff&iconName=PictureAsPdf&backgroundColor1=888"
channel: media
---
6 changes: 6 additions & 0 deletions src/apps/pdf_merger/README.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
name: "PDF 合并"
status: "beta"
icon: "/api/icon?iconColor=fff&iconName=PictureAsPdf&backgroundColor1=888"
channel: media
---
134 changes: 134 additions & 0 deletions src/apps/pdf_merger/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import React, { useState } from "react";
import { PDFDocument } from "pdf-lib";
import {
Box,
Button,
List,
ListItem,
ListItemText,
IconButton,
Typography,
Paper,
} from "@mui/material";
import {
Delete as DeleteIcon,
ArrowUpward as ArrowUpwardIcon,
ArrowDownward as ArrowDownwardIcon,
Merge as MergeIcon,
Upload as UploadIcon,
} from "@mui/icons-material";
import FilePicker from "@/components/FilePicker";
import { saveFile } from "@/utils/fileSaver";

const PdfMerger: React.FC = () => {
const [pdfFiles, setPdfFiles] = useState<File[]>([]);

const handleFileUpload = (file: File) => {
setPdfFiles((prevFiles) => [...prevFiles, file]);
};

const handleRemoveFile = (index: number) => {
setPdfFiles((prevFiles) => prevFiles.filter((_, i) => i !== index));
};

const handleMoveFile = (index: number, direction: "up" | "down") => {
setPdfFiles((prevFiles) => {
const newFiles = [...prevFiles];
const newIndex = direction === "up" ? index - 1 : index + 1;
[newFiles[index], newFiles[newIndex]] = [
newFiles[newIndex],
newFiles[index],
];
return newFiles;
});
};

const handleMergePDFs = async () => {
const mergedPdf = await PDFDocument.create();

for (const file of pdfFiles) {
const pdfBytes = await file.arrayBuffer();
const pdf = await PDFDocument.load(pdfBytes);
const copiedPages = await mergedPdf.copyPages(
pdf,
pdf.getPageIndices()
);
copiedPages.forEach((page) => mergedPdf.addPage(page));
}

const pdfBytes = await mergedPdf.save();
const blob = new Blob([pdfBytes], { type: "application/pdf" });
saveFile({ file: blob, filename: "merged.pdf", type: "pdf" });
};

return (
<Box sx={{ maxWidth: 600, margin: "auto", p: 3 }}>
<Typography variant="h4" gutterBottom>
PDF Merger
</Typography>
<Paper elevation={3} sx={{ p: 2, mb: 2 }}>
<FilePicker
enableDrag={true}
fileType="application/pdf"
handleFileUpload={handleFileUpload}
customButton={
<Button variant="contained" startIcon={<UploadIcon />}>
Add PDF
</Button>
}
/>
</Paper>
<List>
{pdfFiles.map((file, index) => (
<ListItem
key={index}
secondaryAction={
<Box>
<IconButton
edge="end"
aria-label="move up"
onClick={() => handleMoveFile(index, "up")}
disabled={index === 0}
>
<ArrowUpwardIcon />
</IconButton>
<IconButton
edge="end"
aria-label="move down"
onClick={() =>
handleMoveFile(index, "down")
}
disabled={index === pdfFiles.length - 1}
>
<ArrowDownwardIcon />
</IconButton>
<IconButton
edge="end"
aria-label="delete"
onClick={() => handleRemoveFile(index)}
>
<DeleteIcon />
</IconButton>
</Box>
}
>
<ListItemText primary={file.name} />
</ListItem>
))}
</List>
<Box sx={{ mt: 2, display: "flex", justifyContent: "center" }}>
<Button
variant="contained"
color="primary"
startIcon={<MergeIcon />}
onClick={handleMergePDFs}
disabled={pdfFiles.length < 2}
>
Merge PDFs
</Button>
</Box>
</Box>
);
};

export default PdfMerger;
2 changes: 1 addition & 1 deletion src/data/i18n.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"zh-CN":{"homePage.meta.description":"轻盈好用的在线工具,无需下载即可免费使用 30+ 工具,解决生活学习工作中的大小问题","homePage.meta.title":"首页","homePage.appSection.Media":"图片视频","homePage.searchBarAriaLabel":"在此键入以搜索","homePage.searchBarPlaceholder":"搜索(Ctrl+F)","navbar.home":"首页","navbar.donation":"免费捐赠","navbar.about":"关于","navbar.settings":"设置","navbar.downloadApp.tooltip":"Geekits APP 带来更快的速度,离线使用,以及更好的体验","navbar.downloadApp.label":"试试 Geekits APP","navbar.feedback":"反馈","navbar.copyright.subtitle":"Geekits 完全开源和免费","navbar.copyright.title":"YGeeker 出品","navbar.log":"更新日志","channel.life":"生活常用","channel.ai":"人工智能","channel.image":"图片视频","channel.developer":"编程开发","channel.external":"第三方APP","channel.wip":"开发中","appMenu.github":"在 GitHub 上编辑","appMenu.bookmark":"收藏","appMenu.bookmark.undo":"移除收藏","settings.language.title":"语言","settings.language.auto":"跟随系统","settings.language.zh_cn":"简体中文","settings.language.en_us":"English","donation.paid.title":"付费方式","feedback.send":"提交","feedback.hero":"我们会阅读每一条反馈","feedback.subtitle":"你可以畅所欲言","feedback.debug":"发送错误日志","feedback.content.placeholder":"输入内容","feedback.contact.placeholder":"适合我们联系你的方式","general.chooseFile":"选择文件","general.confirm":"确认","general.save":"保存","general.download":"下载","qrcode.basic.title":"基本","qrcode.basic.placeholder":"链接或文本","qrcode.basic.type":"类型","qrcode.basic.wifi":"WI-FI","qrcode.basic.text":"文本","qrcode.advanced.title":"高级","qrcode.advanced.icon":"图标","qrcode.advanced.light":"亮色","qrcode.advanced.dark":"暗色","aboutPage.meta.title":"关于","app.decision.addOption":"添加选项","app.decision.savePreset":"保存预设","app.decision.currentOption":"当前备选项","app.roman.inputHint":"输入整数","app.urlcleaner.confirmBtn":"净化","app.urlcleaner.ruleTitle":"规则"},"en-US":{"homePage.meta.description":"Your all-in-one digital toolkit. 30+ free tools including AI chat, calculators, converters, and creative utilities. Solve daily challenges effortlessly.","homePage.meta.title":"Home","homePage.appSection.Media":"Media","homePage.searchBarAriaLabel":"Type to Search","homePage.searchBarPlaceholder":"Search (Ctrl+F)","navbar.home":"Home","navbar.donation":"Free Donation","navbar.about":"About","navbar.settings":"Settings","navbar.downloadApp.tooltip":"Geekits app allows faster access, offline use, and more.","navbar.downloadApp.label":"Try Geekits App","navbar.feedback":"Feedback","navbar.copyright.subtitle":"Geekits is 100% open source and free","navbar.copyright.title":"Created by YGeeker","navbar.log":"What’s New","channel.life":"Lifestyle","channel.ai":"AI","channel.image":"Media Process","channel.developer":"Developer","channel.external":"External App","channel.wip":"WIP","appMenu.github":"Edit on GitHub","appMenu.bookmark":"Bookmark","appMenu.bookmark.undo":"Remove Bookmark","settings.language.title":"Language","settings.language.auto":"Auto","settings.language.zh_cn":"简体中文","settings.language.en_us":"English","donation.paid.title":"Paid Option","feedback.send":"Submit","feedback.hero":"We Read Every Feedback","feedback.subtitle":"New app request, bug report, or anything you want to tell us.","feedback.debug":"Send Error Log","feedback.content.placeholder":"Write something you want to tell us","feedback.contact.placeholder":"How can we contact you?","general.chooseFile":"Choose File","general.confirm":"Confirm","general.save":"Save","general.download":"Download","qrcode.basic.title":"Basic","qrcode.basic.placeholder":"URL or Text","qrcode.basic.type":"Type","qrcode.basic.wifi":"WI-FI","qrcode.basic.text":"Text","qrcode.advanced.title":"Advanced","qrcode.advanced.icon":"Icon","qrcode.advanced.light":"Light Color","qrcode.advanced.dark":"Dark Color","aboutPage.meta.title":"About","app.decision.addOption":"Add Option","app.decision.savePreset":"Save Preset","app.decision.currentOption":"Current Options","app.roman.inputHint":"Input integer","app.urlcleaner.confirmBtn":"Clean URL","app.urlcleaner.ruleTitle":"Rules"},"zh-HK":{"homePage.searchBarPlaceholder":"搜寻"}}
{"zh-CN":{"homePage.meta.description":"轻盈好用的在线工具,无需下载即可免费使用 30+ 工具,解决生活学习工作中的大小问题","homePage.meta.title":"首页","homePage.appSection.Media":"图片视频","homePage.searchBarAriaLabel":"在此键入以搜索","homePage.searchBarPlaceholder":"搜索(Ctrl+F)","navbar.home":"首页","navbar.donation":"免费捐赠","navbar.about":"关于","navbar.settings":"设置","navbar.downloadApp.tooltip":"Geekits APP 带来更快的速度,离线使用,以及更好的体验","navbar.downloadApp.label":"试试 Geekits APP","navbar.feedback":"反馈","navbar.copyright.subtitle":"Geekits 完全开源和免费","navbar.copyright.title":"YGeeker 出品","navbar.log":"更新日志","channel.life":"生活常用","channel.ai":"人工智能","channel.image":"图片视频","channel.developer":"编程开发","channel.external":"第三方APP","channel.wip":"开发中","appMenu.github":"在 GitHub 上编辑","appMenu.bookmark":"收藏","appMenu.bookmark.undo":"移除收藏","settings.language.title":"语言","settings.language.auto":"跟随系统","settings.language.zh_cn":"简体中文","settings.language.en_us":"English","donation.paid.title":"付费方式","feedback.send":"提交","feedback.hero":"我们会阅读每一条反馈","feedback.subtitle":"你可以畅所欲言","feedback.debug":"发送错误日志","feedback.content.placeholder":"输入内容","feedback.contact.placeholder":"适合我们联系你的方式","general.chooseFile":"选择文件","general.confirm":"确认","general.save":"保存","general.download":"下载","qrcode.basic.title":"基本","qrcode.basic.placeholder":"链接或文本","qrcode.basic.type":"类型","qrcode.basic.wifi":"WI-FI","qrcode.basic.text":"文本","qrcode.advanced.title":"高级","qrcode.advanced.icon":"图标","qrcode.advanced.light":"亮色","qrcode.advanced.dark":"暗色","aboutPage.meta.title":"关于","app.decision.addOption":"添加选项","app.decision.savePreset":"保存预设","app.decision.currentOption":"当前备选项","app.roman.inputHint":"输入整数","app.urlcleaner.confirmBtn":"净化","app.urlcleaner.ruleTitle":"规则"},"en-US":{"homePage.meta.description":"Your all-in-one digital toolkit. 30+ free tools including AI chat, calculators, converters, and creative utilities. Solve daily challenges effortlessly.","homePage.meta.title":"Home","homePage.appSection.Media":"Media","homePage.searchBarAriaLabel":"Type to Search","homePage.searchBarPlaceholder":"Search (Ctrl+F)","navbar.home":"Home","navbar.donation":"Donation","navbar.about":"About","navbar.settings":"Settings","navbar.downloadApp.tooltip":"Geekits app allows faster access, offline use, and more.","navbar.downloadApp.label":"Try Geekits App","navbar.feedback":"Feedback","navbar.copyright.subtitle":"Geekits is 100% open source and free","navbar.copyright.title":"Created by YGeeker","navbar.log":"What’s New","channel.life":"Lifestyle","channel.ai":"AI","channel.image":"Media Process","channel.developer":"Developer","channel.external":"External App","channel.wip":"WIP","appMenu.github":"Edit on GitHub","appMenu.bookmark":"Bookmark","appMenu.bookmark.undo":"Remove Bookmark","settings.language.title":"Language","settings.language.auto":"Auto","settings.language.zh_cn":"简体中文","settings.language.en_us":"English","donation.paid.title":"Paid Option","feedback.send":"Submit","feedback.hero":"We Read Every Feedback","feedback.subtitle":"New app request, bug report, or anything you want to tell us.","feedback.debug":"Send Error Log","feedback.content.placeholder":"Write something you want to tell us","feedback.contact.placeholder":"How can we contact you?","general.chooseFile":"Choose File","general.confirm":"Confirm","general.save":"Save","general.download":"Download","qrcode.basic.title":"Basic","qrcode.basic.placeholder":"URL or Text","qrcode.basic.type":"Type","qrcode.basic.wifi":"WI-FI","qrcode.basic.text":"Text","qrcode.advanced.title":"Advanced","qrcode.advanced.icon":"Icon","qrcode.advanced.light":"Light Color","qrcode.advanced.dark":"Dark Color","aboutPage.meta.title":"About","app.decision.addOption":"Add Option","app.decision.savePreset":"Save Preset","app.decision.currentOption":"Current Options","app.roman.inputHint":"Input integer","app.urlcleaner.confirmBtn":"Clean URL","app.urlcleaner.ruleTitle":"Rules"},"zh-HK":{"homePage.searchBarPlaceholder":"搜寻"}}
Binary file modified src/data/i18n.numbers
Binary file not shown.
Binary file modified src/data/i18n.xlsx
Binary file not shown.
3 changes: 3 additions & 0 deletions src/utils/appEntry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ const appImportList: Record<string, ComponentType> = {
decision: dynamic(() => import("../apps/decision"), {
ssr: false,
}),
pdf_merger: dynamic(() => import("../apps/pdf_merger"), {
ssr: false,
}),
dic_word: dynamic(() => import("../apps/dic_word"), {
ssr: false,
}),
Expand Down
31 changes: 30 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2310,6 +2310,20 @@
resolved "https://registry.npmjs.org/@one-ini/wasm/-/wasm-0.1.1.tgz#6013659736c9dbfccc96e8a9c2b3de317df39323"
integrity sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==

"@pdf-lib/standard-fonts@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz#8ba691c4421f71662ed07c9a0294b44528af2d7f"
integrity sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==
dependencies:
pako "^1.0.6"

"@pdf-lib/upng@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@pdf-lib/upng/-/upng-1.0.1.tgz#7dc9c636271aca007a9df4deaf2dd7e7960280cb"
integrity sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==
dependencies:
pako "^1.0.10"

"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
Expand Down Expand Up @@ -7277,7 +7291,7 @@ p-try@^2.0.0:
resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==

pako@^1.0.0, pako@~1.0.2:
pako@^1.0.0, pako@^1.0.10, pako@^1.0.11, pako@^1.0.6, pako@~1.0.2:
version "1.0.11"
resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
Expand Down Expand Up @@ -7378,6 +7392,16 @@ path-type@^4.0.0:
resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==

pdf-lib@^1.17.1:
version "1.17.1"
resolved "https://registry.yarnpkg.com/pdf-lib/-/pdf-lib-1.17.1.tgz#9e7dd21261a0c1fb17992580885b39e7d08f451f"
integrity sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==
dependencies:
"@pdf-lib/standard-fonts" "^1.0.0"
"@pdf-lib/upng" "^1.0.1"
pako "^1.0.11"
tslib "^1.11.1"

peberminta@^0.9.0:
version "0.9.0"
resolved "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz#8ec9bc0eb84b7d368126e71ce9033501dca2a352"
Expand Down Expand Up @@ -8876,6 +8900,11 @@ ts-node@^10.9.1:
v8-compile-cache-lib "^3.0.1"
yn "3.1.1"

tslib@^1.11.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==

tslib@^2, tslib@^2.0.1, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.4.1, tslib@^2.5.0, tslib@^2.6.2:
version "2.6.2"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
Expand Down

0 comments on commit 9b9298a

Please sign in to comment.