diff --git a/src/main/resources/static/css/dragdrop.css b/src/main/resources/static/css/dragdrop.css
new file mode 100644
index 00000000..e75a0d06
--- /dev/null
+++ b/src/main/resources/static/css/dragdrop.css
@@ -0,0 +1,78 @@
+#drag-container {
+ position: fixed;
+ display:flex;
+ inset: 0;
+ pointer-events: none;
+ z-index: 10000;
+ visibility: hidden;
+}
+
+#drag-container:not(:empty) {
+ visibility: visible;
+}
+
+#drag-container .dragged-img {
+ position: fixed;
+ max-width: 200px;
+ max-height: 200px;
+ box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.58);
+ transform-origin: top left;
+}
+
+.drag-manager_dragging {
+ width: 0px;
+ visibility: hidden;
+}
+
+.drag-manager_draghover {
+ width: 375px !important;
+}
+
+.drag-manager_draghover .insert-file-button-container {
+ display: none !important;
+}
+
+.drag-manager_draghover .button-container {
+ visibility: hidden !important;
+}
+
+html[lang-direction=ltr] .drag-manager_draghover img {
+ left: calc(50% + 62.5px) !important;
+}
+
+html[lang-direction=rtl] .drag-manager_draghover img {
+ left: 125px
+}
+
+.drag-manager_dragging-container .hide-on-drag {
+ display: none !important;
+}
+
+.drag-manager_endpoint {
+ width: 80px;
+ height: 100%;
+ background-color: #FFFFFF10;
+ transition: width 0.1s;
+ animation: end-drop-expand .3s ease;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.drag-manager_endpoint svg {
+ width: 50px;
+ height: 50px;
+}
+
+.drag-manager_endpoint.drag-manager_draghover {
+ width: 150px !important;
+}
+
+@keyframes end-drop-expand {
+ from {
+ width: 0;
+ }
+ to {
+ width: 80px;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/static/css/imageHighlighter.css b/src/main/resources/static/css/imageHighlighter.css
new file mode 100644
index 00000000..231895d6
--- /dev/null
+++ b/src/main/resources/static/css/imageHighlighter.css
@@ -0,0 +1,40 @@
+
+#image-highlighter {
+ position: fixed;
+ display:flex;
+ inset: 0;
+ z-index: 10000;
+ background-color: rgba(0, 0, 0, 0);
+ visibility: hidden;
+ align-items: center;
+ justify-content: center;
+ transition: visbility 0.1s linear, background-color 0.1s linear;
+}
+
+#image-highlighter > * {
+ max-width: 80vw;
+ max-height: 80vh;
+ animation: image-highlight .1s linear;
+ transition: transform .1s linear, opacity .1s linear;
+}
+
+#image-highlighter > *.remove {
+ transform: scale(0.8) !important;
+ opacity: 0 !important;
+}
+
+#image-highlighter:not(:empty) {
+ background-color: rgba(0, 0, 0, 0.37);
+ visibility: visible;
+}
+
+@keyframes image-highlight {
+ from {
+ transform: scale(0.8);
+ opacity: 0;
+ }
+ to {
+ transform: scale(1);
+ opacity: 1;
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/static/css/pdfActions.css b/src/main/resources/static/css/pdfActions.css
new file mode 100644
index 00000000..152e3ebc
--- /dev/null
+++ b/src/main/resources/static/css/pdfActions.css
@@ -0,0 +1,87 @@
+
+.pdf-actions_button-container {
+ z-index: 2;
+ display:flex;
+ opacity: 0;
+ transition: opacity 0.1s linear;
+}
+
+.pdf-actions_container:hover .pdf-actions_button-container {
+ opacity: 1;
+}
+
+.pdf-actions_button-container > * {
+ padding: 0.25rem 0.5rem;
+ margin: 3px;
+ display: block;
+}
+
+.pdf-actions_container svg {
+ width: 16px;
+ height: 16px;
+}
+.pdf-actions_container:nth-child(1) .pdf-actions_move-left-button {
+ display: none;
+}
+.pdf-actions_container:last-child .pdf-actions_move-right-button {
+ display: none;
+}
+
+/* "insert pdf" buttons that appear on the right when hover */
+.pdf-actions_insert-file-button-container {
+ translate: 0 -50%;
+ width: 80px;
+ height: 100%;
+
+ z-index: 1;
+ opacity: 0;
+ transition: opacity 0.2s;
+}
+
+.pdf-actions_insert-file-button-container.left {
+ left: -20px;
+}
+
+.pdf-actions_insert-file-button-container.right {
+ right: -20px;
+}
+
+html[lang-direction=ltr] .pdf-actions_insert-file-button-container.right {
+ display:none;
+}
+
+html[lang-direction=rtl] .pdf-actions_insert-file-button-container.left {
+ display:none;
+}
+
+.pdf-actions_insert-file-button-container.left .pdf-actions_insert-file-button {
+ left: 0;
+ translate: 0 -50%;
+}
+
+.pdf-actions_insert-file-button-container.right .pdf-actions_insert-file-button {
+ right: 0;
+ translate: 0 -50%;
+}
+
+html[lang-direction=ltr] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.right {
+ display: block;
+}
+
+
+html[lang-direction=rtl] .pdf-actions_container:last-child > .pdf-actions_insert-file-button-container.left {
+ display: block;
+}
+
+.pdf-actions_insert-file-button-container:hover {
+ opacity: 1;
+ transition: opacity 0.05s;
+}
+.pdf-actions_insert-file-button {
+ position: absolute;
+ top: 50%;
+ right: 50%;
+ translate: 50% -50%;
+ aspect-ratio: 1;
+ border-radius: 100px;
+}
\ No newline at end of file
diff --git a/src/main/resources/static/js/multitool/DragDropManager.js b/src/main/resources/static/js/multitool/DragDropManager.js
new file mode 100644
index 00000000..93fbbdf1
--- /dev/null
+++ b/src/main/resources/static/js/multitool/DragDropManager.js
@@ -0,0 +1,127 @@
+
+
+class DragDropManager {
+ dragContainer;
+ wrapper;
+ pageDirection;
+ movePageTo;
+ pageDragging;
+ draggelEl;
+ draggedImageEl;
+ hoveredEl;
+ endInsertionElement;
+
+ constructor(id, wrapperId) {
+ this.dragContainer = document.getElementById(id);
+ this.pageDirection = document.documentElement.getAttribute("lang-direction");
+ this.wrapper = document.getElementById(wrapperId);
+ this.pageDragging = false;
+ this.hoveredEl = undefined;
+ this.draggelEl = undefined
+ this.draggedImageEl = undefined;
+
+ var styleElement = document.createElement('link');
+ styleElement.rel = 'stylesheet';
+ styleElement.href = 'css/dragdrop.css'
+
+ document.head.appendChild(styleElement);
+
+ const div = document.createElement('div');
+ div.classList.add('drag-manager_endpoint');
+ div.innerHTML = ``
+ this.endInsertionElement = div;
+
+ this.startDraggingPage = this.startDraggingPage.bind(this);
+ this.onDragEl = this.onDragEl.bind(this);
+ this.stopDraggingPage = this.stopDraggingPage.bind(this);
+
+ this.adapt(div);
+ }
+
+ startDraggingPage(div,) {
+ this.pageDragging = true;
+ this.draggedEl = div;
+ const img = div.querySelector('img');
+ div.classList.add('drag-manager_dragging');
+ const imageSrc = img.src;
+
+ const imgEl = document.createElement('img');
+ imgEl.classList.add('dragged-img');
+ imgEl.src = imageSrc;
+ this.draggedImageEl = imgEl;
+ imgEl.style.left = screenX;
+ imgEl.style.right = screenY;
+ imgEl.style.transform = `rotate(${img.style.rotate === '' ? '0deg' : img.style.rotate}) translate(-50%, -50%)`;
+ this.dragContainer.appendChild(imgEl);
+
+ window.addEventListener('mouseup', this.stopDraggingPage)
+ window.addEventListener('mousemove', this.onDragEl)
+ this.wrapper.classList.add('drag-manager_dragging-container');
+ this.wrapper.appendChild(this.endInsertionElement);
+ }
+
+ onDragEl(mouseEvent) {
+ const { clientX, clientY } = mouseEvent;
+ if(this.draggedImageEl) {
+ this.draggedImageEl.style.left = `${clientX}px`;
+ this.draggedImageEl.style.top = `${clientY}px`;
+ }
+ }
+
+
+ stopDraggingPage() {
+ window.removeEventListener('mousemove', this.onDragEl);
+ this.wrapper.classList.remove('drag-manager_dragging-container');
+ this.wrapper.removeChild(this.endInsertionElement);
+ window.removeEventListener('mouseup', this.stopDraggingPage)
+ this.draggedImageEl = undefined;
+ this.pageDragging = false;
+ this.draggedEl.classList.remove('drag-manager_dragging');
+ this.hoveredEl?.classList.remove('drag-manager_draghover');
+ this.dragContainer.childNodes.forEach((dragChild) => {
+ this.dragContainer.removeChild(dragChild);
+ })
+ if(!this.hoveredEl) {
+ return;
+ }
+ if(this.hoveredEl === this.endInsertionElement) {
+ this.movePageTo(this.draggedEl);
+ return;
+ }
+ this.movePageTo(this.draggedEl, this.hoveredEl);
+ }
+
+ setActions({ movePageTo }) {
+ this.movePageTo = movePageTo;
+ }
+
+
+ adapt(div) {
+ const onDragStart = () => {
+ this.startDraggingPage(div);
+ }
+
+ const onMouseEnter = () => {
+ if (this.pageDragging) {
+ this.hoveredEl = div;
+ div.classList.add('drag-manager_draghover');
+ }
+ }
+
+ const onMouseLeave = () => {
+ this.hoveredEl = undefined
+ div.classList.remove('drag-manager_draghover');
+ }
+
+ div.addEventListener('dragstart', onDragStart);
+ div.addEventListener('mouseenter', onMouseEnter);
+ div.addEventListener('mouseleave', onMouseLeave);
+
+ return div;
+ }
+}
+
+export default DragDropManager;
\ No newline at end of file
diff --git a/src/main/resources/static/js/multitool/ImageHighlighter.js b/src/main/resources/static/js/multitool/ImageHighlighter.js
new file mode 100644
index 00000000..6f7cd22e
--- /dev/null
+++ b/src/main/resources/static/js/multitool/ImageHighlighter.js
@@ -0,0 +1,46 @@
+class ImageHiglighter {
+ imageHighlighter;
+ constructor(id) {
+ this.imageHighlighter = document.getElementById(id);
+ this.imageHighlightCallback = this.imageHighlightCallback.bind(this);
+
+ var styleElement = document.createElement('link');
+ styleElement.rel = 'stylesheet';
+ styleElement.href = 'css/imageHighlighter.css'
+
+ document.head.appendChild(styleElement);
+
+ this.imageHighlighter.onclick = () => {
+ this.imageHighlighter.childNodes.forEach((child) => {
+ child.classList.add('remove');
+ setTimeout(() => {
+ this.imageHighlighter.removeChild(child);
+ }, 100)
+ })
+ }
+ }
+
+ imageHighlightCallback(highlightEvent) {
+ var bigImg = document.createElement('img');
+ bigImg.onclick = (imageClickEvent) => {
+ // This prevents the highlighter's onClick from closing the image when clicking
+ // on the image instead of next to it.
+ imageClickEvent.preventDefault();
+ imageClickEvent.stopPropagation();
+ };
+ bigImg.src = highlightEvent.target.src;
+ this.imageHighlighter.appendChild(bigImg);
+ };
+
+ setActions() {
+ // not needed in this case
+ }
+
+ adapt(div) {
+ const img = div.querySelector('.page-image');
+ img.addEventListener('click', this.imageHighlightCallback)
+ return div;
+ }
+}
+
+export default ImageHiglighter;
\ No newline at end of file
diff --git a/src/main/resources/static/js/multitool/PdfActionsManager.js b/src/main/resources/static/js/multitool/PdfActionsManager.js
new file mode 100644
index 00000000..4bff39e3
--- /dev/null
+++ b/src/main/resources/static/js/multitool/PdfActionsManager.js
@@ -0,0 +1,167 @@
+class PdfActionsManager {
+ pageDirection;
+ pagesContainer;
+
+ constructor(id) {
+ this.pagesContainer = document.getElementById(id);
+ this.pageDirection = document.documentElement.getAttribute("lang-direction");
+
+ var styleElement = document.createElement('link');
+ styleElement.rel = 'stylesheet';
+ styleElement.href = 'css/pdfActions.css'
+
+ document.head.appendChild(styleElement);
+ }
+
+ getPageContainer(element) {
+ var container = element
+ while (!container.classList.contains('page-container')) {
+ container = container.parentNode;
+ }
+ return container;
+ }
+
+ moveUpButtonCallback(e) {
+ var imgContainer = this.getPageContainer(e.target);
+
+ const sibling = imgContainer.previousSibling;
+ if (sibling) {
+ this.movePageTo(imgContainer, sibling, true);
+ }
+ }
+
+ moveDownButtonCallback(e) {
+ var imgContainer = this.getPageContainer(e.target);
+ const sibling = imgContainer.nextSibling;
+ if (sibling) {
+ this.movePageTo(imgContainer, sibling.nextSibling, true);
+ }
+ };
+
+ rotateCCWButtonCallback(e) {
+ var imgContainer = this.getPageContainer(e.target);
+ const img = imgContainer.querySelector("img");
+
+ this.rotateElement(img, -90)
+ };
+
+ rotateCWButtonCallback(e) {
+ var imgContainer = this.getPageContainer(e.target);
+ const img = imgContainer.querySelector("img");
+
+ this.rotateElement(img, 90)
+ };
+
+ deletePageButtonCallback(e) {
+ var imgContainer = this.getPageContainer(e.target);
+ this.pagesContainer.removeChild(imgContainer);
+ };
+
+ insertFileButtonCallback(e) {
+ var imgContainer = this.getPageContainer(e.target);
+ this.addPdfs(imgContainer)
+ };
+
+ setActions({ movePageTo, addPdfs, rotateElement }) {
+ this.movePageTo = movePageTo;
+ this.addPdfs = addPdfs;
+ this.rotateElement = rotateElement;
+
+ this.moveUpButtonCallback = this.moveUpButtonCallback.bind(this);
+ this.moveDownButtonCallback = this.moveDownButtonCallback.bind(this);
+ this.rotateCCWButtonCallback = this.rotateCCWButtonCallback.bind(this);
+ this.rotateCWButtonCallback = this.rotateCWButtonCallback.bind(this);
+ this.deletePageButtonCallback = this.deletePageButtonCallback.bind(this);
+ this.insertFileButtonCallback = this.insertFileButtonCallback.bind(this);
+ }
+
+ adapt(div) {
+ div.classList.add('pdf-actions_container');
+ const leftDirection = this.pageDirection === 'rtl' ? 'right' : 'left'
+ const rightDirection = this.pageDirection === 'rtl' ? 'left' : 'right'
+ const buttonContainer = document.createElement('div');
+
+ buttonContainer.classList.add("pdf-actions_button-container", "hide-on-drag");
+
+ const moveUp = document.createElement('button');
+ moveUp.classList.add("pdf-actions_move-left-button","btn", "btn-secondary");
+ moveUp.innerHTML = ``;
+ moveUp.onclick = this.moveUpButtonCallback;
+ buttonContainer.appendChild(moveUp);
+
+ const moveDown = document.createElement('button');
+ moveDown.classList.add("pdf-actions_move-right-button","btn", "btn-secondary");
+ moveDown.innerHTML = ``;
+ moveDown.onclick = this.moveDownButtonCallback;
+ buttonContainer.appendChild(moveDown);
+
+ const rotateCCW = document.createElement('button');
+ rotateCCW.classList.add("btn", "btn-secondary");
+ rotateCCW.innerHTML = ``;
+ rotateCCW.onclick = this.rotateCCWButtonCallback;
+ buttonContainer.appendChild(rotateCCW);
+
+ const rotateCW = document.createElement('button');
+ rotateCW.classList.add("btn", "btn-secondary");
+ rotateCW.innerHTML = ``;
+ rotateCW.onclick = this.rotateCWButtonCallback;
+ buttonContainer.appendChild(rotateCW);
+
+ const deletePage = document.createElement('button');
+ deletePage.classList.add("btn", "btn-danger");
+ deletePage.innerHTML = ``;
+ deletePage.onclick = this.deletePageButtonCallback;
+ buttonContainer.appendChild(deletePage);
+
+ div.appendChild(buttonContainer);
+
+ const insertFileButtonContainer = document.createElement('div');
+
+ insertFileButtonContainer.classList.add(
+ "pdf-actions_insert-file-button-container",
+ leftDirection,
+ `align-center-${leftDirection}`);
+
+ const insertFileButton = document.createElement('button');
+ insertFileButton.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
+ insertFileButton.innerHTML = ``;
+ insertFileButton.onclick = this.insertFileButtonCallback;
+ insertFileButtonContainer.appendChild(insertFileButton);
+
+ div.appendChild(insertFileButtonContainer);
+
+ // add this button to every element, but only show it on the last one :D
+ const insertFileButtonRightContainer = document.createElement('div');
+ insertFileButtonRightContainer.classList.add(
+ "pdf-actions_insert-file-button-container",
+ rightDirection,
+ `align-center-${rightDirection}`);
+
+ const insertFileButtonRight = document.createElement('button');
+ insertFileButtonRight.classList.add("btn", "btn-primary", "pdf-actions_insert-file-button");
+ insertFileButtonRight.innerHTML = ``;
+ insertFileButtonRight.onclick = () => addPdfs();
+ insertFileButtonRightContainer.appendChild(insertFileButtonRight);
+
+ div.appendChild(insertFileButtonRightContainer);
+
+ return div;
+ }
+}
+
+export default PdfActionsManager;
\ No newline at end of file
diff --git a/src/main/resources/static/js/multitool/PdfContainer.js b/src/main/resources/static/js/multitool/PdfContainer.js
new file mode 100644
index 00000000..f1cc1061
--- /dev/null
+++ b/src/main/resources/static/js/multitool/PdfContainer.js
@@ -0,0 +1,206 @@
+class PdfContainer {
+ fileName;
+ pagesContainer;
+ pagesContainerWrapper;
+ pdfAdapters;
+
+ constructor(id, wrapperId, pdfAdapters) {
+ this.fileName = null;
+ this.pagesContainer = document.getElementById(id)
+ this.pagesContainerWrapper = document.getElementById(wrapperId);
+ this.movePageTo = this.movePageTo.bind(this);
+ this.addPdfs = this.addPdfs.bind(this);
+ this.rotateElement = this.rotateElement.bind(this);
+ this.rotateAll = this.rotateAll.bind(this);
+ this.exportPdf = this.exportPdf.bind(this);
+
+ this.pdfAdapters = pdfAdapters;
+
+ this.pdfAdapters.forEach(adapter => {
+ adapter.setActions({
+ movePageTo: this.movePageTo,
+ addPdfs: this.addPdfs,
+ rotateElement: this.rotateElement,
+ })
+ })
+
+ window.addPdfs = this.addPdfs;
+ window.exportPdf = this.exportPdf;
+ window.rotateAll = this.rotateAll;
+ }
+
+ movePageTo(startElement, endElement, scrollTo = false) {
+ const childArray = Array.from(this.pagesContainer.childNodes);
+ const startIndex = childArray.indexOf(startElement);
+ const endIndex = childArray.indexOf(endElement);
+ this.pagesContainer.removeChild(startElement);
+ if(!endElement) {
+ this.pagesContainer.append(startElement);
+ } else {
+ this.pagesContainer.insertBefore(startElement, endElement);
+ }
+
+ if(scrollTo) {
+ const { width } = startElement.getBoundingClientRect();
+ const vector = (endIndex !== -1 && startIndex > endIndex)
+ ? 0-width
+ : width;
+
+ this.pagesContainerWrapper.scroll({
+ left: this.pagesContainerWrapper.scrollLeft + vector,
+ })
+ }
+ }
+
+ addPdfs(nextSiblingElement) {
+ var input = document.createElement('input');
+ input.type = 'file';
+ input.multiple = true;
+ input.setAttribute("accept", "application/pdf");
+
+ input.onchange = async(e) => {
+ const files = e.target.files;
+ this.fileName = files[0].name;
+ for (var i=0; i < files.length; i++) {
+ this.addPdfFile(files[i], nextSiblingElement);
+ }
+
+ document.querySelectorAll(".enable-on-file").forEach(element => {
+ element.disabled = false;
+ });
+ }
+
+ input.click();
+ }
+
+ rotateElement(element, deg) {
+ var lastTransform = element.style.rotate;
+ if (!lastTransform) {
+ lastTransform = "0";
+ }
+ const lastAngle = parseInt(lastTransform.replace(/[^\d-]/g, ''));
+ const newAngle = lastAngle + deg;
+
+ element.style.rotate = newAngle + "deg";
+ }
+
+ async addPdfFile(file, nextSiblingElement) {
+ const { renderer, pdfDocument } = await this.loadFile(file);
+
+ for (var i=0; i < renderer.pageCount; i++) {
+ const div = document.createElement('div');
+
+ div.classList.add("page-container");
+
+ var img = document.createElement('img');
+ img.classList.add('page-image')
+ const imageSrc = await renderer.renderPage(i)
+ img.src = imageSrc;
+ img.pageIdx = i;
+ img.rend = renderer;
+ img.doc = pdfDocument;
+ div.appendChild(img);
+
+ this.pdfAdapters.forEach((adapter) => {
+ adapter.adapt?.(div)
+ })
+ if (nextSiblingElement) {
+ this.pagesContainer.insertBefore(div, nextSiblingElement);
+ } else {
+ this.pagesContainer.appendChild(div);
+ }
+ }
+ }
+
+ async loadFile(file) {
+ var objectUrl = URL.createObjectURL(file);
+ var pdfDocument = await this.toPdfLib(objectUrl);
+ var renderer = await this.toRenderer(objectUrl);
+ return { renderer, pdfDocument };
+ }
+
+ async toRenderer(objectUrl) {
+ const pdf = await pdfjsLib.getDocument(objectUrl).promise;
+ return {
+ document: pdf,
+ pageCount: pdf.numPages,
+ renderPage: async function(pageIdx) {
+ const page = await this.document.getPage(pageIdx+1);
+
+ const canvas = document.createElement("canvas");
+
+ // set the canvas size to the size of the page
+ if (page.rotate == 90 || page.rotate == 270) {
+ canvas.width = page.view[3];
+ canvas.height = page.view[2];
+ } else {
+ canvas.width = page.view[2];
+ canvas.height = page.view[3];
+ }
+
+ // render the page onto the canvas
+ var renderContext = {
+ canvasContext: canvas.getContext("2d"),
+ viewport: page.getViewport({ scale: 1 })
+ };
+
+ await page.render(renderContext).promise;
+ return canvas.toDataURL();
+ }
+ };
+ }
+
+ async toPdfLib(objectUrl) {
+ const existingPdfBytes = await fetch(objectUrl).then(res => res.arrayBuffer());
+ const pdfDoc = await PDFLib.PDFDocument.load(existingPdfBytes);
+ return pdfDoc;
+ }
+
+
+
+ rotateAll(deg) {
+ for (var i=0; i {
+ var scrollDelta = 0; // variable to store the accumulated scroll delta
+ var isScrolling = false; // variable to track if scroll is already in progress
+ const divToScrollHorizontally = document.getElementById(id)
+ function scrollLoop() {
+ // Scroll the div horizontally by a fraction of the accumulated scroll delta
+ divToScrollHorizontally.scrollLeft += scrollDelta * 0.1;
+
+ // Reduce the accumulated scroll delta by a fraction
+ scrollDelta *= 0.9;
+
+ // If scroll delta is still significant, continue the scroll loop
+ if (Math.abs(scrollDelta) > 0.1) {
+ requestAnimationFrame(scrollLoop);
+ } else {
+ isScrolling = false; // Reset scroll in progress flag
+ }
+ }
+
+
+ divToScrollHorizontally.addEventListener("wheel", function(e) {
+ e.preventDefault(); // prevent default mousewheel behavior
+
+ // Accumulate the horizontal scroll delta
+ scrollDelta -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY;
+
+ // If scroll is not already in progress, start the scroll loop
+ if (!isScrolling) {
+ isScrolling = true;
+ requestAnimationFrame(scrollLoop);
+ }
+ });
+}
+
+export default scrollDivHorizontally;
diff --git a/src/main/resources/templates/multi-tool.html b/src/main/resources/templates/multi-tool.html
index 5d911403..2c6944b0 100644
--- a/src/main/resources/templates/multi-tool.html
+++ b/src/main/resources/templates/multi-tool.html
@@ -3,7 +3,6 @@
-
@@ -53,390 +52,40 @@
-
+
+
+