From 10c83a1431807c1f1c088a11d2f1e6efe5af976d Mon Sep 17 00:00:00 2001 From: Local Dev Date: Sun, 27 Sep 2026 13:16:07 +0200 Subject: [PATCH] feat(pdf-editor): type on the page, keep more than one signature, move what you drew MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three things the editor made you work around. Text was typed into a dialog and then placed, so you chose a size and a weight for words you could not see against the page they were going on. The click now opens a caret where you clicked, in the font, size and colour the words will have, with the style bar over it; double-clicking a stamp reopens it in place. Lining a CSS line box up with a PDF baseline is measured from the font's own metrics, not guessed. A signature lived in a single slot. There was nowhere to keep initials as well as a name, nowhere to change the one you had, and reaching for the tool again simply stamped the first one — which is the same fault three times: one slot. It is a library now, with redraw, rename and delete, and the choice is made when the tool is picked up, so placing stays one click. An existing single signature is carried into it rather than dropped. The mark you had just drawn could be resized by its handles and not moved by its middle, because only the select tool let marks be hit-tested at all. The SELECTED mark now takes a press whatever tool is armed. A press anywhere else still draws, and an unfilled shape is still grabbed by its outline — the same rule select has always followed. Also: words default to dark ink rather than highlighter yellow, which was unreadable on white and is now impossible to miss, since you watch yourself type it. --- bundled-addons/pdf-editor/addon.json | 2 +- bundled-addons/pdf-editor/editor.css | 34 +++ bundled-addons/pdf-editor/editor.html | 38 ++- bundled-addons/pdf-editor/editor.js | 288 +++++++++++++++++++-- bundled-addons/pdf-editor/lib/inline.js | 183 +++++++++++++ bundled-addons/pdf-editor/lib/overlay.js | 5 +- bundled-addons/pdf-editor/lib/signature.js | 20 ++ bundled-addons/pdf-editor/lib/tools.js | 56 +++- 8 files changed, 587 insertions(+), 39 deletions(-) create mode 100644 bundled-addons/pdf-editor/lib/inline.js diff --git a/bundled-addons/pdf-editor/addon.json b/bundled-addons/pdf-editor/addon.json index 8b88ad5b..61790177 100644 --- a/bundled-addons/pdf-editor/addon.json +++ b/bundled-addons/pdf-editor/addon.json @@ -1,7 +1,7 @@ { "id": "pdf-editor", "name": "PDF Editor", - "version": "0.4.0", + "version": "0.5.0", "description": "Open a PDF in a full tab: read it, mark it up with highlight, underline, strike-through, pen, shapes, arrows, text and a drawn signature, then move, resize, restyle or delete anything you placed. Reorder, rotate or drop pages, fill in form fields, redact for real, and save a new copy. Build a PDF from pictures, one page each, or join several PDFs into one. Marks are written into the saved file as real PDF content. The original is never touched.", "author": "Silent Mode", "icon": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTYgMmg4bDYgNnYxMmEyIDIgMCAwIDEtMiAySDZhMiAyIDAgMCAxLTItMlY0YTIgMiAwIDAgMSAyLTJ6IiBmaWxsPSIjZGMyNjI2Ii8+PHBhdGggZD0iTTE0IDJ2Nmg2eiIgZmlsbD0iIzk5MWIxYiIvPjx0ZXh0IHg9IjEyIiB5PSIxNyIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZm9udC1mYW1pbHk9InN5c3RlbS11aSwtYXBwbGUtc3lzdGVtLHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iNS41IiBmb250LXdlaWdodD0iODAwIiBmaWxsPSIjZmZmIj5QREY8L3RleHQ+PC9zdmc+", diff --git a/bundled-addons/pdf-editor/editor.css b/bundled-addons/pdf-editor/editor.css index aee789a5..633e91f4 100644 --- a/bundled-addons/pdf-editor/editor.css +++ b/bundled-addons/pdf-editor/editor.css @@ -160,6 +160,34 @@ body[data-dragover="1"] .dz-actions { visibility: hidden; } .linkish { background: none; border: none; padding: 0; font: inherit; cursor: pointer; color: var(--acid); text-decoration: underline; } +/* ---- typing on the page --------------------------------------------- */ +/* Positioned by lib/inline.js against the page's own coordinates, so it sits + where the text will sit. No background: the page is the background, which + is the whole point — you see the words against what they are going on. */ +.inline-text { position: absolute; z-index: 24; margin: 0; padding: 0; + min-width: 1px; white-space: pre; outline: none; + caret-color: currentColor; + box-shadow: 0 0 0 1px rgb(from var(--acid) r g b / .55), + 0 0 0 4px rgb(from var(--acid) r g b / .14); } +.inline-text:empty::before { content: ""; display: inline-block; width: 1px; } + +/* ---- signature library ---------------------------------------------- */ +.siglist { list-style: none; margin: 0 0 12px; padding: 0; display: grid; + gap: 8px; max-height: 40vh; overflow: auto; } +.sigrow { display: flex; align-items: center; gap: 10px; padding: 8px 10px; + border: 1px solid var(--line); border-radius: 9px; background: var(--bg); } +.sigrow .sigpreview { flex: 0 0 132px; height: 44px; } +.sigrow .sigpreview svg { width: 100%; height: 100%; } +.sigrow .signame { flex: 1 1 auto; min-width: 0; font-size: 13px; color: var(--ink); + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +/* flex: none on the buttons — without it they shrink below their own labels + and the words run into each other. The name gives way instead. */ +.sigrow .sigacts { display: flex; gap: 6px; flex: 0 0 auto; } +/* width: auto matters most — .btn is a 30px square by default, made for an + icon, and a word does not fit in one. */ +.sigrow .sigacts .btn { flex: none; width: auto; height: 26px; white-space: nowrap; + padding: 0 10px; font-size: 11.5px; line-height: 1; } + /* ---- modals --------------------------------------------------------- */ .scrim { position: fixed; inset: 0; background: rgba(4,7,12,.62); z-index: 50; display: flex; align-items: center; justify-content: center; padding: 24px; } @@ -232,6 +260,12 @@ body[data-mode="select"] .smOverlay { pointer-events: none; } body[data-mode="select"] .smOverlay .mark { pointer-events: stroke; cursor: move; } body[data-mode="select"] .smOverlay .mark[data-fill="1"] { pointer-events: all; } .smOverlay .mark.sel { outline: none; } +/* ...with one exception: the SELECTED mark stays grabbable whatever tool is + armed. Its handles already were, so a shape you had just drawn could be + stretched but not shifted. Only the selected one opts in, so a press + anywhere else still draws. */ +.smOverlay .mark.sel { pointer-events: stroke; cursor: move; } +.smOverlay .mark.sel[data-fill="1"] { pointer-events: all; } .smOverlay .selbox { fill: none; stroke: var(--acid); stroke-width: 1; stroke-dasharray: 4 3; vector-effect: non-scaling-stroke; } .smOverlay .handle { fill: var(--acid); stroke: #101418; stroke-width: 1; diff --git a/bundled-addons/pdf-editor/editor.html b/bundled-addons/pdf-editor/editor.html index dafbde70..21907b02 100644 --- a/bundled-addons/pdf-editor/editor.html +++ b/bundled-addons/pdf-editor/editor.html @@ -206,15 +206,35 @@