may download document with translation (#1220)

This commit is contained in:
an-lee
2024-12-02 16:38:00 +08:00
committed by GitHub
parent 1ea4d33b1a
commit 6cdf602fc8
9 changed files with 187 additions and 46 deletions

View File

@@ -85,7 +85,7 @@
"@types/mark.js": "^8.11.12",
"@types/mime-types": "^2.1.4",
"@types/mustache": "^4.2.5",
"@types/node": "^22.10.0",
"@types/node": "^22.10.1",
"@types/prop-types": "^15.7.13",
"@types/rails__actioncable": "^6.1.11",
"@types/react": "^18.3.12",
@@ -106,13 +106,13 @@
"axios": "^1.7.8",
"camelcase": "^8.0.0",
"camelcase-keys": "^9.1.3",
"chart.js": "^4.4.6",
"chart.js": "^4.4.7",
"cheerio": "^1.0.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.4",
"command-exists": "^1.2.9",
"compromise": "^14.14.2",
"compromise": "^14.14.3",
"compromise-paragraphs": "^0.1.0",
"compromise-stats": "^0.1.0",
"dayjs": "^1.11.13",
@@ -127,7 +127,7 @@
"electron-playwright-helpers": "^1.7.1",
"electron-squirrel-startup": "^1.0.1",
"electron-unhandled": "^5.0.0",
"eslint": "^9.15.0",
"eslint": "^9.16.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-import": "^2.31.0",
"flora-colossus": "^2.0.0",
@@ -136,7 +136,7 @@
"https-proxy-agent": "^7.0.5",
"i18next": "^24.0.2",
"input-otp": "^1.4.1",
"intl-tel-input": "^24.7.0",
"intl-tel-input": "^24.8.1",
"js-md5": "^0.8.3",
"langchain": "^0.3.6",
"lodash": "^4.17.21",
@@ -164,7 +164,7 @@
"react-frame-component": "^5.2.7",
"react-hook-form": "^7.53.2",
"react-hotkeys-hook": "^4.6.1",
"react-i18next": "^15.1.2",
"react-i18next": "^15.1.3",
"react-markdown": "^9.0.1",
"react-resizable-panels": "^2.1.7",
"react-router-dom": "^7.0.1",
@@ -189,7 +189,7 @@
"wavesurfer.js": "^7.8.9",
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.5",
"zx": "^8.2.2"
"zx": "^8.2.4"
},
"dependencies": {
"@andrkrn/ffprobe-static": "^5.2.0",

View File

@@ -0,0 +1,69 @@
import {
Button,
DropdownMenu,
DropdownMenuItem,
DropdownMenuContent,
DropdownMenuTrigger,
toast,
} from "@renderer/components/ui";
import { MoreVerticalIcon } from "lucide-react";
import { t } from "i18next";
import { useContext } from "react";
import {
AppSettingsProviderContext,
DocumentProviderContext,
} from "@renderer/context";
import template from "./document.template.html?raw";
export const DocumentActionsButton = (props: { document: DocumentEType }) => {
const { document } = props;
const { EnjoyApp } = useContext(AppSettingsProviderContext);
const { ref, section } = useContext(DocumentProviderContext);
const handlePrint = async () => {
if (!ref.current) return;
const content = template.replace("$title", document.title).replace(
"$content",
Array.from(ref.current.querySelectorAll(".segment, .translation"))
.map((segment) => {
const tagName = segment.tagName.toLowerCase();
if (segment.classList.contains("translation")) {
return `<${tagName}>${segment.textContent}</${tagName}>`;
}
return `<${tagName}>${
segment.querySelector(".segment-content")?.textContent
}</${tagName}>`;
})
.join("")
);
try {
const savePath = await EnjoyApp.dialog.showSaveDialog({
title: t("print"),
defaultPath: `${document.title}(S${section}).pdf`,
});
if (!savePath) return;
await EnjoyApp.download.printAsPdf(content, savePath);
toast.success(t("downloadedSuccessfully"));
} catch (err) {
toast.error(`${t("downloadFailed")}: ${err.message}`);
}
};
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="w-6 h-6">
<MoreVerticalIcon className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent side="bottom" align="start">
<DropdownMenuItem onClick={handlePrint}>{t("print")}</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
};

View File

@@ -1,5 +1,6 @@
import { useCallback, useContext, useEffect, useState } from "react";
import {
DocumentActionsButton,
DocumentConfigButton,
LoaderSpin,
MarkdownWrapper,
@@ -16,7 +17,12 @@ import {
Button,
toast,
} from "@renderer/components/ui";
import { ChevronLeftIcon, ChevronRightIcon, MenuIcon } from "lucide-react";
import {
ChevronLeftIcon,
ChevronRightIcon,
MenuIcon,
TableOfContentsIcon,
} from "lucide-react";
import {
AppSettingsProviderContext,
DocumentProviderContext,
@@ -145,7 +151,7 @@ export const DocumentEpubRenderer = () => {
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="w-6 h-6">
<MenuIcon className="size-4" />
<TableOfContentsIcon className="size-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent
@@ -176,6 +182,7 @@ export const DocumentEpubRenderer = () => {
</DropdownMenuContent>
</DropdownMenu>
<DocumentConfigButton document={document} />
<DocumentActionsButton document={document} />
</div>
<div className="text-xs text-muted-foreground truncate">{title}</div>
<div className="flex items-center gap-2">
@@ -202,7 +209,7 @@ export const DocumentEpubRenderer = () => {
<LoaderSpin />
) : (
<MarkdownWrapper
className="mx-auto max-w-full"
className="mx-auto max-w-full document-renderer"
onLinkClick={handleLinkClick}
onSegmentVisible={onSegmentVisible}
autoTranslate={document.config.autoTranslate}

View File

@@ -1,6 +1,7 @@
import { Readability } from "@mozilla/readability";
import { useContext, useEffect, useState } from "react";
import {
DocumentActionsButton,
DocumentConfigButton,
LoaderSpin,
MarkdownWrapper,
@@ -51,6 +52,7 @@ export const DocumentHtmlRenderer = () => {
<div className="flex items-center justify-between space-x-2 sticky top-0 z-10 bg-background py-2">
<div className="flex items-center gap-2">
<DocumentConfigButton document={document} />
<DocumentActionsButton document={document} />
</div>
<div className="text-xs text-muted-foreground max-w-full truncate">
{title}
@@ -71,7 +73,7 @@ export const DocumentHtmlRenderer = () => {
</div>
</div>
<MarkdownWrapper
className="mx-auto max-w-full"
className="mx-auto max-w-full document-renderer"
autoTranslate={document.config.autoTranslate}
onSpeech={onSpeech}
onSegmentVisible={onSegmentVisible}

View File

@@ -1,5 +1,6 @@
import { useContext, useEffect } from "react";
import {
DocumentActionsButton,
DocumentConfigButton,
LoaderSpin,
MarkdownWrapper,
@@ -33,6 +34,7 @@ export const DocumentTextRenderer = () => {
<div className="flex items-center justify-between space-x-2 sticky top-0 z-10 bg-background py-2">
<div className="flex items-center gap-2">
<DocumentConfigButton document={document} />
<DocumentActionsButton document={document} />
</div>
<div className="text-xs text-muted-foreground max-w-full truncate">
{document.title}
@@ -53,7 +55,7 @@ export const DocumentTextRenderer = () => {
</div>
</div>
<MarkdownWrapper
className="mx-auto max-w-full"
className="mx-auto max-w-full document-renderer"
autoTranslate={document.config.autoTranslate}
onSpeech={onSpeech}
onSegmentVisible={onSegmentVisible}

View File

@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width initial-scale=1.0" />
<title>$title</title>
<style>
body {
font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
}
h1 {
font-size: 24px;
font-weight: 600;
text-align: center;
margin-bottom: 24px;
}
h2 {
font-size: 20px;
font-weight: 600;
margin-bottom: 16px;
}
h3 {
font-size: 18px;
font-weight: 600;
margin-bottom: 16px;
}
p {
font-size: 16px;
margin-bottom: 16px;
}
</style>
</head>
<body>
<div class="content">$content</div>
</body>
</html>

View File

@@ -7,3 +7,4 @@ export * from "./document-config-form";
export * from "./document-add-button";
export * from "./document-config-button";
export * from "./documents-segment";
export * from "./document-actions-button";

View File

@@ -171,7 +171,7 @@ const Segment = memo(
<span className="segment-content">{children}</span>
</Tag>
{translation && (
<Tag id={`translation-${index}`}>
<Tag id={`translation-${index}`} className="translation">
{translation}
<Button
variant="ghost"

View File

@@ -2703,10 +2703,10 @@ __metadata:
languageName: node
linkType: hard
"@eslint/js@npm:9.15.0":
version: 9.15.0
resolution: "@eslint/js@npm:9.15.0"
checksum: 10c0/56552966ab1aa95332f70d0e006db5746b511c5f8b5e0c6a9b2d6764ff6d964e0b2622731877cbc4e3f0e74c5b39191290d5f48147be19175292575130d499ab
"@eslint/js@npm:9.16.0":
version: 9.16.0
resolution: "@eslint/js@npm:9.16.0"
checksum: 10c0/a55846a4ddade720662d36682f3eaaf38eac06eeee12c83bb837bba2b7d550dadcb3445b104219f0bc1da2e09b4fe5fb5ba123b8338c8c787bcfbd540878df75
languageName: node
linkType: hard
@@ -7490,7 +7490,7 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:*, @types/node@npm:>=20, @types/node@npm:^22.10.0":
"@types/node@npm:*, @types/node@npm:>=20":
version: 22.10.0
resolution: "@types/node@npm:22.10.0"
dependencies:
@@ -7524,6 +7524,15 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:^22.10.1":
version: 22.10.1
resolution: "@types/node@npm:22.10.1"
dependencies:
undici-types: "npm:~6.20.0"
checksum: 10c0/0fbb6d29fa35d807f0223a4db709c598ac08d66820240a2cd6a8a69b8f0bc921d65b339d850a666b43b4e779f967e6ed6cf6f0fca3575e08241e6b900364c234
languageName: node
linkType: hard
"@types/normalize-package-data@npm:^2.4.0":
version: 2.4.4
resolution: "@types/normalize-package-data@npm:2.4.4"
@@ -9610,12 +9619,12 @@ __metadata:
languageName: node
linkType: hard
"chart.js@npm:^4.4.6":
version: 4.4.6
resolution: "chart.js@npm:4.4.6"
"chart.js@npm:^4.4.7":
version: 4.4.7
resolution: "chart.js@npm:4.4.7"
dependencies:
"@kurkle/color": "npm:^0.3.0"
checksum: 10c0/456d16a030c35fa16182945e91d4fdd89510343454309b783f5e060ea89baaed3bc9b43d2d9b3acadd385e5921718e27ed2fcae8b5efa277d27bc4da4af639f2
checksum: 10c0/9db499993c561f11184112003956ba96cf00513e025f58846be36e75ebddc6cbab2f93626c3734c305bc801e9362a9ef193b9591e679c59903b2ecb48cfcb317
languageName: node
linkType: hard
@@ -10173,6 +10182,17 @@ __metadata:
languageName: node
linkType: hard
"compromise@npm:^14.14.3":
version: 14.14.3
resolution: "compromise@npm:14.14.3"
dependencies:
efrt: "npm:2.7.0"
grad-school: "npm:0.0.5"
suffix-thumb: "npm:5.0.2"
checksum: 10c0/780c0f1ef984e49e41361183653d87286effb60e73313c12602452145a7de52afe4ca56596bbbc4e62795047ea6ab93dad46703cb699588a823d6012aece31b5
languageName: node
linkType: hard
"concat-map@npm:0.0.1":
version: 0.0.1
resolution: "concat-map@npm:0.0.1"
@@ -12060,7 +12080,7 @@ __metadata:
"@types/mark.js": "npm:^8.11.12"
"@types/mime-types": "npm:^2.1.4"
"@types/mustache": "npm:^4.2.5"
"@types/node": "npm:^22.10.0"
"@types/node": "npm:^22.10.1"
"@types/prop-types": "npm:^15.7.13"
"@types/rails__actioncable": "npm:^6.1.11"
"@types/react": "npm:^18.3.12"
@@ -12081,13 +12101,13 @@ __metadata:
axios: "npm:^1.7.8"
camelcase: "npm:^8.0.0"
camelcase-keys: "npm:^9.1.3"
chart.js: "npm:^4.4.6"
chart.js: "npm:^4.4.7"
cheerio: "npm:^1.0.0"
class-variance-authority: "npm:^0.7.1"
clsx: "npm:^2.1.1"
cmdk: "npm:^1.0.4"
command-exists: "npm:^1.2.9"
compromise: "npm:^14.14.2"
compromise: "npm:^14.14.3"
compromise-paragraphs: "npm:^0.1.0"
compromise-stats: "npm:^0.1.0"
dayjs: "npm:^1.11.13"
@@ -12104,7 +12124,7 @@ __metadata:
electron-settings: "npm:^4.0.4"
electron-squirrel-startup: "npm:^1.0.1"
electron-unhandled: "npm:^5.0.0"
eslint: "npm:^9.15.0"
eslint: "npm:^9.16.0"
eslint-import-resolver-typescript: "npm:^3.6.3"
eslint-plugin-import: "npm:^2.31.0"
ffmpeg-static: "npm:^5.2.0"
@@ -12117,7 +12137,7 @@ __metadata:
https-proxy-agent: "npm:^7.0.5"
i18next: "npm:^24.0.2"
input-otp: "npm:^1.4.1"
intl-tel-input: "npm:^24.7.0"
intl-tel-input: "npm:^24.8.1"
js-md5: "npm:^0.8.3"
langchain: "npm:^0.3.6"
lodash: "npm:^4.17.21"
@@ -12145,7 +12165,7 @@ __metadata:
react-frame-component: "npm:^5.2.7"
react-hook-form: "npm:^7.53.2"
react-hotkeys-hook: "npm:^4.6.1"
react-i18next: "npm:^15.1.2"
react-i18next: "npm:^15.1.3"
react-markdown: "npm:^9.0.1"
react-resizable-panels: "npm:^2.1.7"
react-router-dom: "npm:^7.0.1"
@@ -12176,7 +12196,7 @@ __metadata:
wavesurfer.js: "npm:^7.8.9"
zod: "npm:^3.23.8"
zod-to-json-schema: "npm:^3.23.5"
zx: "npm:^8.2.2"
zx: "npm:^8.2.4"
languageName: unknown
linkType: soft
@@ -12693,16 +12713,16 @@ __metadata:
languageName: node
linkType: hard
"eslint@npm:^9.15.0":
version: 9.15.0
resolution: "eslint@npm:9.15.0"
"eslint@npm:^9.16.0":
version: 9.16.0
resolution: "eslint@npm:9.16.0"
dependencies:
"@eslint-community/eslint-utils": "npm:^4.2.0"
"@eslint-community/regexpp": "npm:^4.12.1"
"@eslint/config-array": "npm:^0.19.0"
"@eslint/core": "npm:^0.9.0"
"@eslint/eslintrc": "npm:^3.2.0"
"@eslint/js": "npm:9.15.0"
"@eslint/js": "npm:9.16.0"
"@eslint/plugin-kit": "npm:^0.2.3"
"@humanfs/node": "npm:^0.16.6"
"@humanwhocodes/module-importer": "npm:^1.0.1"
@@ -12738,7 +12758,7 @@ __metadata:
optional: true
bin:
eslint: bin/eslint.js
checksum: 10c0/d0d7606f36bfcccb1c3703d0a24df32067b207a616f17efe5fb1765a91d13f085afffc4fc97ecde4ab9c9f4edd64d9b4ce750e13ff7937a25074b24bee15b20f
checksum: 10c0/f36d12652c6f20bab8a77375b8ad29a6af030c3840deb0a5f9dd4cee49d68a2d68d7dc73b0c25918df59d83cd686dd5712e11387e696e1f3842e8dde15cd3255
languageName: node
linkType: hard
@@ -14870,10 +14890,10 @@ __metadata:
languageName: node
linkType: hard
"intl-tel-input@npm:^24.7.0":
version: 24.7.0
resolution: "intl-tel-input@npm:24.7.0"
checksum: 10c0/dd51cda968ab69b154792cd101ed6eb07ebf446dcf636493d9f551d2e58b7ca1c1b99a817fea2a486110feeb2d3ca8e384d73a6f064665859804cf36c61d938f
"intl-tel-input@npm:^24.8.1":
version: 24.8.1
resolution: "intl-tel-input@npm:24.8.1"
checksum: 10c0/6fde8ac8cc13e33de428e8526fb039941b49e21cd650029a9eb70da19445b12bf966e75b6c9f2c95053e970f8ee8364f04e301226350e95c8cf380ac5d6ce4df
languageName: node
linkType: hard
@@ -20212,9 +20232,9 @@ __metadata:
languageName: node
linkType: hard
"react-i18next@npm:^15.1.2":
version: 15.1.2
resolution: "react-i18next@npm:15.1.2"
"react-i18next@npm:^15.1.3":
version: 15.1.3
resolution: "react-i18next@npm:15.1.3"
dependencies:
"@babel/runtime": "npm:^7.25.0"
html-parse-stringify: "npm:^3.0.1"
@@ -20226,7 +20246,7 @@ __metadata:
optional: true
react-native:
optional: true
checksum: 10c0/b10052545f0bebcd0b55cf04eb7d58307cdf6645707108bcae28026fe92ce0ef9cf0b35ac9cb940f6fcc22f679c810f2c008e9d8284bd4cfbb26c5649e3885ab
checksum: 10c0/2f8de1757f5b4d91e034f621c0bf6422fad3cde0687d11d4fe87822db86f264c6c3512a26fafe03d91ea691b3c441ba5ca490f4e5611e147df985ee133265089
languageName: node
linkType: hard
@@ -24679,9 +24699,9 @@ __metadata:
languageName: node
linkType: hard
"zx@npm:^8.2.2":
version: 8.2.2
resolution: "zx@npm:8.2.2"
"zx@npm:^8.2.4":
version: 8.2.4
resolution: "zx@npm:8.2.4"
dependencies:
"@types/fs-extra": "npm:>=11"
"@types/node": "npm:>=20"
@@ -24692,6 +24712,6 @@ __metadata:
optional: true
bin:
zx: build/cli.js
checksum: 10c0/68c2fd54cd10e2c3b32ae7db62cc0004808b7ece6aad2c87838e354174bd9868918cc1a6e067d6a7647cfb1180253e6a362f8b57aabb4b2895c8f6c0e92a62cd
checksum: 10c0/ae60ceef4eaf62695de0a24edab302efc770da10f2f4e79b7b8d50c2e7bee8c4b100e8722c6963a6f4badafe3f00d8d0fd50080c90745bf7bca90203c4aee59b
languageName: node
linkType: hard