mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 19:33:11 +02:00
feat(sign): Add signature color picker and custom signature colors (#4441)
# Description of Changes Added sign custom colour as per #4413 ### Example doc [lorem-ipsum_signed.pdf](https://github.com/user-attachments/files/22310651/lorem-ipsum_signed.pdf) ### UI/Picture <img width="771" height="553" alt="image" src="https://github.com/user-attachments/assets/3a715723-d281-4175-8a33-c68cb53e2b47" /> <img width="514" height="445" alt="image" src="https://github.com/user-attachments/assets/c928fbb2-63db-4f44-bc15-9b556af7b3a5" /> <img width="514" height="445" alt="image" src="https://github.com/user-attachments/assets/ea31f2f2-9790-4166-9d33-69771546858d" /> Closes #4413 <!-- Please provide a summary of the changes, including: - What was changed - Why the change was made - Any challenges encountered Closes #(issue_number) --> --- ## Checklist ### General - [x] I have read the [Contribution Guidelines](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/CONTRIBUTING.md) - [x] I have read the [Stirling-PDF Developer Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md) (if applicable) - [ ] I have read the [How to add new languages to Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md) (if applicable) - [x] I have performed a self-review of my own code - [x] My changes generate no new warnings ### Documentation - [ ] I have updated relevant docs on [Stirling-PDF's doc repo](https://github.com/Stirling-Tools/Stirling-Tools.github.io/blob/main/docs/) (if functionality has heavily changed) - [ ] I have read the section [Add New Translation Tags](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md#add-new-translation-tags) (for new translation tags only) ### UI Changes (if applicable) - [x] Screenshots or videos demonstrating the UI changes are attached (e.g., as comments or direct attachments in the PR) ### Testing (if applicable) - [x] I have tested my changes locally. Refer to the [Testing Guide](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/DeveloperGuide.md#6-testing) for more details. --------- Signed-off-by: Balázs Szücs <[email protected]> Co-authored-by: Anthony Stirling <[email protected]>
This commit is contained in:
co-authored by
Anthony Stirling
parent
51aa03b256
commit
69b2701fbf
@@ -1233,6 +1233,7 @@ sign.previous=Previous page
|
|||||||
sign.maintainRatio=Toggle maintain aspect ratio
|
sign.maintainRatio=Toggle maintain aspect ratio
|
||||||
sign.undo=Undo
|
sign.undo=Undo
|
||||||
sign.redo=Redo
|
sign.redo=Redo
|
||||||
|
sign.colour=Signature Colour
|
||||||
|
|
||||||
#repair
|
#repair
|
||||||
repair.title=Repair
|
repair.title=Repair
|
||||||
|
|||||||
@@ -10,6 +10,22 @@ select#font-select option {
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.signature-color-picker {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin: 0.5rem 0 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signature-color-picker input[type="color"] {
|
||||||
|
width: 42px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
border: 1px solid var(--bs-border-color, #ced4da);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
#drawing-pad-canvas {
|
#drawing-pad-canvas {
|
||||||
background: rgba(125, 125, 125, 0.2);
|
background: rgba(125, 125, 125, 0.2);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ window.goToFirstOrLastPage = goToFirstOrLastPage;
|
|||||||
|
|
||||||
let currentPreviewSrc = null;
|
let currentPreviewSrc = null;
|
||||||
|
|
||||||
|
function getSelectedSignatureColor() {
|
||||||
|
const textPicker = document.getElementById('signature-color-text');
|
||||||
|
const drawPicker = document.getElementById('signature-color');
|
||||||
|
return (textPicker && textPicker.value) || (drawPicker && drawPicker.value) || '#000000';
|
||||||
|
}
|
||||||
|
|
||||||
function toggleSignatureView() {
|
function toggleSignatureView() {
|
||||||
const gridView = document.getElementById("gridView");
|
const gridView = document.getElementById("gridView");
|
||||||
const listView = document.getElementById("listView");
|
const listView = document.getElementById("listView");
|
||||||
@@ -242,9 +248,19 @@ const signaturePadCanvas = document.getElementById("drawing-pad-canvas");
|
|||||||
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
||||||
minWidth: 1,
|
minWidth: 1,
|
||||||
maxWidth: 2,
|
maxWidth: 2,
|
||||||
penColor: "black",
|
penColor: "#000000",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Keep pad color in sync if draw picker exists
|
||||||
|
(function initPadColorSync() {
|
||||||
|
const drawPicker = document.getElementById('signature-color');
|
||||||
|
if (!drawPicker) return;
|
||||||
|
if (drawPicker.value) signaturePad.penColor = drawPicker.value;
|
||||||
|
drawPicker.addEventListener('input', () => {
|
||||||
|
signaturePad.penColor = drawPicker.value || '#000000';
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
function addDraggableFromPad() {
|
function addDraggableFromPad() {
|
||||||
if (signaturePad.isEmpty()) return;
|
if (signaturePad.isEmpty()) return;
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
@@ -328,6 +344,7 @@ function addDraggableFromText() {
|
|||||||
const sigText = document.getElementById("sigText").value;
|
const sigText = document.getElementById("sigText").value;
|
||||||
const font = document.querySelector("select[name=font]").value;
|
const font = document.querySelector("select[name=font]").value;
|
||||||
const fontSize = 100;
|
const fontSize = 100;
|
||||||
|
const color = getSelectedSignatureColor();
|
||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
@@ -340,6 +357,7 @@ function addDraggableFromText() {
|
|||||||
canvas.width = textWidth;
|
canvas.width = textWidth;
|
||||||
canvas.height = paragraphs.length * textHeight * 1.35; // for tails
|
canvas.height = paragraphs.length * textHeight * 1.35; // for tails
|
||||||
ctx.font = `${fontSize}px ${font}`;
|
ctx.font = `${fontSize}px ${font}`;
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
|
||||||
ctx.textBaseline = "top";
|
ctx.textBaseline = "top";
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,21 @@ const redoButton = document.getElementById("signature-redo-button");
|
|||||||
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
const signaturePad = new SignaturePad(signaturePadCanvas, {
|
||||||
minWidth: 1,
|
minWidth: 1,
|
||||||
maxWidth: 2,
|
maxWidth: 2,
|
||||||
penColor: 'black',
|
penColor: '#000000', // default color
|
||||||
});
|
});
|
||||||
|
|
||||||
|
(function initSignatureColor() {
|
||||||
|
const colorInput = document.getElementById('signature-color');
|
||||||
|
if (!colorInput) return;
|
||||||
|
|
||||||
|
if (colorInput.value) {
|
||||||
|
signaturePad.penColor = colorInput.value;
|
||||||
|
}
|
||||||
|
colorInput.addEventListener('input', () => {
|
||||||
|
signaturePad.penColor = colorInput.value || '#000000';
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
|
||||||
let undoData = [];
|
let undoData = [];
|
||||||
|
|
||||||
signaturePad.addEventListener("endStroke", () => {
|
signaturePad.addEventListener("endStroke", () => {
|
||||||
@@ -16,10 +28,10 @@ signaturePad.addEventListener("endStroke", () => {
|
|||||||
window.addEventListener("keydown", (event) => {
|
window.addEventListener("keydown", (event) => {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case event.key === "z" && event.ctrlKey:
|
case event.key === "z" && event.ctrlKey:
|
||||||
undoButton.click();
|
undoButton?.click();
|
||||||
break;
|
break;
|
||||||
case event.key === "y" && event.ctrlKey:
|
case event.key === "y" && event.ctrlKey:
|
||||||
redoButton.click();
|
redoButton?.click();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,6 +50,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-container drawing-pad-container" th:data-title="#{sign.draw}">
|
<div class="tab-container drawing-pad-container" th:data-title="#{sign.draw}">
|
||||||
|
<div class="signature-color-picker">
|
||||||
|
<label for="signature-color" th:text="#{sign.colour}">Signature Colour</label>
|
||||||
|
<input id="signature-color" name="signature-color" type="color" value="#000000" />
|
||||||
|
</div>
|
||||||
<canvas id="drawing-pad-canvas"></canvas>
|
<canvas id="drawing-pad-canvas"></canvas>
|
||||||
<br>
|
<br>
|
||||||
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()"
|
<button id="clear-signature" class="btn btn-outline-danger mt-2" onclick="signaturePad.clear()"
|
||||||
@@ -92,7 +96,7 @@
|
|||||||
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}"
|
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Personal'}"
|
||||||
class="small-file-container-saved d-flex flex-column justify-content-center align-items-center">
|
class="small-file-container-saved d-flex flex-column justify-content-center align-items-center">
|
||||||
<div class="drag-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
<div class="drag-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
|
fill="#e8eaed" viewBox="0 -960 960 960" width="24px">
|
||||||
<path
|
<path
|
||||||
d="M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z">
|
d="M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z">
|
||||||
</path>
|
</path>
|
||||||
@@ -114,7 +118,7 @@
|
|||||||
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}"
|
<div th:each="sig : ${signatures}" th:if="${sig.category == 'Shared'}"
|
||||||
class="small-file-container-saved d-flex flex-column justify-content-center align-items-center">
|
class="small-file-container-saved d-flex flex-column justify-content-center align-items-center">
|
||||||
<div class="drag-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
<div class="drag-icon"><svg xmlns="http://www.w3.org/2000/svg" height="24px"
|
||||||
viewBox="0 -960 960 960" width="24px" fill="#e8eaed">
|
fill="#e8eaed" viewBox="0 -960 960 960" width="24px">
|
||||||
<path
|
<path
|
||||||
d="M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z">
|
d="M360-160q-33 0-56.5-23.5T280-240q0-33 23.5-56.5T360-320q33 0 56.5 23.5T440-240q0 33-23.5 56.5T360-160Zm240 0q-33 0-56.5-23.5T520-240q0-33 23.5-56.5T600-320q33 0 56.5 23.5T680-240q0 33-23.5 56.5T600-160ZM360-400q-33 0-56.5-23.5T280-480q0-33 23.5-56.5T360-560q33 0 56.5 23.5T440-480q0 33-23.5 56.5T360-400Zm240 0q-33 0-56.5-23.5T520-480q0-33 23.5-56.5T600-560q33 0 56.5 23.5T680-480q0 33-23.5 56.5T600-400ZM360-640q-33 0-56.5-23.5T280-720q0-33 23.5-56.5T360-800q33 0 56.5 23.5T440-720q0 33-23.5 56.5T360-640Zm240 0q-33 0-56.5-23.5T520-720q0-33 23.5-56.5T600-800q33 0 56.5 23.5T680-720q0 33-23.5 56.5T600-640Z">
|
||||||
</path>
|
</path>
|
||||||
@@ -144,6 +148,11 @@
|
|||||||
th:class="${font.name.toLowerCase()+'-font'}"></option>
|
th:class="${font.name.toLowerCase()+'-font'}"></option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Color picker for text signatures -->
|
||||||
|
<div class="signature-color-picker">
|
||||||
|
<label for="signature-color-text" th:text="#{sign.colour}">Colour</label>
|
||||||
|
<input id="signature-color-text" name="signature-color-text" type="color" value="#000000" />
|
||||||
|
</div>
|
||||||
<div class="margin-auto-parent">
|
<div class="margin-auto-parent">
|
||||||
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center"
|
<button id="save-text-signature" class="btn btn-outline-success mt-2 margin-center"
|
||||||
onclick="addDraggableFromText()" th:text="#{sign.add}"></button>
|
onclick="addDraggableFromText()" th:text="#{sign.add}"></button>
|
||||||
|
|||||||
Reference in New Issue
Block a user