diff --git a/enjoy/package.json b/enjoy/package.json
index fe909144..2fe5d272 100644
--- a/enjoy/package.json
+++ b/enjoy/package.json
@@ -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",
diff --git a/enjoy/src/renderer/components/documents/document-actions-button.tsx b/enjoy/src/renderer/components/documents/document-actions-button.tsx
new file mode 100644
index 00000000..0c722721
--- /dev/null
+++ b/enjoy/src/renderer/components/documents/document-actions-button.tsx
@@ -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 (
+
+
+
+
+
+ {t("print")}
+
+
+ );
+};
diff --git a/enjoy/src/renderer/components/documents/document-epub-renderer.tsx b/enjoy/src/renderer/components/documents/document-epub-renderer.tsx
index 99ef4a22..d472636c 100644
--- a/enjoy/src/renderer/components/documents/document-epub-renderer.tsx
+++ b/enjoy/src/renderer/components/documents/document-epub-renderer.tsx
@@ -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 = () => {
{
+
{title}
@@ -202,7 +209,7 @@ export const DocumentEpubRenderer = () => {
) : (
{
+
{title}
@@ -71,7 +73,7 @@ export const DocumentHtmlRenderer = () => {
{
+
{document.title}
@@ -53,7 +55,7 @@ export const DocumentTextRenderer = () => {
+
+
+
+
+ $title
+
+
+
+ $content
+
+
diff --git a/enjoy/src/renderer/components/documents/index.ts b/enjoy/src/renderer/components/documents/index.ts
index a96ae7b7..94172937 100644
--- a/enjoy/src/renderer/components/documents/index.ts
+++ b/enjoy/src/renderer/components/documents/index.ts
@@ -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";
diff --git a/enjoy/src/renderer/components/misc/markdown-wrapper.tsx b/enjoy/src/renderer/components/misc/markdown-wrapper.tsx
index da4a1503..50930330 100644
--- a/enjoy/src/renderer/components/misc/markdown-wrapper.tsx
+++ b/enjoy/src/renderer/components/misc/markdown-wrapper.tsx
@@ -171,7 +171,7 @@ const Segment = memo(
{children}
{translation && (
-
+
{translation}