From 7558bcc589bea0169bc35fbecd7f5258dba82c73 Mon Sep 17 00:00:00 2001 From: Leons Aleksandrovs <58330666+Skrazzo@users.noreply.github.com> Date: Sat, 12 Jul 2025 17:24:38 +0300 Subject: [PATCH] feat(cover): download cover letter as png --- frontend/bun.lock | 3 +++ frontend/package.json | 1 + frontend/src/routes/cover/$coverId.tsx | 28 ++++++++++++++++++++++++-- 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/frontend/bun.lock b/frontend/bun.lock index 8118110..b16c4f2 100644 --- a/frontend/bun.lock +++ b/frontend/bun.lock @@ -20,6 +20,7 @@ "@tiptap/starter-kit": "^2.25.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "html-to-image": "^1.11.13", "lucide-react": "^0.525.0", "react": "^19.0.0", "react-dom": "^19.0.0", @@ -579,6 +580,8 @@ "html-encoding-sniffer": ["html-encoding-sniffer@4.0.0", "", { "dependencies": { "whatwg-encoding": "^3.1.1" } }, "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ=="], + "html-to-image": ["html-to-image@1.11.13", "", {}, "sha512-cuOPoI7WApyhBElTTb9oqsawRvZ0rHhaHwghRLlTuffoD1B2aDemlCruLeZrUIIdvG7gs9xeELEPm6PhuASqrg=="], + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "4" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], diff --git a/frontend/package.json b/frontend/package.json index 0aee7db..98e5b55 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -25,6 +25,7 @@ "@tiptap/starter-kit": "^2.25.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "html-to-image": "^1.11.13", "lucide-react": "^0.525.0", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/frontend/src/routes/cover/$coverId.tsx b/frontend/src/routes/cover/$coverId.tsx index a55190c..042e23c 100644 --- a/frontend/src/routes/cover/$coverId.tsx +++ b/frontend/src/routes/cover/$coverId.tsx @@ -5,6 +5,10 @@ import type { CoverLetter } from "@/types/api"; import { useQuery } from "@tanstack/react-query"; import { createFileRoute } from "@tanstack/react-router"; import "../../editor.css"; +import { toPng } from "html-to-image"; +import { useRef } from "react"; +import { Button } from "@/components/ui/button"; +import { DownloadIcon } from "lucide-react"; export const Route = createFileRoute("/cover/$coverId")({ component: RouteComponent, @@ -26,14 +30,34 @@ function RouteComponent() { }, }); + // Handle png downloads + const coverRef = useRef(null); + + const handleDownload = async () => { + if (coverRef.current === null) return; + + const dataUrl = await toPng(coverRef.current, { + cacheBust: true, + pixelRatio: 2, + skipFonts: false, + }); + const link = document.createElement("a"); + link.download = `${cover.data?.cover.name || "Cover"}.png`; + link.href = dataUrl; + link.click(); + }; + return ( -
+

{cover.data?.cover.name || "Loading..."}

+ {/* edit buttons */}
-
+
{coverState !== null ? ( coverState ) : (