From e8dac65468ad847ce29dc2d748baaec7a0569d03 Mon Sep 17 00:00:00 2001 From: ramvignesh-b Date: Wed, 15 Apr 2026 19:20:18 +0530 Subject: [PATCH] feat: redesign reader page and disable canvas object caching for improved rendering --- frontend/e2e/letter.spec.ts | 8 +- frontend/src/components/ui/ComposeCanvas.tsx | 3 + frontend/src/components/ui/LogModal.tsx | 4 +- frontend/src/pages/Reader.tsx | 103 +++++++++++++------ 4 files changed, 78 insertions(+), 40 deletions(-) diff --git a/frontend/e2e/letter.spec.ts b/frontend/e2e/letter.spec.ts index 304ab1e..86911a6 100644 --- a/frontend/e2e/letter.spec.ts +++ b/frontend/e2e/letter.spec.ts @@ -174,14 +174,9 @@ test.describe("Letter Drafting (Real Backend)", () => { timeout: 10000, }); await expect( - page.getByText(new RegExp(`A sealed message for ${recipientName}`, "i")), + page.getByText(new RegExp(`A sealed letter for ${recipientName}`, "i")), ).toBeVisible(); - // Verify content is decrypted (using author's masterKey automatically) - await expect(page.getByText(/decrypting/i)).toBeHidden(); - // In the Reader, we check if the recipient name is visible in the Reader header. - await expect(page.getByText(/Drawer Test Recipient/i)).toBeVisible(); - // Also check if we are redirected to the Reader if we manually go to the Editor URL const readerUrl = page.url(); const quillUrl = readerUrl.replace("/read/", "/quill/"); @@ -192,6 +187,5 @@ test.describe("Letter Drafting (Real Backend)", () => { // It should redirect back to the reader await expect(page).toHaveURL(readerUrl); - await expect(page.getByText(/Drawer Test Recipient/i)).toBeVisible(); }); }); diff --git a/frontend/src/components/ui/ComposeCanvas.tsx b/frontend/src/components/ui/ComposeCanvas.tsx index f0f5012..cea1f5e 100644 --- a/frontend/src/components/ui/ComposeCanvas.tsx +++ b/frontend/src/components/ui/ComposeCanvas.tsx @@ -110,6 +110,8 @@ const initializeCanvas = ( selection: !readOnly, preserveObjectStacking: true, allowTouchScrolling: true, + enableRetinaScaling: true, + objectCaching: false, }); const wrapperEl = canvas.getElement().parentElement; @@ -279,6 +281,7 @@ export const ComposeCanvas = forwardRef< textbox.lockScalingX = true; textbox.lockScalingY = true; textbox.lockRotation = true; + textbox.objectCaching = false; logicalSizeRef.current.height = measureLogicalContentHeight( canvas, diff --git a/frontend/src/components/ui/LogModal.tsx b/frontend/src/components/ui/LogModal.tsx index 691ee92..017b1db 100644 --- a/frontend/src/components/ui/LogModal.tsx +++ b/frontend/src/components/ui/LogModal.tsx @@ -5,15 +5,17 @@ interface LogModalContent { message: string; log: string; onClose: () => void; + isOpen: boolean; } export const LogModal = ({ + isOpen, message, log, onClose, status, }: LogModalContent) => { - return status === "RESET" ? ( + return status === "RESET" || !isOpen ? (
) : (
diff --git a/frontend/src/pages/Reader.tsx b/frontend/src/pages/Reader.tsx index 72630a6..67a104d 100644 --- a/frontend/src/pages/Reader.tsx +++ b/frontend/src/pages/Reader.tsx @@ -1,12 +1,13 @@ -import { CrossIcon } from "@phosphor-icons/react"; import { useEffect, useRef, useState } from "react"; import { useLocation, useParams } from "react-router-dom"; import { api } from "../api/apiClient"; +import Logo from "../components/Logo"; import { type CanvasJSON, type CanvasTools, ComposeCanvas, } from "../components/ui/ComposeCanvas"; +import { LogModal } from "../components/ui/LogModal"; import { endpoints } from "../config/endpoints"; import { useKeyStore } from "../store/useKeyStore"; import { CryptoUtils } from "../utils/crypto"; @@ -114,7 +115,6 @@ export default function Reader() { log: err instanceof Error ? err.message : "Unknown error", }); } - setDecryptedCanvasData(canvasData); } catch (err) { const message = err instanceof Error ? err.message : "Unknown error"; @@ -135,9 +135,16 @@ export default function Reader() { if (isDecrypting) { return ( -
-
-

Decrypting...

+
+
+
+ +
+ +

+ Breaking the seal... +

+
); @@ -145,15 +152,23 @@ export default function Reader() { if (error) { return ( -
-
-

{error}

+
+
+
+
+

+ Something went wrong +

+

+ {error} +

+
@@ -161,40 +176,64 @@ export default function Reader() { } return ( -
- {warning && ( -
-
-

{warning.message}

-

{warning.log}

-
-
- )} -
-
-
+
+ {/* Background Ambience */} +
+ + setWarning(null)} + message={warning?.message} + log={warning?.log} + status="WARN" + /> + +
+ {/* Floating Header */} +
+
+ +
{metadata?.recipient && ( -

- A sealed message for{" "} - - {metadata.recipient || "Anonymous"} +

+ A sealed letter for{" "} + + {metadata.recipient}

)}
+ aria-label="Close" + >
-
- + {/* The Letter */} +
+
+ +
+
+ +
+ + {metadata?.recipient && ( +

+ For {metadata.recipient} +

+ )}
+ + {/* Atmospheric Footer */} +
); }