Update: updated all pages to new theme system

This commit is contained in:
Rectos VX 2024-05-05 15:19:53 +04:00
parent 5c572a7d89
commit 303b8e032b
68 changed files with 1866 additions and 1250 deletions

View file

@ -11,7 +11,7 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"></div> <div class="col-md-6" id="bg-card"></div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,23 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{account.title})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{account.title})}"></th:block>
</head> </head>
<body> <body>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9"> <div class="col-md-9" id="bg-card">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2> <h2 class="text-center" th:text="#{account.accountSettings}">User Settings</h2>
<hr> <th:block th:if="${param.messageType != null and param.messageType.size() > 0}">
<th:block th:if="${param.messageType != null and param.messageType.size() > 0}">
<div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'notAuthenticated'}" class="alert alert-danger">
<span th:text="#{notAuthenticatedMessage}">Default message if not found</span> <span th:text="#{notAuthenticatedMessage}">Default message if not found</span>
</div> </div>
@ -33,251 +34,266 @@
<div th:if="${param.messageType[0] == 'invalidUsername'}" class="alert alert-danger"> <div th:if="${param.messageType[0] == 'invalidUsername'}" class="alert alert-danger">
<span th:text="#{invalidUsernameMessage}">Default message if not found</span> <span th:text="#{invalidUsernameMessage}">Default message if not found</span>
</div> </div>
</th:block> </th:block>
<!-- At the top of the user settings --> <!-- At the top of the user settings -->
<h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3> <h3 class="text-center"><span th:text="#{welcome} + ' ' + ${username}">User</span>!</h3>
<th:block th:if="${error}"> <th:block th:if="${error}">
<div class="alert alert-danger" role="alert"> <div class="alert alert-danger" role="alert">
<span th:text="${error}">Error Message</span> <span th:text="${error}">Error Message</span>
</div> </div>
</th:block> </th:block>
<!-- Change Username Form --> <!-- Change Username Form -->
<form action="api/v1/user/change-username" method="post"> <h4 th:text="#{account.changeUsername}">Change Username?</h4>
<div class="mb-3"> <form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-username" method="post">
<label for="newUsername" th:text="#{account.changeUsername}">Change Username</label> <div class="mb-3">
<input type="text" class="form-control" name="newUsername" id="newUsername" th:placeholder="#{account.newUsername}"> <label for="newUsername" th:text="#{account.newUsername}">Change Username</label>
</div> <input type="text" class="form-control" name="newUsername" id="newUsername"
<div class="mb-3"> th:placeholder="#{account.newUsername}">
<label for="currentPassword" th:text="#{password}">Password</label> </div>
<input type="password" class="form-control" name="currentPassword" id="currentPassword" th:placeholder="#{password}"> <div class="mb-3">
</div> <label for="currentPassword" th:text="#{password}">Password</label>
<div class="mb-3"> <input type="password" class="form-control" name="currentPassword" id="currentPassword"
<button type="submit" class="btn btn-primary" th:text="#{account.changeUsername}">Change Username</button> th:placeholder="#{password}">
</div> </div>
</form> <div class="mb-3">
<button type="submit" class="btn btn-primary" th:text="#{account.changeUsername}">Change
Username</button>
</div>
</form>
<hr> <!-- Separator Line --> <!-- Change Password Form -->
<h4 th:text="#{account.changePassword}">Change Password?</h4>
<form id="bg-card" class="mt-4 mb-4" action="api/v1/user/change-password" method="post">
<div class="mb-3">
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label>
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword"
th:placeholder="#{account.oldPassword}">
</div>
<div class="mb-3">
<label for="newPassword" th:text="#{account.newPassword}">New Password</label>
<input type="password" class="form-control" name="newPassword" id="newPassword"
th:placeholder="#{account.newPassword}">
</div>
<div class="mb-3">
<label for="confirmNewPassword" th:text="#{account.confirmNewPassword}">Confirm New Password</label>
<input type="password" class="form-control" name="confirmNewPassword" id="confirmNewPassword"
th:placeholder="#{account.confirmNewPassword}">
</div>
<div class="mb-3">
<button type="submit" class="btn btn-primary" th:text="#{account.changePassword}">Change
Password</button>
</div>
</form>
<!-- Change Password Form --> <!-- API Key Form -->
<h4 th:text="#{account.changePassword}">Change Password?</h4> <h4 th:text="#{account.yourApiKey}">API Key</h4>
<form action="api/v1/user/change-password" method="post"> <div class="card mt-4 mb-4">
<div class="mb-3"> <div class="card-header" th:text="#{account.yourApiKey}"></div>
<label for="currentPassword" th:text="#{account.oldPassword}">Old Password</label> <div class="card-body">
<input type="password" class="form-control" name="currentPassword" id="currentPasswordPassword" th:placeholder="#{account.oldPassword}"> <div class="input-group mb-3">
</div> <input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}"
<div class="mb-3"> readonly>
<label for="newPassword" th:text="#{account.newPassword}">New Password</label> <div class="input-group-append">
<input type="password" class="form-control" name="newPassword" id="newPassword" th:placeholder="#{account.newPassword}"> <button class="btn btn-secondary" id="copyBtn" type="button" onclick="copyToClipboard()">
</div> <span class="material-symbols-rounded">
<div class="mb-3"> content_copy
<label for="confirmNewPassword" th:text="#{account.confirmNewPassword}">Confirm New Password</label> </span>
<input type="password" class="form-control" name="confirmNewPassword" id="confirmNewPassword" th:placeholder="#{account.confirmNewPassword}"> </button>
</div> <button class="btn btn-secondary" id="showBtn" type="button" onclick="showApiKey()">
<div class="mb-3"> <span class="material-symbols-rounded" id="eyeIcon">
<button type="submit" class="btn btn-primary" th:text="#{account.changePassword}">Change Password</button> visibility
</div> </span>
</form> </button>
<button class="btn btn-secondary" id="refreshBtn" type="button" onclick="refreshApiKey()">
<hr> <span class="material-symbols-rounded">
refresh
<div class="card"> </span>
<div class="card-header" th:text="#{account.yourApiKey}"></div> </button>
<div class="card-body">
<div class="input-group mb-3">
<input type="password" class="form-control" id="apiKey" th:placeholder="#{account.yourApiKey}" readonly>
<div class="input-group-append">
<button class="btn btn-outline-secondary" id="copyBtn" type="button" onclick="copyToClipboard()">
<img class="blackwhite-icon" src="images/clipboard.svg" alt="Copy" style="height:20px;">
</button>
<button class="btn btn-outline-secondary" id="showBtn" type="button" onclick="showApiKey()">
<img class="blackwhite-icon" id="eyeIcon" src="images/eye.svg" alt="Toggle API Key Visibility" style="height:20px;">
</button>
<button class="btn btn-outline-secondary" id="refreshBtn" type="button" onclick="refreshApiKey()">
<img class="blackwhite-icon" id="arrowIcon" src="images/arrow-clockwise.svg" alt="Refresh API-Key" style="height:20px;">
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<script> <script>
function copyToClipboard() { function copyToClipboard() {
const apiKeyElement = document.getElementById("apiKey"); const apiKeyElement = document.getElementById("apiKey");
apiKeyElement.select(); apiKeyElement.select();
document.execCommand("copy"); document.execCommand("copy");
}
function showApiKey() {
const apiKeyElement = document.getElementById("apiKey");
const copyBtn = document.getElementById("copyBtn");
const eyeIcon = document.getElementById("eyeIcon");
if (apiKeyElement.type === "password") {
apiKeyElement.type = "text";
eyeIcon.textContent = "visibility_off";
copyBtn.disabled = false; // Enable copy button when API key is visible
} else {
apiKeyElement.type = "password";
eyeIcon.textContent = "visibility";
copyBtn.disabled = true; // Disable copy button when API key is hidden
} }
}
function showApiKey() { document.addEventListener("DOMContentLoaded", async function () {
const apiKeyElement = document.getElementById("apiKey"); try {
const copyBtn = document.getElementById("copyBtn"); let response = await fetch('/api/v1/user/get-api-key', { method: 'POST' });
const eyeIcon = document.getElementById("eyeIcon"); if (response.status === 200) {
if (apiKeyElement.type === "password") { let apiKey = await response.text();
apiKeyElement.type = "text"; manageUIState(apiKey);
eyeIcon.src = "images/eye-slash.svg";
copyBtn.disabled = false; // Enable copy button when API key is visible
} else { } else {
apiKeyElement.type = "password"; manageUIState(null);
eyeIcon.src = "images/eye.svg";
copyBtn.disabled = true; // Disable copy button when API key is hidden
} }
} catch (error) {
console.error('There was an error:', error);
} }
});
document.addEventListener("DOMContentLoaded", async function() { async function refreshApiKey() {
try { try {
let response = await fetch('/api/v1/user/get-api-key', { method: 'POST' }); let response = await fetch('/api/v1/user/update-api-key', { method: 'POST' });
if (response.status === 200) { if (response.status === 200) {
let apiKey = await response.text(); let apiKey = await response.text();
manageUIState(apiKey); manageUIState(apiKey);
} else { document.getElementById("apiKey").type = 'text';
manageUIState(null); document.getElementById("copyBtn").disabled = false;
}
} catch (error) {
console.error('There was an error:', error);
}
});
async function refreshApiKey() {
try {
let response = await fetch('/api/v1/user/update-api-key', { method: 'POST' });
if (response.status === 200) {
let apiKey = await response.text();
manageUIState(apiKey);
document.getElementById("apiKey").type = 'text';
document.getElementById("copyBtn").disabled = false;
} else {
alert('Error refreshing API key.');
}
} catch (error) {
console.error('There was an error:', error);
}
}
function manageUIState(apiKey) {
const apiKeyElement = document.getElementById("apiKey");
const showBtn = document.getElementById("showBtn");
const copyBtn = document.getElementById("copyBtn");
if (apiKey && apiKey.trim().length > 0) {
apiKeyElement.value = apiKey;
showBtn.disabled = false;
copyBtn.disabled = true;
} else { } else {
apiKeyElement.value = ""; alert('Error refreshing API key.');
showBtn.disabled = true;
copyBtn.disabled = true;
} }
} catch (error) {
console.error('There was an error:', error);
} }
}
document.addEventListener("DOMContentLoaded", function() { function manageUIState(apiKey) {
const form = document.querySelector('form[action="api/v1/user/change-password"]'); const apiKeyElement = document.getElementById("apiKey");
const showBtn = document.getElementById("showBtn");
const copyBtn = document.getElementById("copyBtn");
form.addEventListener('submit', function(event) { if (apiKey && apiKey.trim().length > 0) {
const newPassword = document.getElementById('newPassword').value; apiKeyElement.value = apiKey;
const confirmNewPassword = document.getElementById('confirmNewPassword').value; showBtn.disabled = false;
copyBtn.disabled = true;
} else {
apiKeyElement.value = "";
showBtn.disabled = true;
copyBtn.disabled = true;
}
}
if (newPassword !== confirmNewPassword) { document.addEventListener("DOMContentLoaded", function () {
alert('New Password and Confirm New Password must match.'); const form = document.querySelector('form[action="api/v1/user/change-password"]');
event.preventDefault(); // Prevent form submission
} form.addEventListener('submit', function (event) {
}); const newPassword = document.getElementById('newPassword').value;
const confirmNewPassword = document.getElementById('confirmNewPassword').value;
if (newPassword !== confirmNewPassword) {
alert('New Password and Confirm New Password must match.');
event.preventDefault(); // Prevent form submission
}
}); });
</script> });
</script>
<hr> <!-- Separator Line --> <h4 th:text="#{account.syncTitle}">Sync browser settings with Account</h4>
<div id="bg-card" class="container mt-4">
<h3 th:text="#{account.settingsCompare}">Settings Comparison:</h3>
<table id="settingsTable" class="table table-bordered table-sm table-striped">
<thead>
<tr>
<th th:text="#{account.property}">Property</th>
<th th:text="#{account.accountSettings}">Account Setting</th>
<th th:text="#{account.webBrowserSettings}">Web Browser Setting</th>
</tr>
</thead>
<tbody>
<!-- This will be dynamically populated by JavaScript -->
</tbody>
</table>
<h4 th:text="#{account.syncTitle}">Sync browser settings with Account</h4> <div class="buttons-container mt-3 text-center">
<div class="container mt-4"> <button id="syncToBrowser" class="btn btn-primary btn-sm" th:text="#{account.syncToBrowser}">Sync
<h3 th:text="#{account.settingsCompare}">Settings Comparison:</h3> Account -> Browser</button>
<table id="settingsTable" class="table table-bordered table-sm table-striped"> <button id="syncToAccount" class="btn btn-secondary btn-sm" th:text="#{account.syncToAccount}">Sync
<thead> Account <- Browser</button>
<tr>
<th th:text="#{account.property}">Property</th>
<th th:text="#{account.accountSettings}">Account Setting</th>
<th th:text="#{account.webBrowserSettings}">Web Browser Setting</th>
</tr>
</thead>
<tbody>
<!-- This will be dynamically populated by JavaScript -->
</tbody>
</table>
<div class="buttons-container mt-3 text-center">
<button id="syncToBrowser" class="btn btn-primary btn-sm" th:text="#{account.syncToBrowser}">Sync Account -> Browser</button>
<button id="syncToAccount" class="btn btn-secondary btn-sm" th:text="#{account.syncToAccount}">Sync Account <- Browser</button>
</div>
</div> </div>
</div>
<script th:inline="javascript"> <script th:inline="javascript">
document.addEventListener("DOMContentLoaded", function() { document.addEventListener("DOMContentLoaded", function () {
const settingsTableBody = document.querySelector("#settingsTable tbody"); const settingsTableBody = document.querySelector("#settingsTable tbody");
/*<![CDATA[*/ /*<![CDATA[*/
var accountSettingsString = /*[[${settings}]]*/ {}; var accountSettingsString = /*[[${settings}]]*/ {};
/*]]>*/ /*]]>*/
var accountSettings = JSON.parse(accountSettingsString); var accountSettings = JSON.parse(accountSettingsString);
let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]); let allKeys = new Set([...Object.keys(accountSettings), ...Object.keys(localStorage)]);
allKeys.forEach(key => { allKeys.forEach(key => {
if(key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys if (key === 'debug' || key === '0' || key === '1') return; // Ignoring specific keys
const accountValue = accountSettings[key] || '-'; const accountValue = accountSettings[key] || '-';
const browserValue = localStorage.getItem(key) || '-'; const browserValue = localStorage.getItem(key) || '-';
const row = settingsTableBody.insertRow(); const row = settingsTableBody.insertRow();
const propertyCell = row.insertCell(0); const propertyCell = row.insertCell(0);
const accountCell = row.insertCell(1); const accountCell = row.insertCell(1);
const browserCell = row.insertCell(2); const browserCell = row.insertCell(2);
propertyCell.textContent = key;
accountCell.textContent = accountValue;
browserCell.textContent = browserValue;
});
document.getElementById('syncToBrowser').addEventListener('click', function() {
// First, clear the local storage
localStorage.clear();
// Then, set the account settings to local storage
for (let key in accountSettings) {
if(key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys
localStorage.setItem(key, accountSettings[key]);
}
}
location.reload(); // Refresh the page after sync
});
document.getElementById('syncToAccount').addEventListener('click', function() {
let form = document.createElement("form");
form.method = "POST";
form.action = "api/v1/user/updateUserSettings"; // Your endpoint URL
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if(key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys
let hiddenField = document.createElement("input");
hiddenField.type = "hidden";
hiddenField.name = key;
hiddenField.value = localStorage.getItem(key);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
});
propertyCell.textContent = key;
accountCell.textContent = accountValue;
browserCell.textContent = browserValue;
}); });
</script>
<div class="mb-3 mt-4 text-center"> document.getElementById('syncToBrowser').addEventListener('click', function () {
<a href="logout" role="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</a> // First, clear the local storage
<a th:if="${role == 'ROLE_ADMIN'}" class="btn btn-info" href="addUsers" role="button" th:text="#{account.adminSettings}" target="_blank">Admin Settings</a> localStorage.clear();
</div>
// Then, set the account settings to local storage
for (let key in accountSettings) {
if (key !== 'debug' && key !== '0' && key !== '1') { // Only sync non-ignored keys
localStorage.setItem(key, accountSettings[key]);
}
}
location.reload(); // Refresh the page after sync
});
document.getElementById('syncToAccount').addEventListener('click', function () {
let form = document.createElement("form");
form.method = "POST";
form.action = "api/v1/user/updateUserSettings"; // Your endpoint URL
for (let i = 0; i < localStorage.length; i++) {
const key = localStorage.key(i);
if (key !== 'debug' && key !== '0' && key !== '1') { // Only send non-ignored keys
let hiddenField = document.createElement("input");
hiddenField.type = "hidden";
hiddenField.name = key;
hiddenField.value = localStorage.getItem(key);
form.appendChild(hiddenField);
}
}
document.body.appendChild(form);
form.submit();
});
});
</script>
<div class="mb-3 mt-4 text-center">
<a href="logout" role="button" class="btn btn-danger" th:text="#{account.signOut}">Sign Out</a>
<a th:if="${role == 'ROLE_ADMIN'}" class="btn btn-info" href="addUsers" role="button"
th:text="#{account.adminSettings}" target="_blank">Admin Settings</a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html> </html>

View file

@ -12,7 +12,7 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-8"> <div class="col-md-8" id="bg-card">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2> <h2 class="text-center" th:text="#{adminUserSettings.header}">Admin User Control Settings</h2>

View file

@ -1,43 +1,62 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<th:block th:insert="~{fragments/common :: head(title=#{autoSplitPDF.title}, header=#{autoSplitPDF.header})}"></th:block>
</head>
<body> <head>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{autoSplitPDF.title}, header=#{autoSplitPDF.header})}">
<div id="page-container"> </th:block>
<div id="content-wrap"> </head>
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br> <body>
<div class="container"> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div class="row justify-content-center"> <div id="page-container">
<div class="col-md-6"> <div id="content-wrap">
<h2 th:text="#{autoSplitPDF.header}"></h2> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<!-- Added a brief description --> <br><br>
<p th:text="#{autoSplitPDF.description}"></p> <div class="container">
<ul> <div class="row justify-content-center">
<li th:text="#{autoSplitPDF.selectText.1}"></li> <div class="col-md-6" id="bg-card">
<li th:text="#{autoSplitPDF.selectText.2}"></li> <div class="tool-header">
<li th:text="#{autoSplitPDF.selectText.3}"></li> <span class="material-symbols-rounded tool-header-icon advance">cut</span>
<li th:text="#{autoSplitPDF.selectText.4}"></li> <span class="tool-header-text" th:text="#{autoSplitPDF.header}"></span>
</ul>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/auto-split-pdf}">
<p th:text="#{autoSplitPDF.formPrompt}"></p>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="duplexMode" id="duplexMode">
<label class="ms-3" for="duplexMode" th:text=#{autoSplitPDF.duplexMode}></label>
</div>
<p><a th:href="@{files/Auto%20Splitter%20Divider%20(minimal).pdf}" download th:text="#{autoSplitPDF.dividerDownload1}"></a></p>
<p><a th:href="@{files/Auto%20Splitter%20Divider%20(with%20instructions).pdf}" download th:text="#{autoSplitPDF.dividerDownload2}"></a></p>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{autoSplitPDF.submit}"></button>
</form>
</div> </div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/auto-split-pdf}">
<p th:text="#{autoSplitPDF.formPrompt}"></p>
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
</div>
<div class="form-check ms-3">
<input type="checkbox" name="duplexMode" id="duplexMode">
<label for="duplexMode" th:text=#{autoSplitPDF.duplexMode}></label>
</div>
<p>
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
aria-expanded="false" aria-controls="info" th:text="#{info}"></a>
</p>
<div class="collapse" id="info">
<!-- Added a brief description -->
<p th:text="#{autoSplitPDF.description}"></p>
<ul>
<li th:text="#{autoSplitPDF.selectText.1}"></li>
<li th:text="#{autoSplitPDF.selectText.2}"></li>
<li th:text="#{autoSplitPDF.selectText.3}"></li>
<li th:text="#{autoSplitPDF.selectText.4}"></li>
</ul>
<p><a th:href="@{files/Auto%20Splitter%20Divider%20(minimal).pdf}" download
th:text="#{autoSplitPDF.dividerDownload1}"></a></p>
<p><a th:href="@{files/Auto%20Splitter%20Divider%20(with%20instructions).pdf}" download
th:text="#{autoSplitPDF.dividerDownload2}"></a></p>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{autoSplitPDF.submit}"></button>
</form>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html> </html>

View file

@ -12,7 +12,7 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9"> <div class="col-md-9" id="bg-card">
<!-- User Settings Title --> <!-- User Settings Title -->
<h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2> <h2 class="text-center" th:text="#{changeCreds.header}">User Settings</h2>

View file

@ -1,43 +1,57 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<th:block th:insert="~{fragments/common :: head(title=#{fileToPDF.title}, header=#{fileToPDF.header})}"></th:block>
</head>
<body> <head>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{fileToPDF.title}, header=#{fileToPDF.header})}"></th:block>
<div id="page-container"> </head>
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <body>
<br><br> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div class="container"> <div id="page-container">
<div class="row justify-content-center"> <div id="content-wrap">
<div class="col-md-6"> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<h2 th:text="#{fileToPDF.header}"></h2> <br><br>
<p th:text="#{processTimeWarning}"></p> <div class="container">
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/file/pdf}"> <div class="row justify-content-center">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div> <div class="col-md-6" id="bg-card">
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button> <div class="tool-header">
</form> <span class="material-symbols-rounded tool-header-icon convert">draft</span>
<p class="mt-3" th:text="#{fileToPDF.credit}"></p> <span class="tool-header-text" th:text="#{fileToPDF.header}"></span>
<p class="mt-3" th:text="#{fileToPDF.supportedFileTypes}"></p>
<p>Microsoft Word: (DOC, DOCX, DOT, DOTX)</p>
<p>Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF)</p>
<p>Microsoft PowerPoint: (PPT, PPTX)</p>
<p>OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG)</p>
<p>Plain Text: (TXT, TEXT, XML)</p>
<p>Rich Text Format: (RTF)</p>
<p>Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF)</p>
<p>HTML: (HTML)</p>
<p>Lotus Word Pro: (LWP)</p>
<p>StarOffice: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW)</p>
<p>Other: (DBF, FODS, VSD, VOR, VOR3, VOR4, UOP, PCT, PS, PDF)</p>
<a href="https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html">https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html</a>
</div> </div>
<p th:text="#{processTimeWarning}"></p>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/file/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false)}"></div>
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
aria-expanded="false" aria-controls="info" th:text="#{fileToPDF.supportedFileTypesInfo}"></a>
<div class="collapse" id="info">
<p class="mt-3" th:text="#{fileToPDF.credit}"></p>
<p class="mt-3" th:text="#{fileToPDF.supportedFileTypes}"></p>
<p>Microsoft Word: (DOC, DOCX, DOT, DOTX)</p>
<p>Microsoft Excel: (CSV, XLS, XLSX, XLT, XLTX, SLK, DIF)</p>
<p>Microsoft PowerPoint: (PPT, PPTX)</p>
<p>OpenDocument Formats: (ODT, OTT, ODS, OTS, ODP, OTP, ODG, OTG)</p>
<p>Plain Text: (TXT, TEXT, XML)</p>
<p>Rich Text Format: (RTF)</p>
<p>Images: (BMP, GIF, JPEG, PNG, TIF, PBM, PGM, PPM, RAS, XBM, XPM, SVG, SVM, WMF)</p>
<p>HTML: (HTML)</p>
<p>Lotus Word Pro: (LWP)</p>
<p>StarOffice: (SDA, SDC, SDD, SDW, STC, STD, STI, STW, SXD, SXG, SXI, SXW)</p>
<p>Other: (DBF, FODS, VSD, VOR, VOR3, VOR4, UOP, PCT, PS, PDF)</p>
<a
href="https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html">https://help.libreoffice.org/latest/en-US/text/shared/guide/supported_formats.html</a>
</div>
<br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{fileToPDF.submit}"></button>
</form>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html> </html>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="mb-3"> <div class="mb-3" id="bg-card">
<h2 th:text="#{HTMLToPDF.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">html</span>
<span class="tool-header-text" th:text="#{HTMLToPDF.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/html/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/html/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/html,application/zip' )}"></div>
<div class="mb-3"> <div class="mb-3">

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{imageToPDF.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon image">image</span>
<span class="tool-header-text" th:text="#{imageToPDF.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/img/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/img/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*', inputText=#{imgPrompt})}"></div>
<div class="mb-3"> <div class="mb-3">
@ -25,9 +28,9 @@
</select> </select>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input type="checkbox" class="form-check-input" name="autoRotate" id="autoRotate"> <input type="checkbox" name="autoRotate" id="autoRotate">
<label class="ms-3" for="autoRotate" th:text=#{imageToPDF.selectText.2}></label> <label for="autoRotate" th:text=#{imageToPDF.selectText.2}></label>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{pdfToImage.colorType}"></label> <label th:text="#{pdfToImage.colorType}"></label>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{MarkdownToPDF.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">markdown</span>
<span class="tool-header-text" th:text="#{MarkdownToPDF.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/markdown/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/markdown/pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/markdown')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='text/markdown')}"></div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{MarkdownToPDF.submit}"></button>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{PDFToCSV.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">csv</span>
<span class="tool-header-text" th:text="#{PDFToCSV.header}"></span>
</div>
<form id="PDFToCSVForm" th:action="@{api/v1/convert/pdf/csv}" method="post" enctype="multipart/form-data"> <form id="PDFToCSVForm" th:action="@{api/v1/convert/pdf/csv}" method="post" enctype="multipart/form-data">
<input id="pageId" type="hidden" name="pageId"> <input id="pageId" type="hidden" name="pageId">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{PDFToHTML.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">html</span>
<span class="tool-header-text" th:text="#{PDFToHTML.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/html}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/html}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pdfToImage.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon image">image</span>
<span class="tool-header-text" th:text="#{pdfToImage.header}"></span>
</div>
<p th:text="#{processTimeWarning}"></p> <p th:text="#{processTimeWarning}"></p>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/img}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/img}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pdfToPDFA.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">picture_as_pdf</span>
<span class="tool-header-text" th:text="#{pdfToPDFA.header}"></span>
</div>
<p th:text="#{pdfToPDFA.tip}"></p> <p th:text="#{pdfToPDFA.tip}"></p>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/pdfa}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/pdfa}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{PDFToPresentation.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon ppt">slideshow</span>
<span class="tool-header-text" th:text="#{PDFToPresentation.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/presentation}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/presentation}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{PDFToText.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">text_fields</span>
<span class="tool-header-text" th:text="#{PDFToText.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/text}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/text}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{PDFToWord.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon word">description</span>
<span class="tool-header-text" th:text="#{PDFToWord.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/word}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/word}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{PDFToXML.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">code</span>
<span class="tool-header-text" th:text="#{PDFToXML.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/xml}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/pdf/xml}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{URLToPDF.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon convert">link</span>
<span class="tool-header-text" th:text="#{URLToPDF.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/url/pdf}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/convert/url/pdf}">
<input type="text" class="form-control" id="urlInput" name="urlInput" placeholder="http://"> <input type="text" class="form-control" id="urlInput" name="urlInput" placeholder="http://">
<br> <br>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{crop.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">crop</span>
<span class="tool-header-text" th:text="#{crop.header}"></span>
</div>
<form id="cropForm" action="/api/v1/general/crop" method="post" enctype="multipart/form-data"> <form id="cropForm" action="/api/v1/general/crop" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<input id="x" type="hidden" name="x"> <input id="x" type="hidden" name="x">

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pageExtracter.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">upload</span>
<span class="tool-header-text" th:text="#{pageExtracter.header}"></span>
</div>
<form th:action="@{api/v1/general/rearrange-pages}" method="post" enctype="multipart/form-data"> <form th:action="@{api/v1/general/rearrange-pages}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<input type="hidden" id="customMode" name="customMode" value=""> <input type="hidden" id="customMode" name="customMode" value="">

View file

@ -1,12 +1,23 @@
<div th:fragment="card" class="feature-card" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}" th:data-bs-tags="${tags}"> <div th:fragment="card" class="feature-card" th:id="${id}" th:if="${@endpointConfiguration.isEndpointEnabled(cardLink)}"
<a th:href="${cardLink}"> th:data-bs-tags="${tags}">
<div class="d-flex align-items-center"> <!-- Add a flex container to align the SVG and title --> <a th:href="${cardLink}">
<img th:if="${svgPath}" class="card-icon home-card-icon home-card-icon-colour" th:src="${svgPath}" alt="Icon" width="30" height="30"> <div class="d-flex align-items-center"> <!-- Add a flex container to align the SVG and title -->
<h5 class="card-title ms-2" th:text="${cardTitle}"></h5> <!-- Add some margin-left (ms-2) for spacing between SVG and title -->
</div>
<p class="card-text" th:text="${cardText}"></p>
</a> <div class="icon" alt="icon" th:class="@{${toolGroup}}">
<div class="favorite-icon" onclick="toggleFavorite(this)"> <span class="material-symbols-rounded nav-icon" th:text="@{${toolIcon}}"></span>
<img src="images/star.svg" alt="Favorite"> </div>
</div>
</div>
<h5 class="card-title ms-2" th:text="${cardTitle}"></h5>
<!-- Add some margin-left (ms-2) for spacing between SVG and title -->
</div>
<p class="card-text" th:text="${cardText}"></p>
</a>
<div class="favorite-icon" onclick="toggleFavorite(this)">
<span class="material-symbols-rounded no-fill">
star
</span>
</div>
</div>

View file

@ -1,162 +1,171 @@
<th:block th:fragment="head"> <th:block th:fragment="head">
<!-- Title --> <!-- Title -->
<title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title> <title th:text="${@appName} + (${title} != null and ${title} != '' ? ' - ' + ${title} : '')"></title>
<!-- Metadata --> <!-- Metadata -->
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="description" th:content="${@appName} + (${header} != null and ${header} != '' ? ' - ' + ${header} : '')"> <meta name="description" th:content="${@appName} + (${header} != null and ${header} != '' ? ' - ' + ${header} : '')">
<meta name="msapplication-TileColor" content="#2d89ef"> <meta name="msapplication-TileColor" content="#2d89ef">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Icons --> <!-- Icons -->
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2"> <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png?v=2">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=2"> <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png?v=2">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=2"> <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png?v=2">
<link rel="manifest" href="/site.webmanifest?v=2"> <link rel="manifest" href="/site.webmanifest?v=2">
<link rel="mask-icon" href="/safari-pinned-tab.svg?v=2" color="#ca2b2a"> <link rel="mask-icon" href="/safari-pinned-tab.svg?v=2" color="#ca2b2a">
<link rel="shortcut icon" href="/favicon.ico?v=2"> <link rel="shortcut icon" href="/favicon.ico?v=2">
<meta name="apple-mobile-web-app-title" content="Stirling PDF"> <meta name="apple-mobile-web-app-title" content="Stirling PDF">
<meta name="application-name" content="Stirling PDF"> <meta name="application-name" content="Stirling PDF">
<meta name="msapplication-TileColor" content="#00aba9"> <meta name="msapplication-TileColor" content="#00aba9">
<meta name="theme-color" content="#ffffff"> <meta name="theme-color" content="#ffffff">
<!-- jQuery --> <!-- jQuery -->
<script src="js/thirdParty/jquery.min.js"></script> <script src="js/thirdParty/jquery.min.js"></script>
<script src="js/thirdParty/jszip.min.js"></script> <script src="js/thirdParty/jszip.min.js"></script>
<!-- Bootstrap --> <!-- Bootstrap -->
<script src="js/thirdParty/popper.min.js"></script> <script src="js/thirdParty/popper.min.js"></script>
<script src="js/thirdParty/bootstrap.min.js"></script> <script src="js/thirdParty/bootstrap.min.js"></script>
<link rel="stylesheet" href="css/bootstrap.min.css"> <link rel="stylesheet" href="css/bootstrap.min.css">
<!-- Bootstrap Icons --> <!-- Bootstrap Icons -->
<link rel="stylesheet" href="css/bootstrap-icons.min.css"> <link rel="stylesheet" href="css/bootstrap-icons.min.css">
<!-- PDF.js --> <!-- PDF.js -->
<script th:src="@{pdfjs/pdf.js}"></script> <script th:src="@{pdfjs/pdf.js}"></script>
<!-- PDF-Lib --> <!-- PDF-Lib -->
<script src="js/thirdParty/pdf-lib.min.js"></script> <script src="js/thirdParty/pdf-lib.min.js"></script>
<!-- Custom --> <!-- Custom -->
<link rel="stylesheet" href="css/general.css"> <link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" th:href="@{css/light-mode.css}" id="light-mode-styles"> <link rel="stylesheet" th:href="@{css/theme/theme.css}">
<link rel="stylesheet" th:href="@{css/dark-mode.css}" id="dark-mode-styles"> <link rel="stylesheet" th:href="@{css/theme/componentes.css}">
<link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled> <link rel="stylesheet" th:href="@{css/theme/theme.light.css}" id="light-mode-styles">
<link rel="stylesheet" href="css/tab-container.css"> <link rel="stylesheet" th:href="@{css/theme/theme.dark.css}" id="dark-mode-styles">
<link rel="stylesheet" href="css/navbar.css"> <link rel="stylesheet" th:href="@{css/rainbow-mode.css}" id="rainbow-mode-styles" disabled>
<link rel="stylesheet" href="css/tab-container.css">
<link rel="stylesheet" href="css/navbar.css">
<link rel="stylesheet" th:href="@{/css/error.css}" th:if="${error}"> <link rel="stylesheet" th:href="@{/css/error.css}" th:if="${error}">
<link rel="stylesheet" href="css/home.css" th:if="${currentPage == 'home'}"> <link rel="stylesheet" href="css/home.css" th:if="${currentPage == 'home'}">
<link rel="stylesheet" href="css/account.css" th:if="${currentPage == 'account'}"> <link rel="stylesheet" href="css/account.css" th:if="${currentPage == 'account'}">
<link rel="stylesheet" href="css/licenses.css" th:if="${currentPage == 'licenses'}"> <link rel="stylesheet" href="css/licenses.css" th:if="${currentPage == 'licenses'}">
<link rel="stylesheet" href="css/multi-tool.css" th:if="${currentPage == 'multi-tool'}"> <link rel="stylesheet" href="css/multi-tool.css" th:if="${currentPage == 'multi-tool'}">
<link rel="stylesheet" href="css/rotate-pdf.css" th:if="${currentPage == 'rotate-pdf'}"> <link rel="stylesheet" href="css/rotate-pdf.css" th:if="${currentPage == 'rotate-pdf'}">
<link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}"> <link rel="stylesheet" href="css/stamp.css" th:if="${currentPage == 'stamp'}">
<link rel="stylesheet" href="css/fileSelect.css"> <link rel="stylesheet" href="css/fileSelect.css">
<link rel="stylesheet" href="css/footer.css"> <link rel="stylesheet" href="css/footer.css">
<!-- Help Modal --> <!-- Google MD Icons -->
<link rel="stylesheet" href="css/errorBanner.css"> <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet" />
<script src="js/tab-container.js"></script> <!-- Help Modal -->
<script src="js/darkmode.js"></script> <link rel="stylesheet" href="css/errorBanner.css">
</th:block>
<th:block th:fragment="game"> <script src="js/tab-container.js"></script>
<dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal> <script src="js/darkmode.js"></script>
<script th:inline="javascript">
console.log("loaded game");
$(document).ready(function() {
// Find the file input within the form
var fileInput = $('input[type="file"]');
// Find the closest enclosing form of the file input
var form = fileInput.closest('form');
// Find the submit button within the form
var submitButton = form.find('button[type="submit"], input[type="submit"]');
const boredWaitingText = /*[[#{bored}]]*/ 'Bored Waiting?';
const downloadCompleteText = /*[[#{downloadComplete}]]*/ 'Download Complete';
window.downloadCompleteText = downloadCompleteText;
// Create the 'show-game-btn' button
var gameButton = $('<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">' + boredWaitingText + '</button><br><br>');
// Insert the 'show-game-btn' just above the submit button
submitButton.before(gameButton);
function loadGameScript(callback) {
console.log('loadGameScript called');
const script = document.createElement('script');
script.src = 'js/game.js';
script.onload = callback;
document.body.appendChild(script);
}
let gameScriptLoaded = false;
const gameDialog = document.getElementById('game-container-wrapper');
$('#show-game-btn').on('click', function() {
console.log('Show game button clicked');
if (!gameScriptLoaded) {
console.log('Show game button load');
loadGameScript(function() {
console.log('Game script loaded');
window.initializeGame();
gameScriptLoaded = true;
});
} else {
window.resetGame();
}
gameDialog.showModal();
});
gameDialog.addEventListener("click", e => {
const dialogDimensions = gameDialog.getBoundingClientRect()
if (
e.clientX < dialogDimensions.left ||
e.clientX > dialogDimensions.right ||
e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom
) {
gameDialog.close();
}
})
})
</script>
<div id="game-container">
<div id="lives">Lives: 3</div>
<div id="score">Score: 0</div>
<div id="high-score">High Score: 0</div>
<div id="level">Level: 1</div>
<img src="favicon.svg" class="player" id="player" alt="favicon">
</div>
<link rel="stylesheet" href="css/game.css">
</dialog>
</th:block> </th:block>
<th:block th:fragment="fileSelector(name, multiple)" th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false"> <th:block th:fragment="game">
<script th:inline="javascript"> <dialog id="game-container-wrapper" class="game-container-wrapper" data-bs-modal>
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ ''; <script th:inline="javascript">
const multiple = [[${multiple}]] || false; console.log("loaded game");
const remoteCall = [[${remoteCall}]] || true; $(document).ready(function () {
</script>
<script src="js/downloader.js"></script>
<div class="custom-file-chooser" th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}"> // Find the file input within the form
<div class="mb-3"> var fileInput = $('input[type="file"]');
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple th:required="${notRequired} ? null : 'required'">
</div>
<div class="selected-files"></div>
</div>
<div class="progressBarContainer" style="display: none; position: relative;"> // Find the closest enclosing form of the file input
<div class="progress" style="height: 1rem;"> var form = fileInput.closest('form');
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span class="visually-hidden">Loading...</span> // Find the submit button within the form
</div> var submitButton = form.find('button[type="submit"], input[type="submit"]');
</div>
</div> const boredWaitingText = /*[[#{bored}]]*/ 'Bored Waiting?';
<script src="js/fileInput.js"></script> const downloadCompleteText = /*[[#{downloadComplete}]]*/ 'Download Complete';
window.downloadCompleteText = downloadCompleteText;
// Create the 'show-game-btn' button
var gameButton = $('<button type="button" class="btn btn-primary" id="show-game-btn" style="display:none;">' + boredWaitingText + '</button><br><br>');
// Insert the 'show-game-btn' just above the submit button
submitButton.before(gameButton);
function loadGameScript(callback) {
console.log('loadGameScript called');
const script = document.createElement('script');
script.src = 'js/game.js';
script.onload = callback;
document.body.appendChild(script);
}
let gameScriptLoaded = false;
const gameDialog = document.getElementById('game-container-wrapper');
$('#show-game-btn').on('click', function () {
console.log('Show game button clicked');
if (!gameScriptLoaded) {
console.log('Show game button load');
loadGameScript(function () {
console.log('Game script loaded');
window.initializeGame();
gameScriptLoaded = true;
});
} else {
window.resetGame();
}
gameDialog.showModal();
});
gameDialog.addEventListener("click", e => {
const dialogDimensions = gameDialog.getBoundingClientRect()
if (
e.clientX < dialogDimensions.left ||
e.clientX > dialogDimensions.right ||
e.clientY < dialogDimensions.top ||
e.clientY > dialogDimensions.bottom
) {
gameDialog.close();
}
})
})
</script>
<div id="game-container">
<div id="lives">Lives: 3</div>
<div id="score">Score: 0</div>
<div id="high-score">High Score: 0</div>
<div id="level">Level: 1</div>
<img src="favicon.svg" class="player" id="player" alt="favicon">
</div>
<link rel="stylesheet" href="css/game.css">
</dialog>
</th:block>
<th:block th:fragment="fileSelector(name, multiple)"
th:with="accept=${accept} ?: '*/*', inputText=${inputText} ?: #{pdfPrompt}, remoteCall=${remoteCall} ?: true, notRequired=${notRequired} ?: false">
<script th:inline="javascript">
const pdfPasswordPrompt = /*[[#{error.pdfPassword}]]*/ '';
const multiple = [[${ multiple }]] || false;
const remoteCall = [[${ remoteCall }]] || true;
</script>
<script src="js/downloader.js"></script>
<div class="custom-file-chooser"
th:attr="data-bs-unique-id=${name}, data-bs-element-id=${name+'-input'}, data-bs-files-selected=#{filesSelected}, data-bs-pdf-prompt=#{pdfPrompt}">
<div class="mb-3">
<input type="file" class="form-control" th:name="${name}" th:id="${name}+'-input'" th:accept="${accept}" multiple
th:required="${notRequired} ? null : 'required'">
</div>
<div class="selected-files"></div>
</div>
<div class="progressBarContainer" style="display: none; position: relative;">
<div class="progress" style="height: 1rem;">
<div class="progressBar progress-bar progress-bar-striped progress-bar-animated bg-success" role="progressbar"
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;">
<span class="visually-hidden">Loading...</span>
</div>
</div>
</div>
<script src="js/fileInput.js"></script>
</th:block> </th:block>

View file

@ -1,19 +1,8 @@
<footer th:fragment="footer" id="footer" class="text-center py-3"> <footer th:fragment="footer" id="footer" class="text-center py-5">
<div class="footer-center"> <div class="footer-center">
<a href="https://github.com/Stirling-Tools/Stirling-PDF" target="_blank" class="mx-1" th:title="#{visitGithub}"> <div class="footer-powered-by">
<img src="images/github.svg" alt="github"> <span th:text="#{poweredBy} + ' Stirling PDF'"></span>
</a> </div>
<a href="https://hub.docker.com/r/frooodle/s-pdf" target="_blank" class="mx-1" th:title="#{seeDockerHub}"> <a href="licenses" id="licenses" target="_blank" class="mx-1" title="" th:text="#{licenses.nav}">Licenses</a>
<img src="images/docker.svg" alt="docker"> </div>
</a> </footer>
<a href="https://discord.gg/Cn8pWhQRxZ" target="_blank" class="mx-1" th:title="#{joinDiscord}">
<img src="images/discord.svg" alt="discord">
</a>
<a href="https://github.com/sponsors/Frooodle" target="_blank" class="mx-1" th:title="#{donate}">
<img src="images/suit-heart-fill.svg" alt="suit-heart-fill">
</a>
</div>
<div style="color: grey;" th:if="${@appName} != 'Stirling PDF'" class="footer-powered-by" th:text="#{poweredBy} + ' Stirling PDF'"></div>
<a href="licenses" id="licenses" target="_blank" class="mx-1" title="" th:text="#{licenses.nav}">Licenses</a>
</footer>

View file

@ -1,226 +1,407 @@
<div th:fragment="navbar" class="mx-auto"> <div th:fragment="navbar" class="mx-auto">
<script src="js/languageSelection.js"></script> <script src="js/languageSelection.js"></script>
<script th:inline="javascript"> <script th:inline="javascript">
const currentVersion = /*[[${@appVersion}]]*/ ''; const currentVersion = /*[[${@appVersion}]]*/ '';
const noFavourites = /*[[#{noFavourites}]]*/ ''; const noFavourites = /*[[#{noFavourites}]]*/ '';
</script> </script>
<script th:src="@{js/githubVersion.js}"></script> <script th:src="@{js/githubVersion.js}"></script>
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg">
<div class="container "> <div class="container ">
<a class="navbar-brand" href="#" th:href="@{/}" style="display: flex;"> <a class="navbar-brand" href="#" th:href="@{/}" style="display: flex;">
<img class="main-icon" src="favicon.svg?v=2" alt="icon"> <img class="main-icon" src="favicon.svg?v=2" alt="icon">
<span class="icon-text" th:text="${@navBarText}"></span> <span class="icon-text" th:text="${@navBarText}"></span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav"
aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="material-symbols-rounded">
menu
</span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto flex-nowrap">
<!-- All Tools -->
<li class="nav-item dropdown dropdown-mega position-static"
th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' OR ${currentPage}=='add-password' OR ${currentPage}=='remove-password' OR ${currentPage}=='add-watermark' OR ${currentPage}=='cert-sign' OR ${currentPage}=='sanitize-pdf' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='html-to-pdf' OR ${currentPage}=='url-to-pdf' OR ${currentPage}=='pdf-to-img' OR ${currentPage}=='pdf-to-word' OR ${currentPage}=='pdf-to-presentation' OR ${currentPage}=='pdf-to-text' OR ${currentPage}=='pdf-to-html' OR ${currentPage}=='pdf-to-xml' OR ${currentPage}=='pdf-to-pdfa' OR ${currentPage}=='sign' OR ${currentPage}=='repair' OR ${currentPage}=='compare' OR ${currentPage}=='show-javascript' OR ${currentPage}=='flatten' OR ${currentPage}=='remove-blanks' OR ${currentPage}=='remove-annotations' OR ${currentPage}=='extract-image-scans' OR ${currentPage}=='change-metadata' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='change-permissions' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' OR ${currentPage}=='add-page-numbers' OR ${currentPage}=='auto-rename' OR ${currentPage}=='get-info-on-pdf' ? 'active' : ''">
<a class="nav-link" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="material-symbols-rounded">
apps
</span>
<span class="icon-text" th:data-text="#{navbar.allTools}" th:text="#{navbar.allTools}"></span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown-1">
<div class='mega-content px-md-4'>
<div class="container-fluid">
<div class="row">
<!-- Page tools menu items -->
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
<h6 class="menu-title" th:text="#{navbar.sections.organize}"></h6>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'zoom_in_map', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'add_to_photos', 'home.merge.title', 'home.merge.desc', 'merge.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdfs', 'cut', 'home.split.title', 'home.split.desc', 'split.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('rotate-pdf', 'rotate_right', 'home.rotate.title', 'home.rotate.desc', 'rotate.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-pages', 'delete', 'home.removePages.title', 'home.removePages.desc', 'removePages.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-organizer', 'format_list_bulleted', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc', 'pdfOrganiser.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-page-layout', 'dashboard', 'home.pageLayout.title', 'home.pageLayout.desc', 'pageLayout.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('scale-pages', 'fullscreen', 'home.scalePages.title', 'home.scalePages.desc', 'scalePages.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('crop', 'crop', 'home.crop.title', 'home.crop.desc', 'crop.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-page', 'upload', 'home.extractPage.title', 'home.extractPage.desc', 'extractPage.tags', 'organize')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-single-page', 'looks_one', 'home.PdfToSinglePage.title', 'home.PdfToSinglePage.desc', 'PdfToSinglePage.tags', 'organize')}">
</div>
</div>
<!-- Convert to PDF menu items -->
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
<h6 class="menu-title" th:text="#{navbar.sections.convertTo}"></h6>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('img-to-pdf', 'image', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags', 'image')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('file-to-pdf', 'draft', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('url-to-pdf', 'link', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('html-to-pdf', 'html', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('markdown-to-pdf', 'markdown', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags', 'convert')}">
</div>
</div>
<!-- Convert from PDF menu items -->
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
<h6 class="menu-title" th:text="#{navbar.sections.convertFrom}"></h6>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-img', 'image', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags', 'image')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-word', 'description', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags', 'word')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-presentation', 'slideshow', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags', 'ppt')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-text', 'text_fields', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-html', 'html', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-xml', 'code', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-pdfa', 'picture_as_pdf', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags', 'convert')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-csv', 'csv', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'pdfToPDFA.tags', 'convert')}">
</div>
</div>
<!-- Security menu items -->
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
<h6 class="menu-title" th:text="#{navbar.sections.security}"></h6>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('sign', 'signature', 'home.sign.title', 'home.sign.desc', 'sign.tags', 'sign')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-password', 'lock', 'home.addPassword.title', 'home.addPassword.desc', 'addPassword.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-password', 'lock_open_right', 'home.removePassword.title', 'home.removePassword.desc', 'removePassword.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('change-permissions', 'encrypted', 'home.permissions.title', 'home.permissions.desc', 'permissions.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-watermark', 'water_drop', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'workspace_premium', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('sanitize-pdf', 'sanitizer', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-redact', 'ink_eraser', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags', 'security')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('stamp', 'approval', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags', 'security')}">
</div>
</div>
<!-- View & Edit menu items -->
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
<h6 class="menu-title" th:text="#{navbar.sections.edit}"></h6>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('view-pdf', 'menu_book', 'home.viewPdf.title', 'home.viewPdf.desc', 'viewPdf.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'quick_reference_all', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-page-numbers', '123', 'home.add-page-numbers.title', 'home.add-page-numbers.desc', 'add-page-numbers.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('add-image', 'add_photo_alternate', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-images', 'photo_library', 'home.extractImages.title', 'home.extractImages.desc', 'extractImages.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('flatten', 'layers_clear', 'home.flatten.title', 'home.flatten.desc', 'flatten.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-annotations', 'thread_unread', 'home.removeAnnotations.title', 'home.removeAnnotations.desc', 'removeAnnotations.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-blanks', 'scan_delete', 'home.removeBlanks.title', 'home.removeBlanks.desc', 'removeBlanks.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('compare', 'compare', 'home.compare.title', 'home.compare.desc', 'compare.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('change-metadata', 'assignment', 'home.changeMetadata.title', 'home.changeMetadata.desc', 'changeMetadata.tags', 'other')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('get-info-on-pdf', 'info', 'home.getPdfInfo.title', 'home.getPdfInfo.desc', 'getPdfInfo.tags', 'other')}">
</div>
</div>
<!-- Advance menu items -->
<div class="col-lg-2 col-sm-6 py px-xl-1 px-2">
<h6 class="menu-title" th:text="#{navbar.sections.advance}"></h6>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-tool', 'construction', 'home.multiTool.title', 'home.multiTool.desc', 'multiTool.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'family_history', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-rename', 'text_fields_alt', 'home.auto-rename.title', 'home.auto-rename.desc', 'auto-rename.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('repair', 'build', 'home.repair.title', 'home.repair.desc', 'repair.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('adjust-contrast', 'palette', 'home.adjust-contrast.title', 'home.adjust-contrast.desc', 'adjust-contrast.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('overlay-pdf', 'layers', 'home.overlay-pdfs.title', 'home.overlay-pdfs.desc', 'overlay-pdfs.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-split-pdf', 'cut', 'home.autoSplitPDF.title', 'home.autoSplitPDF.desc', 'autoSplitPDF.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-sections', 'grid_on', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('split-by-size-or-count', 'vertical_split', 'home.autoSizeSplitPDF.title', 'home.autoSizeSplitPDF.desc', 'autoSizeSplitPDF.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-image-scans', 'scanner', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc', 'ScannerImageSplit.tags', 'advance')}">
</div>
<div
th:replace="~{fragments/navbarEntry :: navbarEntry ('show-javascript', 'javascript', 'home.showJS.title', 'home.showJS.desc', 'showJS.tags', 'advance')}">
</div>
</div>
</div>
</div>
</div>
</div>
</li>
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{multi-tool}"
th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
<span class="material-symbols-rounded">
construction
</span>
<span class="icon-text" th:data-text="#{navbar.multiTool}" th:text="#{navbar.multiTool}"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{pipeline}"
th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
<span class="material-symbols-rounded">
family_history
</span>
<span class="icon-text" th:data-text="#{home.pipeline.title}" th:text="#{home.pipeline.title}"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" title="#{home.compressPdfs.title}" th:href="@{compress-pdf}"
th:classappend="${currentPage}=='compress-pdf' ? 'active' : ''" th:title="#{home.compressPdfs.desc}">
<span class="material-symbols-rounded">
zoom_in_map
</span>
<span class="icon-text" th:data-text="#{home.compressPdfs.title}"
th:text="#{home.compressPdfs.title}"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{split-pdfs}"
th:classappend="${currentPage}=='split-pdfs' ? 'active' : ''" th:title="#{home.split-pdfs.desc}">
<span class="material-symbols-rounded">
cut
</span>
<span class="icon-text" th:data-text="#{home.split.title}" th:text="#{home.split.title}"></span>
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{merge-pdfs}"
th:classappend="${currentPage}=='merge-pdfs' ? 'active' : ''" th:title="#{home.merge.desc}">
<span class="material-symbols-rounded">
add_to_photos
</span>
<span class="icon-text" th:data-text="#{home.merge.title}" th:text="#{home.merge.title}"></span>
</a>
</li>
</ul>
<ul class="navbar-nav flex-nowrap">
<li class="nav-item dropdown">
<a class="nav-link" id="navbarDropdown-5" href="#" role="button" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="material-symbols-rounded">
star
</span>
</a>
<div class="dropdown-menu px-xl-2 px-2" id="favoritesDropdown" aria-labelledby="navbarDropdown-5">
<!-- Dropdown items will be added here by JavaScript -->
</div>
</li>
<li class="nav-item">
<a class="nav-link" id="dark-mode-toggle" href="#">
<span class="material-symbols-rounded" id="dark-mode-icon">
dark_mode
</span>
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
<span class="material-symbols-rounded">
language
</span>
</a>
<div class="dropdown-menu px-xl-2 px-2" aria-labelledby="languageDropdown">
<div class="scrollable-y">
<th:block th:insert="~{fragments/languages :: langs}"></th:block>
</div>
</div>
</li>
<li class="nav-item">
<!-- Settings Button -->
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal">
<span class="material-symbols-rounded">
settings
</span>
</a>
</li>
</ul>
</div>
</div>
<script src="js/favourites.js"></script>
<script src="js/search.js"></script>
</nav>
<th:block th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></th:block>
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="settingsModalLabel" th:text="#{settings.title}"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
<span class="material-symbols-rounded">
close
</span>
</button>
</div>
<div class="modal-body">
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
<div class="d-flex justify-content-between align-items-center mb-3 mt-3">
<div class="footer-center" style="flex-direction: row;">
<a href="https://github.com/Stirling-Tools/Stirling-PDF" class="mx-1" role="button"
th:title="#{visitGithub}">
<img src="images/github.svg" alt="github">
</a>
<a href="https://hub.docker.com/r/frooodle/s-pdf" class="mx-1" role="button" th:title="#{seeDockerHub}">
<img src="images/docker.svg" alt="docker">
</a>
<a href="https://discord.gg/Cn8pWhQRxZ" class="mx-1" role="button" th:title="#{joinDiscord}">
<img src="images/discord.svg" alt="discord">
</a>
<a href="https://github.com/sponsors/Frooodle" class="mx-1" role="button" th:title="#{donate}">
<span class="material-symbols-rounded fill footer-icon">
favorite
</span>
</a> </a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav me-auto flex-nowrap">
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{multi-tool}" th:classappend="${currentPage}=='multi-tool' ? 'active' : ''" th:title="#{home.multiTool.desc}">
<img class="icon" src="images/tools.svg" alt="icon">
<span class="icon-text" th:text="#{home.multiTool.title}"></span>
</a>
</li>
<li class="nav-item nav-item-separator"></li>
<li class="nav-item">
<a class="nav-link" href="#" th:href="@{pipeline}" th:classappend="${currentPage}=='pipeline' ? 'active' : ''" th:title="#{home.pipeline.desc}">
<img class="icon" src="images/pipeline.svg" alt="icon">
<span class="icon-text" th:text="#{home.pipeline.title}"></span>
</a>
</li>
<li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='remove-pages' OR ${currentPage}=='merge-pdfs' OR ${currentPage}=='split-pdfs' OR ${currentPage}=='crop' OR ${currentPage}=='adjust-contrast' OR ${currentPage}=='pdf-organizer' OR ${currentPage}=='rotate-pdf' OR ${currentPage}=='multi-page-layout' OR ${currentPage}=='scale-pages' OR ${currentPage}=='auto-split-pdf' OR ${currentPage}=='extract-page' OR ${currentPage}=='pdf-to-single-page' ? 'active' : ''">
<a class="nav-link dropdown-toggle" id="navbarDropdown-1" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/file-earmark-pdf.svg" alt="icon">
<span class="icon-text" th:text="#{navbar.pageOps}"></span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown-1">
<!-- Existing menu items -->
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('merge-pdfs', 'images/union.svg', 'home.merge.title', 'home.merge.desc', 'merge.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdfs', 'images/layout-split.svg', 'home.split.title', 'home.split.desc', 'split.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-organizer', 'images/sort-numeric-down.svg', 'home.pdfOrganiser.title', 'home.pdfOrganiser.desc', 'pdfOrganiser.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('rotate-pdf', 'images/arrow-clockwise.svg', 'home.rotate.title', 'home.rotate.desc', 'rotate.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-pages', 'images/file-earmark-x.svg', 'home.removePages.title', 'home.removePages.desc', 'removePages.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('multi-page-layout', 'images/page-layout.svg', 'home.pageLayout.title', 'home.pageLayout.desc', 'pageLayout.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('scale-pages', 'images/scale-pages.svg', 'home.scalePages.title', 'home.scalePages.desc', 'scalePages.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-split-pdf', 'images/layout-split.svg', 'home.autoSplitPDF.title', 'home.autoSplitPDF.desc', 'autoSplitPDF.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('adjust-contrast', 'images/adjust-contrast.svg', 'home.adjust-contrast.title', 'home.adjust-contrast.desc', 'adjust-contrast.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('crop', 'images/crop.svg', 'home.crop.title', 'home.crop.desc', 'crop.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-page', 'images/extract.svg', 'home.extractPage.title', 'home.extractPage.desc', 'extractPage.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-single-page', 'images/single-page.svg', 'home.PdfToSinglePage.title', 'home.PdfToSinglePage.desc', 'PdfToSinglePage.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('split-by-size-or-count', 'images/layout-split.svg', 'home.autoSizeSplitPDF.title', 'home.autoSizeSplitPDF.desc', 'autoSizeSplitPDF.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('overlay-pdf', 'images/overlay.svg', 'home.overlay-pdfs.title', 'home.overlay-pdfs.desc', 'overlay-pdfs.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('split-pdf-by-sections', 'images/layout-split.svg', 'home.split-by-sections.title', 'home.split-by-sections.desc', 'split-by-sections.tags')}"></div>
</div>
</li>
<li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='pdf-to-img' OR ${currentPage}=='img-to-pdf' OR ${currentPage}=='pdf-to-pdfa' OR ${currentPage}=='file-to-pdf' OR ${currentPage}=='xlsx-to-pdf' OR ${currentPage}=='pdf-to-word' OR ${currentPage}=='pdf-to-presentation' OR ${currentPage}=='pdf-to-text' OR ${currentPage}=='pdf-to-html' OR ${currentPage}=='pdf-to-xml' ? 'active' : ''">
<a class="nav-link dropdown-toggle" id="navbarDropdown-2" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/arrow-left-right.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;">
<span class="icon-text" th:text="#{navbar.convert}"></span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown-2">
<!-- Existing menu items -->
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('img-to-pdf', 'images/image.svg', 'home.imageToPdf.title', 'home.imageToPdf.desc', 'imageToPdf.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('file-to-pdf', 'images/file.svg', 'home.fileToPDF.title', 'home.fileToPDF.desc', 'fileToPDF.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('html-to-pdf', 'images/html.svg', 'home.HTMLToPDF.title', 'home.HTMLToPDF.desc', 'HTMLToPDF.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('url-to-pdf', 'images/url.svg', 'home.URLToPDF.title', 'home.URLToPDF.desc', 'URLToPDF.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('markdown-to-pdf', 'images/markdown.svg', 'home.MarkdownToPDF.title', 'home.MarkdownToPDF.desc', 'MarkdownToPDF.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('book-to-pdf', 'images/book.svg', 'home.BookToPDF.title', 'home.BookToPDF.desc', 'BookToPDF.tags')}"></div>
<hr class="dropdown-divider">
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-img', 'images/image.svg', 'home.pdfToImage.title', 'home.pdfToImage.desc', 'pdfToImage.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-word', 'images/file-earmark-word.svg', 'home.PDFToWord.title', 'home.PDFToWord.desc', 'PDFToWord.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-presentation', 'images/file-earmark-ppt.svg', 'home.PDFToPresentation.title', 'home.PDFToPresentation.desc', 'PDFToPresentation.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-text', 'images/filetype-txt.svg', 'home.PDFToText.title', 'home.PDFToText.desc', 'PDFToText.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-html', 'images/filetype-html.svg', 'home.PDFToHTML.title', 'home.PDFToHTML.desc', 'PDFToHTML.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-xml', 'images/filetype-xml.svg', 'home.PDFToXML.title', 'home.PDFToXML.desc', 'PDFToXML.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-pdfa', 'images/file-earmark-pdf.svg', 'home.pdfToPDFA.title', 'home.pdfToPDFA.desc', 'pdfToPDFA.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-csv', 'images/pdf-csv.svg', 'home.tableExtraxt.title', 'home.tableExtraxt.desc', 'pdfToPDFA.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pdf-to-book', 'images/book.svg', 'home.PDFToBook.title', 'home.PDFToBook.desc', 'PDFToBook.tags')}"></div>
</div>
</li>
<li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='add-password' OR ${currentPage}=='remove-password' OR ${currentPage}=='add-watermark' OR ${currentPage}=='cert-sign' OR ${currentPage}=='sanitize-pdf' ? 'active' : ''">
<a class="nav-link dropdown-toggle" id="navbarDropdown-3" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/shield-check.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;"> <span class="icon-text" th:text="#{navbar.security}"></span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown-3">
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-password', 'images/lock.svg', 'home.addPassword.title', 'home.addPassword.desc', 'addPassword.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-password', 'images/unlock.svg', 'home.removePassword.title', 'home.removePassword.desc', 'removePassword.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('change-permissions', 'images/shield-lock.svg', 'home.permissions.title', 'home.permissions.desc', 'permissions.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-watermark', 'images/droplet.svg', 'home.watermark.title', 'home.watermark.desc', 'watermark.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('cert-sign', 'images/award.svg', 'home.certSign.title', 'home.certSign.desc', 'certSign.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('sanitize-pdf', 'images/sanitize.svg', 'home.sanitizePdf.title', 'home.sanitizePdf.desc', 'sanitizePdf.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-redact', 'images/eraser-fill.svg', 'home.autoRedact.title', 'home.autoRedact.desc', 'autoRedact.tags')}"></div>
</div>
</li>
<li class="nav-item nav-item-separator"></li>
<li class="nav-item dropdown" th:classappend="${currentPage}=='sign' OR ${currentPage}=='repair' OR ${currentPage}=='compare' OR ${currentPage}=='show-javascript' OR ${currentPage}=='flatten' OR ${currentPage}=='remove-blanks' OR ${currentPage}=='remove-annotations' OR ${currentPage}=='extract-image-scans' OR ${currentPage}=='change-metadata' OR ${currentPage}=='add-image' OR ${currentPage}=='ocr-pdf' OR ${currentPage}=='change-permissions' OR ${currentPage}=='extract-images' OR ${currentPage}=='compress-pdf' OR ${currentPage}=='add-page-numbers' OR ${currentPage}=='auto-rename' OR ${currentPage}=='get-info-on-pdf' ? 'active' : ''">
<a class="nav-link dropdown-toggle" id="navbarDropdown-4" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="icon" src="images/card-list.svg" alt="icon" style="width: 16px; height: 16px; vertical-align: middle;">
<span class="icon-text" th:text="#{navbar.other}"></span>
</a>
<div class="dropdown-menu" aria-labelledby="navbarDropdown-4">
<!--<div th:replace="~{fragments/navbarEntry :: navbarEntry ('pipeline', 'images/pipeline.svg', 'home.pipeline.title', 'home.pipeline.desc', 'pipeline.tags')}"></div> -->
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('view-pdf', 'images/book-opened.svg', 'home.viewPdf.title', 'home.viewPdf.desc', 'viewPdf.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('ocr-pdf', 'images/search.svg', 'home.ocr.title', 'home.ocr.desc', 'ocr.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-image', 'images/file-earmark-richtext.svg', 'home.addImage.title', 'home.addImage.desc', 'addImage.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('compress-pdf', 'images/file-zip.svg', 'home.compressPdfs.title', 'home.compressPdfs.desc', 'compressPdfs.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-images', 'images/images.svg', 'home.extractImages.title', 'home.extractImages.desc', 'extractImages.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('change-metadata', 'images/clipboard-data.svg', 'home.changeMetadata.title', 'home.changeMetadata.desc', 'changeMetadata.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('extract-image-scans', 'images/scanner.svg', 'home.ScannerImageSplit.title', 'home.ScannerImageSplit.desc', 'ScannerImageSplit.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('sign', 'images/sign.svg', 'home.sign.title', 'home.sign.desc', 'sign.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('flatten', 'images/flatten.svg', 'home.flatten.title', 'home.flatten.desc', 'flatten.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('repair', 'images/wrench.svg', 'home.repair.title', 'home.repair.desc', 'repair.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-blanks', 'images/blank-file.svg', 'home.removeBlanks.title', 'home.removeBlanks.desc', 'removeBlanks.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('remove-annotations', 'images/no-chat.svg', 'home.removeAnnotations.title', 'home.removeAnnotations.desc', 'removeAnnotations.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('compare', 'images/scales.svg', 'home.compare.title', 'home.compare.desc', 'compare.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('add-page-numbers', 'images/add-page-numbers.svg', 'home.add-page-numbers.title', 'home.add-page-numbers.desc', 'add-page-numbers.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('auto-rename', 'images/fonts.svg', 'home.auto-rename.title', 'home.auto-rename.desc', 'auto-rename.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('get-info-on-pdf', 'images/info.svg', 'home.getPdfInfo.title', 'home.getPdfInfo.desc', 'getPdfInfo.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('show-javascript', 'images/js.svg', 'home.showJS.title', 'home.showJS.desc', 'showJS.tags')}"></div>
<div th:replace="~{fragments/navbarEntry :: navbarEntry ('stamp', 'images/stamp.svg', 'home.AddStampRequest.title', 'home.AddStampRequest.desc', 'AddStampRequest.tags')}"></div>
</div>
</li>
</ul>
<ul class="navbar-nav flex-nowrap">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" id="navbarDropdown-5" href="#" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<img class="navbar-icon" src="images/star.svg" alt="icon" width="24" height="24">
</a>
<div class="dropdown-menu" id="favoritesDropdown" aria-labelledby="navbarDropdown-5">
<!-- Dropdown items will be added here by JavaScript -->
</div>
</li>
<li class="nav-item">
<a class="nav-link" id="dark-mode-toggle" href="#">
<img class="navbar-icon" id="dark-mode-icon" src="moon.svg" alt="icon" >
</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="languageDropdown" role="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-globe2 globe-icon" viewBox="0 0 20 20">
<path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855-.143.268-.276.56-.395.872.705.157 1.472.257 2.282.287V1.077zM4.249 3.539c.142-.384.304-.744.481-1.078a6.7 6.7 0 0 1 .597-.933A7.01 7.01 0 0 0 3.051 3.05c.362.184.763.349 1.198.49zM3.509 7.5c.036-1.07.188-2.087.436-3.008a9.124 9.124 0 0 1-1.565-.667A6.964 6.964 0 0 0 1.018 7.5h2.49zm1.4-2.741a12.344 12.344 0 0 0-.4 2.741H7.5V5.091c-.91-.03-1.783-.145-2.591-.332zM8.5 5.09V7.5h2.99a12.342 12.342 0 0 0-.399-2.741c-.808.187-1.681.301-2.591.332zM4.51 8.5c.035.987.176 1.914.399 2.741A13.612 13.612 0 0 1 7.5 10.91V8.5H4.51zm3.99 0v2.409c.91.03 1.783.145 2.591.332.223-.827.364-1.754.4-2.741H8.5zm-3.282 3.696c.12.312.252.604.395.872.552 1.035 1.218 1.65 1.887 1.855V11.91c-.81.03-1.577.13-2.282.287zm.11 2.276a6.696 6.696 0 0 1-.598-.933 8.853 8.853 0 0 1-.481-1.079 8.38 8.38 0 0 0-1.198.49 7.01 7.01 0 0 0 2.276 1.522zm-1.383-2.964A13.36 13.36 0 0 1 3.508 8.5h-2.49a6.963 6.963 0 0 0 1.362 3.675c.47-.258.995-.482 1.565-.667zm6.728 2.964a7.009 7.009 0 0 0 2.275-1.521 8.376 8.376 0 0 0-1.197-.49 8.853 8.853 0 0 1-.481 1.078 6.688 6.688 0 0 1-.597.933zM8.5 11.909v3.014c.67-.204 1.335-.82 1.887-1.855.143-.268.276-.56.395-.872A12.63 12.63 0 0 0 8.5 11.91zm3.555-.401c.57.185 1.095.409 1.565.667A6.963 6.963 0 0 0 14.982 8.5h-2.49a13.36 13.36 0 0 1-.437 3.008zM14.982 7.5a6.963 6.963 0 0 0-1.362-3.675c-.47.258-.995.482-1.565.667.248.92.4 1.938.437 3.008h2.49zM11.27 2.461c.177.334.339.694.482 1.078a8.368 8.368 0 0 0 1.196-.49 7.01 7.01 0 0 0-2.275-1.52c.218.283.418.597.597.932zm-.488 1.343a7.765 7.765 0 0 0-.395-.872C9.835 1.897 9.17 1.282 8.5 1.077V4.09c.81-.03 1.577-.13 2.282-.287z"/>
</svg>
</a>
<div class="dropdown-menu" aria-labelledby="languageDropdown">
<th:block th:insert="~{fragments/languages :: langs}"></th:block>
</div>
</li>
<li class="nav-item">
<!-- Settings Button -->
<a href="#" class="nav-link" data-bs-toggle="modal" data-bs-target="#settingsModal">
<img class="navbar-icon" src="images/gear.svg" alt="icon" width="24" height="24">
</a>
</li>
<!-- Search Button and Search Bar -->
<li class="nav-item position-relative">
<a href="#" class="nav-link" id="search-icon">
<img class="navbar-icon" src="images/search.svg" alt="icon" width="24" height="24">
</a>
<!-- Search Bar -->
<div class="collapse position-absolute" id="navbarSearch">
<form class="d-flex p-2 bg-white border search-form" id="searchForm">
<input class="form-control search-input" type="search" th:placeholder="#{home.searchBar}" aria-label="Search" id="navbarSearchInput">
</form>
<!-- Search Results -->
<div id="searchResults" class="border p-2 bg-white search-results"></div>
</div>
</li>
</ul>
</div>
</div> </div>
<script src="js/favourites.js"></script>
<script src="js/search.js"></script>
</nav>
<th:block th:insert="~{fragments/errorBannerPerPage.html :: errorBannerPerPage}"></th:block> <a href="swagger-ui/index.html" class="btn btn-sm btn-outline-primary mx-1" role="button"
<div class="modal fade" id="settingsModal" tabindex="-1" role="dialog" aria-labelledby="settingsModalLabel" aria-hidden="true"> target="_blank">API</a>
<div class="modal-dialog modal-dialog-centered" role="document"> <a href="https://github.com/Stirling-Tools/Stirling-PDF/releases"
<div class="modal-content dark-card"> class="btn btn-sm btn-outline-primary mx-1" id="update-btn" th:utext="#{settings.update}" role="button"
<div class="modal-header"> target="_blank"></a>
<h5 class="modal-title" id="settingsModalLabel" th:text="#{settings.title}"></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<p class="mb-0" th:utext="#{settings.appVersion} + ' ' + ${@appVersion}"></p>
<a href="https://github.com/sponsors/Frooodle" class="btn btn-sm btn-outline-primary" role="button" target="_blank" th:text="#{sponsor}+' Stirling-PDF'"></a>
<a href="swagger-ui/index.html" class="btn btn-sm btn-outline-primary" role="button" target="_blank">API</a>
<a href="https://github.com/Stirling-Tools/Stirling-PDF/releases" class="btn btn-sm btn-outline-primary" id="update-btn" th:utext="#{settings.update}" role="button" target="_blank"></a>
</div>
<div class="mb-3">
<label for="downloadOption" th:utext="#{settings.downloadOption.title}"></label>
<select class="form-control" id="downloadOption">
<option value="sameWindow" th:utext="#{settings.downloadOption.1}"></option>
<option value="newWindow" th:utext="#{settings.downloadOption.2}"></option>
<option value="downloadFile" th:utext="#{settings.downloadOption.3}"></option>
</select>
</div>
<div class="mb-3">
<label for="zipThreshold" th:utext="#{settings.zipThreshold}"></label>
<input type="range" class="form-range" min="1" max="9" step="1" id="zipThreshold" value="4">
<span id="zipThresholdValue" class="ms-2"></span>
</div>
<div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="boredWaiting">
<label class="form-check-label" for="boredWaiting" th:text="#{bored}"></label>
</div>
<a th:if="${@loginEnabled}" href="account" class="btn btn-sm btn-outline-primary" role="button" th:text="#{settings.accountSettings}" target="_blank">Account Settings</a>
</div>
<div class="modal-footer">
<a th:if="${@loginEnabled}" class="btn btn-danger" role="button" th:text="#{settings.signOut}" href="logout">Sign Out</a>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
</div>
</div>
</div>
</div> </div>
<script src="js/settings.js"></script>
</div>
<div class="mb-3">
<label for="downloadOption" th:utext="#{settings.downloadOption.title}"></label>
<select class="form-control" id="downloadOption">
<option value="sameWindow" th:utext="#{settings.downloadOption.1}"></option>
<option value="newWindow" th:utext="#{settings.downloadOption.2}"></option>
<option value="downloadFile" th:utext="#{settings.downloadOption.3}"></option>
</select>
</div>
<div class="mb-3">
<label for="zipThreshold" th:utext="#{settings.zipThreshold}"></label>
<input type="range" class="form-range" min="1" max="9" step="1" id="zipThreshold" value="4">
<span id="zipThresholdValue" class="ms-2"></span>
</div>
<div class="form-check mb-3">
<input type="checkbox" id="boredWaiting">
<label for="boredWaiting" th:text="#{bored}"></label>
</div>
<a th:if="${@loginEnabled}" href="account" class="btn btn-sm btn-outline-primary" role="button"
th:text="#{settings.accountSettings}" target="_blank">Account Settings</a>
</div>
<div class="modal-footer">
<a th:if="${@loginEnabled}" class="btn btn-danger" role="button" th:text="#{settings.signOut}"
href="logout">Sign Out</a>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" th:text="#{close}"></button>
</div>
</div>
</div>
</div>
<script src="js/settings.js"></script>
</div>

View file

@ -1,6 +1,11 @@
<th:block th:fragment="navbarEntry(endpoint, imgSrc, titleKey, descKey, tagKey)" th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}"> <th:block th:fragment="navbarEntry(endpoint, toolIcon, titleKey, descKey, tagKey, toolGroup)"
<a class="dropdown-item" href="#" th:href="@{${endpoint}}" th:classappend="${endpoint.equals(currentPage)} ? 'active' : ''" th:title="#{${descKey}}" th:data-bs-tags="#{${tagKey}}"> th:if="${@endpointConfiguration.isEndpointEnabled(endpoint)}">
<img class="icon" th:src="@{${imgSrc}}" alt="icon"> <a class="dropdown-item" href="#" th:href="@{${endpoint}}"
<span class="icon-text" th:text="#{${titleKey}}"></span> th:classappend="${endpoint.equals(currentPage)} ? ${toolGroup} + ' active' : '' + ${toolGroup}" th:title="#{${descKey}}"
</a> th:data-bs-tags="#{${tagKey}}">
</th:block> <div class="icon" alt="icon" th:class="@{${toolGroup}}">
<span class="material-symbols-rounded nav-icon" th:text="@{${toolIcon}}"></span>
<span class="icon-text" th:text="#{${titleKey}}"></span>
</div>
</a>
</th:block>

View file

@ -1,104 +1,222 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title='')}"></th:block> <th:block th:insert="~{fragments/common :: head(title='')}"></th:block>
</head> </head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<!-- Jumbotron --> <!-- Jumbotron -->
<div class="bg-light p-5 rounded d-none d-md-block" id="jumbotron"> <div class="p-5 rounded d-none d-md-block" id="jumbotron">
<div class="container"> <div class="container">
<h1 class="display-4" th:text="${@appName}"></h1> <h1 class="display-4 fw-normal" th:text="${@appName}"></h1>
<p class="lead" th:text="${@homeText != 'null' and @homeText != null and @homeText != ''} ? ${@homeText} : #{home.desc}"></p> <p class="lead fs-4"
</div> th:text="${@homeText != 'null' and @homeText != null and @homeText != ''} ? ${@homeText} : #{home.desc}">
</p>
</div> </div>
<br class="d-md-none"> </div>
<!-- Features --> <br class="d-md-none">
<script src="js/homecard.js"></script> <!-- Features -->
<script src="js/homecard.js"></script>
<div class=" container"> <div class=" container">
<br> <br>
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus> <span class="material-symbols-rounded search-icon">
<div class="features-container"> search
<div th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', svgPath='images/pipeline.svg', tags=#{pipeline.tags})}"></div> </span>
<input type="text" id="searchBar" onkeyup="filterCards()" th:placeholder="#{home.searchBar}" autofocus>
<div class="features-container">
<div
th:replace="~{fragments/card :: card(id='pipeline', cardTitle=#{home.pipeline.title}, cardText=#{home.pipeline.desc}, cardLink='pipeline', toolIcon='family_history', tags=#{pipeline.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', toolIcon='menu_book', tags=#{viewPdf.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', toolIcon='construction', tags=#{multiTool.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', toolIcon='add_to_photos', tags=#{merge.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', toolIcon='cut', tags=#{split.tags}, toolGroup='organize')}">
</div>
<div th:replace="~{fragments/card :: card(id='view-pdf', cardTitle=#{home.viewPdf.title}, cardText=#{home.viewPdf.desc}, cardLink='view-pdf', svgPath='images/book-opened.svg', tags=#{viewPdf.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='multi-tool', cardTitle=#{home.multiTool.title}, cardText=#{home.multiTool.desc}, cardLink='multi-tool', svgPath='images/tools.svg', tags=#{multiTool.tags})}"></div> th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', toolIcon='rotate_right', tags=#{rotate.tags}, toolGroup='organize')}">
<div th:replace="~{fragments/card :: card(id='merge-pdfs', cardTitle=#{home.merge.title}, cardText=#{home.merge.desc}, cardLink='merge-pdfs', svgPath='images/union.svg', tags=#{merge.tags})}"></div> </div>
<div th:replace="~{fragments/card :: card(id='split-pdfs', cardTitle=#{home.split.title}, cardText=#{home.split.desc}, cardLink='split-pdfs', svgPath='images/layout-split.svg', tags=#{split.tags})}"></div> <div
th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', toolIcon='crop', tags=#{crop.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', toolIcon='123', tags=#{add-page-numbers.tags}, toolGroup='other')}">
</div>
<div th:replace="~{fragments/card :: card(id='rotate-pdf', cardTitle=#{home.rotate.title}, cardText=#{home.rotate.desc}, cardLink='rotate-pdf', svgPath='images/arrow-clockwise.svg', tags=#{rotate.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='crop', cardTitle=#{home.crop.title}, cardText=#{home.crop.desc}, cardLink='crop', svgPath='images/crop.svg', tags=#{crop.tags})}"></div> th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', toolIcon='palette', tags=#{adjust-contrast.tags}, toolGroup='advance')}">
<div th:replace="~{fragments/card :: card(id='add-page-numbers', cardTitle=#{home.add-page-numbers.title}, cardText=#{home.add-page-numbers.desc}, cardLink='add-page-numbers', svgPath='images/add-page-numbers.svg', tags=#{add-page-numbers.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', toolIcon='image', tags=#{imageToPdf.tags}, toolGroup='image')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', toolIcon='image', tags=#{pdfToImage.tags}, toolGroup='image')}">
</div>
<div th:replace="~{fragments/card :: card(id='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', svgPath='images/adjust-contrast.svg', tags=#{adjust-contrast.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='img-to-pdf', cardTitle=#{home.imageToPdf.title}, cardText=#{home.imageToPdf.desc}, cardLink='img-to-pdf', svgPath='images/image.svg', tags=#{imageToPdf.tags})}"></div> th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', toolIcon='format_list_bulleted', tags=#{pdfOrganiser.tags}, toolGroup='organize')}">
<div th:replace="~{fragments/card :: card(id='pdf-to-img', cardTitle=#{home.pdfToImage.title}, cardText=#{home.pdfToImage.desc}, cardLink='pdf-to-img', svgPath='images/image.svg', tags=#{pdfToImage.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', toolIcon='text_fields', tags=#{addImage.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', toolIcon='water_drop', tags=#{watermark.tags}, toolGroup='security')}">
</div>
<div th:replace="~{fragments/card :: card(id='pdf-organizer', cardTitle=#{home.pdfOrganiser.title}, cardText=#{home.pdfOrganiser.desc}, cardLink='pdf-organizer', svgPath='images/sort-numeric-down.svg', tags=#{pdfOrganiser.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='add-image', cardTitle=#{home.addImage.title}, cardText=#{home.addImage.desc}, cardLink='add-image', svgPath='images/file-earmark-richtext.svg', tags=#{addImage.tags})}"></div> th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', toolIcon='draft', tags=#{fileToPDF.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='add-watermark', cardTitle=#{home.watermark.title}, cardText=#{home.watermark.desc}, cardLink='add-watermark', svgPath='images/droplet.svg', tags=#{watermark.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', toolIcon='delete', tags=#{removePages.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', toolIcon='lock', tags=#{addPassword.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', toolIcon='lock_open_right', tags=#{removePassword.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', toolIcon='assignment', tags=#{changeMetadata.tags}, toolGroup='other')}">
</div>
<div th:replace="~{fragments/card :: card(id='file-to-pdf', cardTitle=#{home.fileToPDF.title}, cardText=#{home.fileToPDF.desc}, cardLink='file-to-pdf', svgPath='images/file.svg', tags=#{fileToPDF.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='remove-pages', cardTitle=#{home.removePages.title}, cardText=#{home.removePages.desc}, cardLink='remove-pages', svgPath='images/file-earmark-x.svg', tags=#{removePages.tags})}"></div> th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', toolIcon='encrypted', tags=#{permissions.tags}, toolGroup='security')}">
<div th:replace="~{fragments/card :: card(id='add-password', cardTitle=#{home.addPassword.title}, cardText=#{home.addPassword.desc}, cardLink='add-password', svgPath='images/lock.svg', tags=#{addPassword.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', toolIcon='quick_reference_all', tags=#{ocr.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', toolIcon='photo_library', tags=#{extractImages.tags}, toolGroup='other')}">
</div>
<div th:replace="~{fragments/card :: card(id='remove-password', cardTitle=#{home.removePassword.title}, cardText=#{home.removePassword.desc}, cardLink='remove-password', svgPath='images/unlock.svg', tags=#{removePassword.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', svgPath='images/file-zip.svg', tags=#{compressPdfs.tags})}"></div> th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', toolIcon='picture_as_pdf', tags=#{pdfToPDFA.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', svgPath='images/clipboard-data.svg', tags=#{changeMetadata.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', toolIcon='description', tags=#{PDFToWord.tags}, toolGroup='word')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', toolIcon='slideshow', tags=#{PDFToPresentation.tags}, toolGroup='ppt')}">
</div>
<div th:replace="~{fragments/card :: card(id='change-permissions', cardTitle=#{home.permissions.title}, cardText=#{home.permissions.desc}, cardLink='change-permissions', svgPath='images/shield-lock.svg', tags=#{permissions.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='ocr-pdf', cardTitle=#{home.ocr.title}, cardText=#{home.ocr.desc}, cardLink='ocr-pdf', svgPath='images/search.svg', tags=#{ocr.tags})}"></div> th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', toolIcon='text_fields', tags=#{PDFToText.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='extract-images', cardTitle=#{home.extractImages.title}, cardText=#{home.extractImages.desc}, cardLink='extract-images', svgPath='images/images.svg', tags=#{extractImages.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', toolIcon='html', tags=#{PDFToHTML.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', toolIcon='code', tags=#{PDFToXML.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', toolIcon='scanner', tags=#{ScannerImageSplit.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', toolIcon='signature', tags=#{sign.tags}, toolGroup='sign')}">
</div>
<div
th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', toolIcon='layers_clear', tags=#{flatten.tags}, toolGroup='other')}">
</div>
<div th:replace="~{fragments/card :: card(id='pdf-to-pdfa', cardTitle=#{home.pdfToPDFA.title}, cardText=#{home.pdfToPDFA.desc}, cardLink='pdf-to-pdfa', svgPath='images/file-earmark-pdf.svg', tags=#{pdfToPDFA.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='pdf-to-word', cardTitle=#{home.PDFToWord.title}, cardText=#{home.PDFToWord.desc}, cardLink='pdf-to-word', svgPath='images/file-earmark-word.svg', tags=#{PDFToWord.tags})}"></div> th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', toolIcon='build', tags=#{repair.tags}, toolGroup='advance')}">
<div th:replace="~{fragments/card :: card(id='pdf-to-presentation', cardTitle=#{home.PDFToPresentation.title}, cardText=#{home.PDFToPresentation.desc}, cardLink='pdf-to-presentation', svgPath='images/file-earmark-ppt.svg', tags=#{PDFToPresentation.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', toolIcon='scan_delete', tags=#{removeBlanks.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', toolIcon='thread_unread', tags=#{removeAnnotations.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', toolIcon='compare', tags=#{compare.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', toolIcon='workspace_premium', tags=#{certSign.tags}, toolGroup='security')}">
</div>
<div
th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', toolIcon='dashboard', tags=#{pageLayout.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', toolIcon='fullscreen', tags=#{scalePages.tags}, toolGroup='organize')}">
</div>
<div th:replace="~{fragments/card :: card(id='pdf-to-text', cardTitle=#{home.PDFToText.title}, cardText=#{home.PDFToText.desc}, cardLink='pdf-to-text', svgPath='images/filetype-txt.svg', tags=#{PDFToText.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='pdf-to-html', cardTitle=#{home.PDFToHTML.title}, cardText=#{home.PDFToHTML.desc}, cardLink='pdf-to-html', svgPath='images/filetype-html.svg', tags=#{PDFToHTML.tags})}"></div> th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', toolIcon='text_fields_alt', tags=#{auto-rename.tags}, toolGroup='advance')}">
<div th:replace="~{fragments/card :: card(id='pdf-to-xml', cardTitle=#{home.PDFToXML.title}, cardText=#{home.PDFToXML.desc}, cardLink='pdf-to-xml', svgPath='images/filetype-xml.svg', tags=#{PDFToXML.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', toolIcon='cut', tags=#{autoSplitPDF.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', toolIcon='sanitizer', tags=#{sanitizePdf.tags}, toolGroup='security')}">
</div>
<div th:replace="~{fragments/card :: card(id='extract-image-scans', cardTitle=#{home.ScannerImageSplit.title}, cardText=#{home.ScannerImageSplit.desc}, cardLink='extract-image-scans', svgPath='images/scanner.svg', tags=#{ScannerImageSplit.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='sign', cardTitle=#{home.sign.title}, cardText=#{home.sign.desc}, cardLink='sign', svgPath='images/sign.svg', tags=#{sign.tags})}"></div> th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', toolIcon='link', tags=#{URLToPDF.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', svgPath='images/flatten.svg', tags=#{flatten.tags})}"></div> </div>
<div
th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', toolIcon='html', tags=#{HTMLToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', toolIcon='markdown', tags=#{MarkdownToPDF.tags}, toolGroup='convert')}">
</div>
<div
th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', toolIcon='info', tags=#{getPdfInfo.tags}, toolGroup='other')}">
</div>
<div
th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', toolIcon='upload', tags=#{extractPage.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', toolIcon='looks_one', tags=#{PdfToSinglePage.tags}, toolGroup='organize')}">
</div>
<div
th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', toolIcon='javascript', tags=#{showJS.tags}, toolGroup='advance')}">
</div>
<div
th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', toolIcon='ink_eraser', tags=#{autoRedact.tags}, toolGroup='security')}">
</div>
<div th:replace="~{fragments/card :: card(id='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', svgPath='images/wrench.svg', tags=#{repair.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='remove-blanks', cardTitle=#{home.removeBlanks.title}, cardText=#{home.removeBlanks.desc}, cardLink='remove-blanks', svgPath='images/blank-file.svg', tags=#{removeBlanks.tags})}"></div> th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', toolIcon='csv', tags=#{tableExtraxt.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='remove-annotations', cardTitle=#{home.removeAnnotations.title}, cardText=#{home.removeAnnotations.desc}, cardLink='remove-annotations', svgPath='images/no-chat.svg', tags=#{removeAnnotations.tags})}"></div> </div>
<div th:replace="~{fragments/card :: card(id='compare', cardTitle=#{home.compare.title}, cardText=#{home.compare.desc}, cardLink='compare', svgPath='images/scales.svg', tags=#{compare.tags})}"></div> <div
th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', toolIcon='vertical_split', tags=#{autoSizeSplitPDF.tags}, toolGroup='advance')}">
<div th:replace="~{fragments/card :: card(id='cert-sign', cardTitle=#{home.certSign.title}, cardText=#{home.certSign.desc}, cardLink='cert-sign', svgPath='images/award.svg', tags=#{certSign.tags})}"></div> </div>
<div th:replace="~{fragments/card :: card(id='multi-page-layout', cardTitle=#{home.pageLayout.title}, cardText=#{home.pageLayout.desc}, cardLink='multi-page-layout', svgPath='images/page-layout.svg', tags=#{pageLayout.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='scale-pages', cardTitle=#{home.scalePages.title}, cardText=#{home.scalePages.desc}, cardLink='scale-pages', svgPath='images/scale-pages.svg', tags=#{scalePages.tags})}"></div> th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', toolIcon='layers', tags=#{overlay-pdfs.tags}, toolGroup='advance')}">
</div>
<div th:replace="~{fragments/card :: card(id='auto-rename', cardTitle=#{home.auto-rename.title}, cardText=#{home.auto-rename.desc}, cardLink='auto-rename', svgPath='images/fonts.svg', tags=#{auto-rename.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='auto-split-pdf', cardTitle=#{home.autoSplitPDF.title}, cardText=#{home.autoSplitPDF.desc}, cardLink='auto-split-pdf', svgPath='images/layout-split.svg', tags=#{autoSplitPDF.tags})}"></div> th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', toolIcon='grid_on', tags=#{split-by-sections.tags}, toolGroup='advance')}">
<div th:replace="~{fragments/card :: card(id='sanitize-pdf', cardTitle=#{home.sanitizePdf.title}, cardText=#{home.sanitizePdf.desc}, cardLink='sanitize-pdf', svgPath='images/sanitize.svg', tags=#{sanitizePdf.tags})}"></div> </div>
<div
<div th:replace="~{fragments/card :: card(id='url-to-pdf', cardTitle=#{home.URLToPDF.title}, cardText=#{home.URLToPDF.desc}, cardLink='url-to-pdf', svgPath='images/url.svg', tags=#{URLToPDF.tags})}"></div> th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', toolIcon='images/book.svg', tags=#{BookToPDF.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='html-to-pdf', cardTitle=#{home.HTMLToPDF.title}, cardText=#{home.HTMLToPDF.desc}, cardLink='html-to-pdf', svgPath='images/html.svg', tags=#{HTMLToPDF.tags})}"></div> </div>
<div th:replace="~{fragments/card :: card(id='markdown-to-pdf', cardTitle=#{home.MarkdownToPDF.title}, cardText=#{home.MarkdownToPDF.desc}, cardLink='markdown-to-pdf', svgPath='images/markdown.svg', tags=#{MarkdownToPDF.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='get-info-on-pdf', cardTitle=#{home.getPdfInfo.title}, cardText=#{home.getPdfInfo.desc}, cardLink='get-info-on-pdf', svgPath='images/info.svg', tags=#{getPdfInfo.tags})}"></div> th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', toolIcon='images/book.svg', tags=#{PDFToBook.tags}, toolGroup='convert')}">
<div th:replace="~{fragments/card :: card(id='extract-page', cardTitle=#{home.extractPage.title}, cardText=#{home.extractPage.desc}, cardLink='extract-page', svgPath='images/extract.svg', tags=#{extractPage.tags})}"></div> </div>
<div th:replace="~{fragments/card :: card(id='pdf-to-single-page', cardTitle=#{home.PdfToSinglePage.title}, cardText=#{home.PdfToSinglePage.desc}, cardLink='pdf-to-single-page', svgPath='images/single-page.svg', tags=#{PdfToSinglePage.tags})}"></div> <div
<div th:replace="~{fragments/card :: card(id='show-javascript', cardTitle=#{home.showJS.title}, cardText=#{home.showJS.desc}, cardLink='show-javascript', svgPath='images/js.svg', tags=#{showJS.tags})}"></div> th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', toolIcon='approval', tags=#{AddStampRequest.tags}, toolGroup='security')}">
<div th:replace="~{fragments/card :: card(id='auto-redact', cardTitle=#{home.autoRedact.title}, cardText=#{home.autoRedact.desc}, cardLink='auto-redact', svgPath='images/eraser-fill.svg', tags=#{autoRedact.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-csv', cardTitle=#{home.tableExtraxt.title}, cardText=#{home.tableExtraxt.desc}, cardLink='pdf-to-csv', svgPath='images/pdf-csv.svg', tags=#{tableExtraxt.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='split-by-size-or-count', cardTitle=#{home.autoSizeSplitPDF.title}, cardText=#{home.autoSizeSplitPDF.desc}, cardLink='split-by-size-or-count', svgPath='images/layout-split.svg', tags=#{autoSizeSplitPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='overlay-pdf', cardTitle=#{home.overlay-pdfs.title}, cardText=#{home.overlay-pdfs.desc}, cardLink='overlay-pdf', svgPath='images/overlay.svg', tags=#{overlay-pdfs.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='split-pdf-by-sections', cardTitle=#{home.split-by-sections.title}, cardText=#{home.split-by-sections.desc}, cardLink='split-pdf-by-sections', svgPath='images/layout-split.svg', tags=#{split-by-sections.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='book-to-pdf', cardTitle=#{home.BookToPDF.title}, cardText=#{home.BookToPDF.desc}, cardLink='book-to-pdf', svgPath='images/book.svg', tags=#{BookToPDF.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='pdf-to-book', cardTitle=#{home.PDFToBook.title}, cardText=#{home.PDFToBook.desc}, cardLink='pdf-to-book', svgPath='images/book.svg', tags=#{PDFToBook.tags})}"></div>
<div th:replace="~{fragments/card :: card(id='stamp', cardTitle=#{home.AddStampRequest.title}, cardText=#{home.AddStampRequest.desc}, cardLink='stamp', svgPath='images/stamp.svg', tags=#{AddStampRequest.tags})}"></div>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html> </html>

View file

@ -11,7 +11,7 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{licenses.header}">3rd Party licenses</h2> <h2 th:text="#{licenses.header}">3rd Party licenses</h2>
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>

View file

@ -8,28 +8,8 @@
<body> <body>
<div class="your-container-class"></div> <div class="your-container-class"></div>
<div class="container-flex"> <div class="container-flex">
<main class="form-signin text-center"> <main class="form-signin">
<script> <script>
function setInputMode(elementId, mode) {
var inputElement = document.getElementById(elementId);
if (!inputElement) return; // If the element doesn't exist, exit the function
switch (mode) {
case "on":
inputElement.classList.add("bg-dark", "text-light");
inputElement.classList.remove("bg-light", "text-dark");
break;
case "off":
inputElement.classList.add("bg-light", "text-dark");
inputElement.classList.remove("bg-dark", "text-light");
break;
case "rainbow":
// Assuming you have defined some classes for rainbow mode
break;
}
}
document.addEventListener('modeChanged', function(e) { document.addEventListener('modeChanged', function(e) {
var mode = e.detail; var mode = e.detail;
@ -137,34 +117,38 @@
<span th:text="#{changedCredsMessage}">Default message if not found</span> <span th:text="#{changedCredsMessage}">Default message if not found</span>
</div> </div>
<form th:action="@{login}" method="post"> <form th:action="@{login}" method="post">
<img class="mb-4" src="favicon.svg?v=2" alt="" width="144" height="144"> <div class="text-center">
<h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1> <img class="mb-4" src="favicon.svg?v=2" alt="" width="144" height="144">
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2> <h1 class="h1 mb-3 fw-normal" th:text="${@appName}">Stirling-PDF</h1>
<h2 class="h5 mb-3 fw-normal" th:text="#{login.signinTitle}">Please sign in</h2>
</div>
<div class="form-floating"> <div class="form-floating">
<input type="text" class="form-control bg-dark text-light" id="username" name="username" placeholder="admin"> <input type="text" class="form-control" id="username" name="username" placeholder="admin">
<label for="username" th:text="#{username}">Username</label> <label for="username" th:text="#{username}">Username</label>
</div> </div>
<div class="form-floating"> <div class="form-floating">
<input type="password" class="form-control bg-dark text-light" id="password" name="password" placeholder="Password"> <input type="password" class="form-control" id="password" name="password" placeholder="Password">
<label for="password" th:text="#{password}">Password</label> <label for="password" th:text="#{password}">Password</label>
</div> </div>
<div class="checkbox mb-3"> <div class="form-check m-2 mb-3">
<input type="checkbox" id="remember" value="remember-me"> <input type="checkbox" id="remember" value="remember-me">
<label for="remember" th:text="#{login.rememberme}"></label> <label for="remember" th:text="#{login.rememberme}"></label>
</div> </div>
<button class="w-100 btn btn-lg btn-primary" type="submit" th:text="#{login.signin}">Sign in</button> <button class="w-100 btn btn-lg btn-primary" type="submit" th:text="#{login.signin}">Sign in</button>
</form> </form>
<div class="mt-3"> <!-- Added a margin-top for spacing --> <div class="mt-3"> <!-- Added a margin-top for spacing -->
<div class="dropdown"> <div class="dropdown text-center">
<button class="btn btn-secondary dropdown-toggle" type="button" id="languageDropdown" data-bs-toggle="dropdown" aria-expanded="false"> <button class="btn btn-secondary dropdown-toggle" type="button" id="languageDropdown" data-bs-toggle="dropdown" aria-expanded="false">
<img src="images/flags/gb.svg" alt="icon" width="20" height="15"> English (GB) <img src="images/flags/gb.svg" alt="icon" width="20" height="15"> English (GB)
<!-- Default language placeholder --> <!-- Default language placeholder -->
</button> </button>
<div class="dropdown-menu" aria-labelledby="languageDropdown"> <div class="dropdown-menu" aria-labelledby="languageDropdown">
<!-- Here's where the fragment will be included --> <!-- Here's where the fragment will be included -->
<th:block th:replace="~{fragments/languages :: langs}"></th:block> <div class="scrollable-y">
<th:block th:replace="~{fragments/languages :: langs}"></th:block>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container" id="dropContainer"> <div class="container" id="dropContainer">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{merge.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">add_to_photos</span>
<span class="tool-header-text" th:text="#{merge.header}"></span>
</div>
<form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data"> <form action="api/v1/general/merge-pdfs" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label th:text="#{multiPdfDropPrompt}"></label> <label th:text="#{multiPdfDropPrompt}"></label>
@ -22,7 +25,7 @@
<div class="mb-3"> <div class="mb-3">
<ul id="selectedFiles" class="list-group"></ul> <ul id="selectedFiles" class="list-group"></ul>
</div> </div>
<div class="mb-3 text-center"> <div class="mb-3">
<button type="button" id="sortByNameBtn" class="btn btn-info" th:text="#{merge.sortByName}"></button> <button type="button" id="sortByNameBtn" class="btn btn-info" th:text="#{merge.sortByName}"></button>
<button type="button" id="sortByDateBtn" class="btn btn-info" th:text="#{merge.sortByDate}"></button> <button type="button" id="sortByDateBtn" class="btn btn-info" th:text="#{merge.sortByDate}"></button>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{merge.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{merge.submit}"></button>

View file

@ -13,8 +13,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{addImage.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">add_photo_alternate</span>
<span class="tool-header-text" th:text="#{addImage.header}"></span>
</div>
<!-- pdf selector --> <!-- pdf selector -->
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multiple=false, accept='application/pdf')}"></div>

View file

@ -55,8 +55,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{addPageNumbers.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">123</span>
<span class="tool-header-text" th:text="#{addPageNumbers.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/add-page-numbers}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/add-page-numbers}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>

View file

@ -20,7 +20,7 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-12"> <div class="col-md-12" id="bg-card">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-3"> <div class="col-md-3">
<div id="sliders-container" style="display:none;"> <div id="sliders-container" style="display:none;">
@ -35,7 +35,10 @@
</div> </div>
</div> </div>
<div class="col-md-7"> <div class="col-md-7">
<h2 th:text="#{adjustContrast.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">palette</span>
<span class="tool-header-text" th:text="#{adjustContrast.header}"></span>
</div>
<div class="col-md-8"> <div class="col-md-8">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
</div> </div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{autoCrop.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">crop</span>
<span class="tool-header-text" th:text="#{autoCrop.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/auto-crop}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/auto-crop}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{auto-rename.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">text_fields_alt</span>
<span class="tool-header-text" th:text="#{auto-rename.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/auto-rename}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/auto-rename}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>

View file

@ -11,18 +11,21 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{changeMetadata.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">assignment</span>
<span class="tool-header-text" th:text="#{changeMetadata.header}"></span>
</div>
<form method="post" id="form1" enctype="multipart/form-data" th:action="@{api/v1/misc/update-metadata}"> <form method="post" id="form1" enctype="multipart/form-data" th:action="@{api/v1/misc/update-metadata}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p> <p class="text-muted" th:text="#{changeMetadata.selectText.1}"></p>
<div class="mb-3-inline form-check"> <div class="form-check mb-3-inline ms-3">
<input type="checkbox" class="form-check-input" id="deleteAll" name="deleteAll"> <input type="checkbox" id="deleteAll" name="deleteAll">
<label class="ms-3" for="deleteAll" th:text="#{changeMetadata.selectText.2}" ></label> <label for="deleteAll" th:text="#{changeMetadata.selectText.2}" ></label>
</div> </div>
<div class="mb-3-inline form-check"> <div class="form-check mb-3-inline ms-3">
<input type="checkbox" class="form-check-input" id="customModeCheckbox"> <input type="checkbox" id="customModeCheckbox">
<label class="ms-3" for="customModeCheckbox" th:text="#{changeMetadata.selectText.3}"></label> <label for="customModeCheckbox" th:text="#{changeMetadata.selectText.3}"></label>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label class="form-check-label" for="author" th:text="#{changeMetadata.author}"></label> <label class="form-check-label" for="author" th:text="#{changeMetadata.author}"></label>

View file

@ -20,8 +20,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-9"> <div class="col-md-9" id="bg-card">
<h2 th:text="#{compare.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">compare</span>
<span class="tool-header-text" th:text="#{compare.header}"></span>
</div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput2', multiple=false, accept='application/pdf', remoteCall='false')}"></div>
<button class="btn btn-primary" onclick="comparePDFs()" th:text="#{compare.submit}"></button> <button class="btn btn-primary" onclick="comparePDFs()" th:text="#{compare.submit}"></button>

View file

@ -1,47 +1,55 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<th:block th:insert="~{fragments/common :: head(title=#{compress.title}, header=#{compress.header})}"></th:block>
</head>
<body> <head>
<th:block th:insert="~{fragments/common :: game}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{compress.title}, header=#{compress.header})}"></th:block>
<div id="page-container"> </head>
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <body>
<br><br> <th:block th:insert="~{fragments/common :: game}"></th:block>
<div class="container"> <div id="page-container">
<div class="row justify-content-center"> <div id="content-wrap">
<div class="col-md-6"> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<h2 th:text="#{compress.header}"></h2> <br><br>
<form action="#" th:action="@{api/v1/misc/compress-pdf}" method="post" enctype="multipart/form-data"> <div class="container">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div class="row justify-content-center">
<div class="card mb-3"> <div class="col-md-6" id="bg-card">
<div class="card-body"> <div class="tool-header">
<h4 th:text="#{compress.selectText.1}"></h4> <span class="material-symbols-rounded tool-header-icon advance">zoom_in_map</span>
<label for="optimizeLevel" th:text="#{compress.selectText.2}"></label> <span class="tool-header-text" th:text="#{compress.header}"></span>
<select name="optimizeLevel" id="optimizeLevel" class="form-control">
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
<option value="4" th:text="#{compress.selectText.3}"></option>
</select>
</div>
</div>
<div class="card mb-3">
<div class="card-body">
<h4 th:text="#{compress.selectText.4}"></h4>
<label for="expectedOutputSize" th:text="#{compress.selectText.5}"></label>
<input type="text" name="expectedOutputSize" id="expectedOutputSize" class="form-control">
</div>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{compress.submit}"></button>
</form>
</div> </div>
<form action="#" th:action="@{api/v1/misc/compress-pdf}" method="post" enctype="multipart/form-data">
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
</div>
<div class="card mb-3">
<div class="card-body">
<h4 th:text="#{compress.selectText.1}"></h4>
<label for="optimizeLevel" th:text="#{compress.selectText.2}"></label>
<select name="optimizeLevel" id="optimizeLevel" class="form-control">
<option value="1">1</option>
<option value="2" selected>2</option>
<option value="3">3</option>
<option value="4" th:text="#{compress.selectText.3}"></option>
</select>
</div>
</div>
<div class="card mb-3">
<div class="card-body">
<h4 th:text="#{compress.selectText.4}"></h4>
<label for="expectedOutputSize" th:text="#{compress.selectText.5}"></label>
<input type="text" name="expectedOutputSize" id="expectedOutputSize" class="form-control">
</div>
</div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{compress.submit}"></button>
</form>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html> </html>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{home.ScannerImageSplit.title}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">scanner</span>
<span class="tool-header-text" th:text="#{home.ScannerImageSplit.title}"></span>
</div>
<form id="multiPdfForm" th:action="@{api/v1/misc/extract-image-scans}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/misc/extract-image-scans}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='image/*, application/pdf')}"></div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{extractImages.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">photo_library</span>
<span class="tool-header-text" th:text="#{extractImages.header}"></span>
</div>
<form id="multiPdfForm" th:action="@{api/v1/misc/extract-images}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/misc/extract-images}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{flatten.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">layers_clear</span>
<span class="tool-header-text" th:text="#{flatten.header}"></span>
</div>
<form id="pdfForm" class="mb-3"> <form id="pdfForm" class="mb-3">
<div class="custom-file"> <div class="custom-file">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>

View file

@ -34,17 +34,20 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{ocr.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">quick_reference_all</span>
<span class="tool-header-text" th:text="#{ocr.header}"></span>
</div>
<form th:if="${#lists.size(languages) > 0}" action="#" th:action="@{api/v1/misc/ocr-pdf}" method="post" enctype="multipart/form-data" class="mb-3"> <form th:if="${#lists.size(languages) > 0}" action="#" th:action="@{api/v1/misc/ocr-pdf}" method="post" enctype="multipart/form-data" class="mb-3">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label> <label for="languages" class="form-label" th:text="#{ocr.selectText.1}"></label>
<hr> <hr>
<div id="languages"> <div id="languages">
<div th:each="language, iterStat : ${languages}"> <div class="form-check" th:each="language, iterStat : ${languages}">
<input type="checkbox" th:name="languages" th:value="${language}" required th:id="${'language-' + language}" onchange="handleLangSelection()" /> <input type="checkbox" th:name="languages" th:value="${language}" required th:id="${'language-' + language}" onchange="handleLangSelection()" />
<label class="form-check-label" th:for="${'language-' + language}" th:text="${language}"></label> <label th:for="${'language-' + language}" th:text="${language}"></label>
</div> </div>
</div> </div>
<hr> <hr>
@ -59,25 +62,25 @@
</div> </div>
<br> <br>
<label for="languages" class="form-label" th:text="#{ocr.selectText.9}"></label> <label for="languages" class="form-label" th:text="#{ocr.selectText.9}"></label>
<div class="form-check"> <div class="form-check ms-3">
<input type="checkbox" class="form-check-input" name="sidecar" id="sidecar" /> <input type="checkbox" name="sidecar" id="sidecar" />
<label class="form-check-label" for="sidecar" th:text="#{ocr.selectText.2}"></label> <label for="sidecar" th:text="#{ocr.selectText.2}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input type="checkbox" class="form-check-input" name="deskew" id="deskew" /> <input type="checkbox" name="deskew" id="deskew" />
<label class="form-check-label" for="deskew" th:text="#{ocr.selectText.3}"></label> <label for="deskew" th:text="#{ocr.selectText.3}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input type="checkbox" class="form-check-input" name="clean" id="clean" /> <input type="checkbox" name="clean" id="clean" />
<label class="form-check-label" for="clean" th:text="#{ocr.selectText.4}"></label> <label for="clean" th:text="#{ocr.selectText.4}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input type="checkbox" class="form-check-input" name="clean-final" id="clean-final" /> <input type="checkbox" name="clean-final" id="clean-final" />
<label class="form-check-label" for="clean-final" th:text="#{ocr.selectText.5}"></label> <label for="clean-final" th:text="#{ocr.selectText.5}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input type="checkbox" class="form-check-input" name="removeImagesAfter" id="removeImagesAfter" /> <input type="checkbox" name="removeImagesAfter" id="removeImagesAfter" />
<label class="form-check-label" for="removeImagesAfter" th:text="#{ocr.selectText.11}"></label> <label for="removeImagesAfter" th:text="#{ocr.selectText.11}"></label>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{ocr.selectText.12}"></label> <label th:text="#{ocr.selectText.12}"></label>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{removeAnnotations.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">thread_unread</span>
<span class="tool-header-text" th:text="#{removeAnnotations.header}"></span>
</div>
<form id="pdfForm" class="mb-3"> <form id="pdfForm" class="mb-3">
<div class="custom-file"> <div class="custom-file">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf', remoteCall='false')}"></div>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{removeBlanks.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">scan_delete</span>
<span class="tool-header-text" th:text="#{removeBlanks.header}"></span>
</div>
<form id="multiPdfForm" th:action="@{api/v1/misc/remove-blanks}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/misc/remove-blanks}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{repair.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">build</span>
<span class="tool-header-text" th:text="#{repair.header}"></span>
</div>
<form id="multiPdfForm" th:action="@{api/v1/misc/repair}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/misc/repair}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{repair.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{repair.submit}"></button>

View file

@ -20,8 +20,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-12"> <div class="col-md-12" id="bg-card">
<h2 th:text="#{showJS.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">javascript</span>
<span class="tool-header-text" th:text="#{showJS.header}"></span>
</div>
<form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{show-javascript}"> <form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{show-javascript}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div>
<br> <br>

View file

@ -22,8 +22,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{AddStampRequest.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">approval</span>
<span class="tool-header-text" th:text="#{AddStampRequest.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/add-stamp}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/misc/add-stamp}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<br> <br>

View file

@ -11,13 +11,16 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pageLayout.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">dashboard</span>
<span class="tool-header-text" th:text="#{pageLayout.header}"></span>
</div>
<form id="multiPdfForm" th:action="@{api/v1/general/multi-page-layout}" method="post" enctype="multipart/form-data"> <form id="multiPdfForm" th:action="@{api/v1/general/multi-page-layout}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="pagesPerSheet" th:text="#{pageLayout.pagesPerSheet}"></label> <label for="pagesPerSheet" th:text="#{pageLayout.pagesPerSheet}"></label>
<select id="pagesPerSheet" name="pagesPerSheet"> <select class="form-control" id="pagesPerSheet" name="pagesPerSheet">
<option value="2">2</option> <option value="2">2</option>
<option value="3">3</option> <option value="3">3</option>
<option value="4">4</option> <option value="4">4</option>
@ -25,9 +28,9 @@
<option value="16">16</option> <option value="16">16</option>
</select> </select>
</div> </div>
<div class="mb-3"> <div class="form-check mb-3">
<input type="checkbox" class="form-check-input" id="addBorder" name="addBorder"> <input type="checkbox" id="addBorder" name="addBorder">
<label class="form-check-label" for="addBorder" th:text="#{pageLayout.addBorder}"></label> <label for="addBorder" th:text="#{pageLayout.addBorder}"></label>
</div> </div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageLayout.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pageLayout.submit}"></button>
</form> </form>

View file

@ -1,104 +1,108 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<th:block th:insert="~{fragments/common :: head(title=#{multiTool.title}, header=#{multiTool.header})}"></th:block>
</head>
<body> <head>
<div id="image-highlighter"></div> <th:block th:insert="~{fragments/common :: head(title=#{multiTool.title}, header=#{multiTool.header})}"></th:block>
<div id="page-container"> </head>
<div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <body>
<br><br> <div id="image-highlighter"></div>
<div class="multi-tool-container"> <div id="page-container">
<div class="row justify-content-center"> <div id="content-wrap">
<h2 th:text="#{multiTool.header}"></h2> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<div class="col-md-12" id="pages-container-wrapper"> <br><br>
<div id="pages-container"> <div class="container">
<div class="page-container" th:each="pdf, status: ${pdfList}" th:id="'page-container-' + ${status.index}"> <div class="row justify-content-center">
<div class="page-number-container"> <div class="col-md-12">
<span th:text="${status.index + 1}"></span> <div id="bg-card">
</div> <div class="tool-header">
<img th:src="${pdf.imageUrl}" alt="PDF Page"> <span class="material-symbols-rounded tool-header-icon advance">construction</span>
</div> <span class="tool-header-text" th:text="#{multiTool.header}"></span>
</div> </div>
</div> <div class="mt-action-bar d-flex flex-wrap">
</div> <div class="mt-filename">
</div>
<div class="container">
<div class="row justify-content-center">
<div class="col-md-6" style="text-align: center">
<div class="global-buttons-container d-flex align-content-center justify-content-center">
<div class="form-group">
<label for="filename-input" th:text="#{multiTool.uploadPrompts}">Filename</label> <label for="filename-input" th:text="#{multiTool.uploadPrompts}">Filename</label>
<input type="text" class="form-control" id="filename-input" th:placeholder="#{multiTool.uploadPrompts}"> <input type="text" class="form-control" id="filename-input"
th:placeholder="#{multiTool.uploadPrompts}">
</div>
<div class="mt-action-btn">
<button class="btn btn-primary" onclick="addPdfs()">
<span class="material-symbols-rounded">
add
</span>
</button>
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(-90)" disabled>
<span class="material-symbols-rounded">
rotate_left
</span>
</button>
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(90)" disabled>
<span class="material-symbols-rounded">
rotate_right
</span>
</button>
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf()" disabled>
<span class="material-symbols-rounded">
download
</span>
</button>
</div> </div>
</div> </div>
<div class="global-buttons-container"> <div class="multi-tool-container">
<button class="btn btn-primary" onclick="addPdfs()"> <div class="d-flex flex-wrap" id="pages-container-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-earmark-plus" viewBox="0 0 16 16"> <div id="pages-container">
<path d="M8 6.5a.5.5 0 0 1 .5.5v1.5H10a.5.5 0 0 1 0 1H8.5V11a.5.5 0 0 1-1 0V9.5H6a.5.5 0 0 1 0-1h1.5V7a.5.5 0 0 1 .5-.5z"/> <div class="page-container" th:each="pdf, status: ${pdfList}"
<path d="M14 4.5V14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2h5.5L14 4.5zm-3 0A1.5 1.5 0 0 1 9.5 3V1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4.5h-2z"/> th:id="'page-container-' + ${status.index}">
</svg> <div class="page-number-container">
</button> <span th:text="${status.index + 1}"></span>
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(-90)" disabled> </div>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-counterclockwise" viewBox="0 0 16 16"> <img th:src="${pdf.imageUrl}" alt="PDF Page">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 1-4.546 2.914.5.5 0 0 0-.908-.417A6 6 0 1 0 8 2v1z" /> </div>
<path d="M8 4.466V.534a.25.25 0 0 0-.41-.192L5.23 2.308a.25.25 0 0 0 0 .384l2.36 1.966A.25.25 0 0 0 8 4.466z" /> </div>
</svg> </div>
</button>
<button class="btn btn-secondary enable-on-file" onclick="rotateAll(90)" disabled>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-clockwise" viewBox="0 0 16 16">
<path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z" />
<path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z" />
</svg>
</button>
<button id="export-button" class="btn btn-primary enable-on-file" onclick="exportPdf()" disabled>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-download" viewBox="0 0 16 16">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z"/>
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708l3 3z"/>
</svg>
</button>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div id="drag-container"></div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
<div id="drag-container"></div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
<script type="module"> <script type="module">
import PdfContainer from './js/multitool/PdfContainer.js'; import PdfContainer from './js/multitool/PdfContainer.js';
import DragDropManager from "./js/multitool/DragDropManager.js"; import DragDropManager from "./js/multitool/DragDropManager.js";
import scrollDivHorizontally from "./js/multitool/horizontalScroll.js"; import scrollDivHorizontally from "./js/multitool/horizontalScroll.js";
import ImageHighlighter from "./js/multitool/ImageHighlighter.js"; import ImageHighlighter from "./js/multitool/ImageHighlighter.js";
import PdfActionsManager from './js/multitool/PdfActionsManager.js'; import PdfActionsManager from './js/multitool/PdfActionsManager.js';
import FileDragManager from './js/multitool/fileInput.js'; import FileDragManager from './js/multitool/fileInput.js';
// enables drag and drop // enables drag and drop
const dragDropManager = new DragDropManager('drag-container', 'pages-container'); const dragDropManager = new DragDropManager('drag-container', 'pages-container');
// enables image highlight on click // enables image highlight on click
const imageHighlighter = new ImageHighlighter('image-highlighter'); const imageHighlighter = new ImageHighlighter('image-highlighter');
// enables the default action buttons on each pdf // enables the default action buttons on each pdf
const pdfActionsManager = new PdfActionsManager('pages-container'); const pdfActionsManager = new PdfActionsManager('pages-container');
const fileDragManager = new FileDragManager(); const fileDragManager = new FileDragManager();
// Scroll the wrapper horizontally // Scroll the wrapper horizontally
scrollDivHorizontally('pages-container-wrapper'); scrollDivHorizontally('pages-container-wrapper');
// Automatically exposes rotateAll, addPdfs and exportPdf to the window for the global buttons. // Automatically exposes rotateAll, addPdfs and exportPdf to the window for the global buttons.
const pdfContainer = new PdfContainer( const pdfContainer = new PdfContainer(
'pages-container', 'pages-container',
'pages-container-wrapper', 'pages-container-wrapper',
[ [
dragDropManager, dragDropManager,
imageHighlighter, imageHighlighter,
pdfActionsManager, pdfActionsManager,
fileDragManager fileDragManager
] ]
) )
fileDragManager.setCallback(async (files) => pdfContainer.addPdfsFromFiles(files));
</script>
</body>
fileDragManager.setCallback(async (files) => pdfContainer.addPdfsFromFiles(files));
</script>
</body>
</html> </html>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{overlay-pdfs.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">layers</span>
<span class="tool-header-text" th:text="#{overlay-pdfs.header}"></span>
</div>
<form id="overlayForm" method="post" enctype="multipart/form-data" th:action="@{/api/v1/general/overlay-pdfs}"> <form id="overlayForm" method="post" enctype="multipart/form-data" th:action="@{/api/v1/general/overlay-pdfs}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div th:replace="~{fragments/common :: fileSelector(name='overlayFiles', multiple=true, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='overlayFiles', multiple=true, accept='application/pdf')}"></div>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pdfOrganiser.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">format_list_bulleted</span>
<span class="tool-header-text" th:text="#{pdfOrganiser.header}"></span>
</div>
<form th:action="@{api/v1/general/rearrange-pages}" method="post" enctype="multipart/form-data"> <form th:action="@{api/v1/general/rearrange-pages}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pdfToSinglePage.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">looks_one</span>
<span class="tool-header-text" th:text="#{pdfToSinglePage.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{api/v1/general/pdf-to-single-page}"> <form method="post" enctype="multipart/form-data" th:action="@{api/v1/general/pdf-to-single-page}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToSinglePage.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{pdfToSinglePage.submit}"></button>

View file

@ -1,10 +1,21 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html
th:lang="${#locale.language}"
th:dir="#{language.direction}"
th:data-language="${#locale.toString()}"
xmlns:th="http://www.thymeleaf.org"
>
<head> <head>
<th:block th:insert="~{fragments/common :: head(title=#{pipeline.title}, header=#{pipeline.header})}"></th:block> <th:block
<link rel="stylesheet" href="css/pipeline.css" th:if="${currentPage == 'pipeline'}"> th:insert="~{fragments/common :: head(title=#{pipeline.title}, header=#{pipeline.header})}"
></th:block>
<link
rel="stylesheet"
href="css/pipeline.css"
th:if="${currentPage == 'pipeline'}"
/>
<script th:inline="javascript"> <script th:inline="javascript">
const saveSettings = /*[[#{pipelineOptions.saveSettings}]]*/ ''; const saveSettings = /*[[#{pipelineOptions.saveSettings}]]*/ "";
</script> </script>
</head> </head>
@ -12,96 +23,174 @@
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br> <br /><br />
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6" id="bg-card">
<div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">family_history</span>
<span class="tool-header-text" th:text="#{pipeline.header}"></span>
</div>
<div class="text-end text-top">
<button
id="uploadPipelineBtn"
class="btn btn-primary"
th:text="#{pipeline.uploadButton}"
></button>
<button
type="button"
class="btn btn-primary"
data-bs-toggle="modal"
data-bs-target="#pipelineSettingsModal"
th:text="#{pipeline.configureButton}"
></button>
</div>
<div style="text-align: center;"> <div class="center-element">
<h1 th:text="#{pipeline.header}"></h1> <div class="element-margin">
<img src="images/pipeline.svg" alt="icon" style="filter: invert(33%) sepia(100%) saturate(5000%) hue-rotate(183deg) brightness(90%) contrast(100%); width: 100px; height: 100px;"> <select id="pipelineSelect" class="custom-select form-control">
</div> <option
value='{"name":"Custom","pipeline":[],"_examples":{"outputDir":"{outputFolder}/{folderName}","outputFileName":"{filename}-{pipelineName}-{date}-{time}"},"outputDir":"{outputFolder}","outputFileName":"{filename}"}'
<div class="bordered-box"> th:text="#{pipeline.defaultOption}"
<div class="text-end text-top"> ></option>
<button id="uploadPipelineBtn" class="btn btn-primary" th:text="#{pipeline.uploadButton}"></button> <th:block th:each="config : ${pipelineConfigsWithNames}">
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#pipelineSettingsModal" th:text="#{pipeline.configureButton}"></button> <option
th:value="${config.json}"
th:text="${config.name}"
></option>
</th:block>
</select>
</div>
<div class="element-margin">
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true)}"
></div>
</div>
<div class="element-margin">
<button
class="btn btn-primary"
id="submitConfigBtn"
th:text="#{pipeline.submitButton}"
></button>
</div>
<br/>
<a
href="https://github.com/Stirling-Tools/Stirling-PDF/blob/main/PipelineFeature.md"
target="_blank"
th:text="#{pipeline.help}"
>Pipeline Help</a
>
<br/>
<a
href="https://github.com/Stirling-Tools/Stirling-PDF/blob/main/FolderScanning.md"
target="_blank"
th:text="#{pipeline.scanHelp}"
>Folder Scanning Help</a
>
</div>
</div> </div>
<div class="center-element"> <!-- The Modal -->
<div class="element-margin"> <div class="modal" id="pipelineSettingsModal">
<select id="pipelineSelect" class="custom-select"> <div class="modal-dialog">
<option value="{&quot;name&quot;:&quot;Custom&quot;,&quot;pipeline&quot;:[],&quot;_examples&quot;:{&quot;outputDir&quot;:&quot;{outputFolder}/{folderName}&quot;,&quot;outputFileName&quot;:&quot;{filename}-{pipelineName}-{date}-{time}&quot;},&quot;outputDir&quot;:&quot;{outputFolder}&quot;,&quot;outputFileName&quot;:&quot;{filename}&quot;}" th:text="#{pipeline.defaultOption}"></option> <div class="modal-content dark-card">
<th:block th:each="config : ${pipelineConfigsWithNames}"> <!-- Modal Header -->
<option th:value="${config.json}" th:text="${config.name}"></option> <div class="modal-header">
</th:block> <h2
</select> class="modal-title"
</div> th:text="#{pipelineOptions.header}"
<div class="element-margin"> ></h2>
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=true)}"></div> <button
</div> type="button"
<div class="element-margin"> class="btn-close"
<button class="btn btn-primary" id="submitConfigBtn" th:text="#{pipeline.submitButton}"></button> data-bs-dismiss="modal"
</div> aria-label="Close">
<a href="https://github.com/Stirling-Tools/Stirling-PDF/blob/main/PipelineFeature.md" target="_blank" th:text="#{pipeline.help}">Pipeline Help</a> <span class="material-symbols-rounded">
<br> close
<a href="https://github.com/Stirling-Tools/Stirling-PDF/blob/main/FolderScanning.md" target="_blank" th:text="#{pipeline.scanHelp}">Folder Scanning Help</a> </span>
</div> </button>
</div>
<!-- The Modal -->
<div class="modal" id="pipelineSettingsModal">
<div class="modal-dialog">
<div class="modal-content dark-card">
<!-- Modal Header -->
<div class="modal-header">
<h2 class="modal-title" th:text="#{pipelineOptions.header}"></h2>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<div class="mb-3">
<label for="pipelineName" class="form-label" th:text="#{pipelineOptions.pipelineNameLabel}"></label>
<input type="text" id="pipelineName" class="form-control" th:placeholder="#{pipelineOptions.pipelineNamePrompt}">
</div> </div>
<div class="mb-3">
<label for="operationsDropdown" th:text="#{pipelineOptions.selectOperation}"></label>
<select id="operationsDropdown" class="form-select">
<!-- Options will be dynamically populated here -->
</select>
</div>
<div class="mb-3">
<button id="addOperationBtn" class="btn btn-primary" th:text="#{pipelineOptions.addOperationButton}"></button>
</div>
<h3 id="pipelineHeader" style="display: none;" th:text="#{pipelineOptions.pipelineHeader}"></h3>
<ol id="pipelineList" class="list-group"> <!-- Modal body -->
<!-- Pipeline operations will be dynamically populated here --> <div class="modal-body">
</ol> <div class="mb-3">
<div id="pipelineSettingsContent"> <label
<!-- pipelineSettings will be dynamically populated here --> for="pipelineName"
class="form-label"
th:text="#{pipelineOptions.pipelineNameLabel}"
></label>
<input
type="text"
id="pipelineName"
class="form-control"
th:placeholder="#{pipelineOptions.pipelineNamePrompt}"
/>
</div>
<div class="mb-3">
<label
for="operationsDropdown"
th:text="#{pipelineOptions.selectOperation}"
></label>
<select id="operationsDropdown" class="form-select">
<!-- Options will be dynamically populated here -->
</select>
</div>
<div class="mb-3">
<button
id="addOperationBtn"
class="btn btn-primary"
th:text="#{pipelineOptions.addOperationButton}"
></button>
</div>
<h3
id="pipelineHeader"
style="display: none"
th:text="#{pipelineOptions.pipelineHeader}"
></h3>
<ol id="pipelineList" class="list-group">
<!-- Pipeline operations will be dynamically populated here -->
</ol>
<div id="pipelineSettingsContent">
<!-- pipelineSettings will be dynamically populated here -->
</div>
</div> </div>
</div>
<!-- Modal footer --> <!-- Modal footer -->
<div class="modal-footer"> <div class="modal-footer">
<button id="saveBrowserPipelineBtn" class="btn btn-success" th:text="#{saveToBrowser}"></button> <button
<button id="savePipelineBtn" class="btn btn-success" th:text="#{pipelineOptions.saveButton}"></button> id="saveBrowserPipelineBtn"
<button id="validateButton" class="btn btn-success" th:text="#{pipelineOptions.validateButton}"></button> class="btn btn-success"
th:text="#{saveToBrowser}"
></button>
<button
id="savePipelineBtn"
class="btn btn-success"
th:text="#{pipelineOptions.saveButton}"
></button>
<button
id="validateButton"
class="btn btn-success"
th:text="#{pipelineOptions.validateButton}"
></button>
<div class="btn-group"> <div class="btn-group">
<input type="file" id="uploadPipelineInput" accept=".json" style="display: none;"> <input
type="file"
id="uploadPipelineInput"
accept=".json"
style="display: none"
/>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> <script src="js/pipeline.js"></script>\
</div> </div>
<script src="js/pipeline.js"></script>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> </body>
</html> </html>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{pageRemover.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">delete</span>
<span class="tool-header-text" th:text="#{pageRemover.header}"></span>
</div>
<form th:action="@{api/v1/general/remove-pages}" method="post" enctype="multipart/form-data"> <form th:action="@{api/v1/general/remove-pages}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{rotate.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">rotate_right</span>
<span class="tool-header-text" th:text="#{rotate.header}"></span>
</div>
<form action="#" th:action="@{api/v1/general/rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data"> <form action="#" th:action="@{api/v1/general/rotate-pdf}" th:object="${rotateForm}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>

View file

@ -11,13 +11,16 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{scalePages.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon organize">fullscreen</span>
<span class="tool-header-text" th:text="#{scalePages.header}"></span>
</div>
<form id="scalePagesFrom" th:action="@{api/v1/general/scale-pages}" method="post" enctype="multipart/form-data"> <form id="scalePagesFrom" th:action="@{api/v1/general/scale-pages}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3"> <div class="mb-3">
<label for="pageSize" th:text="#{scalePages.pageSize}"></label> <label for="pageSize" th:text="#{scalePages.pageSize}"></label>
<select id="pageSize" name="pageSize"> <select class="form-control" id="pageSize" name="pageSize">
<option value="A0">A0</option> <option value="A0">A0</option>
<option value="A1">A1</option> <option value="A1">A1</option>
<option value="A2">A2</option> <option value="A2">A2</option>
@ -31,7 +34,7 @@
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="scaleFactor" th:text="#{scalePages.scaleFactor}"></label> <label for="scaleFactor" th:text="#{scalePages.scaleFactor}"></label>
<input type="number" id="scaleFactor" name="scaleFactor" step="any" min="0" value="1"> <input class="form-control" type="number" id="scaleFactor" name="scaleFactor" step="any" min="0" value="1">
</div> </div>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{scalePages.submit}"></button> <button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{scalePages.submit}"></button>
</form> </form>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{addPassword.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">lock</span>
<span class="tool-header-text" th:text="#{addPassword.header}"></span>
</div>
<form action="api/v1/security/add-password" method="post" enctype="multipart/form-data"> <form action="api/v1/security/add-password" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label th:text="#{addPassword.selectText.1}"></label> <label th:text="#{addPassword.selectText.1}"></label>
@ -36,38 +39,38 @@
<small class="form-text text-muted" th:text="#{addPassword.selectText.4}"></small> <small class="form-text text-muted" th:text="#{addPassword.selectText.4}"></small>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{addPassword.selectText.5}"></label> <label class="mb-2" th:text="#{addPassword.selectText.5}"></label>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canAssembleDocument" name="canAssembleDocument"> <input type="checkbox" id="canAssembleDocument" name="canAssembleDocument">
<label class="form-check-label" for="canAssembleDocument" th:text="#{addPassword.selectText.6}"></label> <label for="canAssembleDocument" th:text="#{addPassword.selectText.6}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canExtractContent" name="canExtractContent"> <input type="checkbox" id="canExtractContent" name="canExtractContent">
<label class="form-check-label" for="canExtractContent" th:text="#{addPassword.selectText.7}"></label> <label for="canExtractContent" th:text="#{addPassword.selectText.7}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canExtractForAccessibility" name="canExtractForAccessibility"> <input type="checkbox" id="canExtractForAccessibility" name="canExtractForAccessibility">
<label class="form-check-label" for="canExtractForAccessibility" th:text="#{addPassword.selectText.8}"></label> <label for="canExtractForAccessibility" th:text="#{addPassword.selectText.8}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canFillInForm" name="canFillInForm"> <input type="checkbox" id="canFillInForm" name="canFillInForm">
<label class="form-check-label" for="canFillInForm" th:text="#{addPassword.selectText.9}"></label> <label for="canFillInForm" th:text="#{addPassword.selectText.9}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canModify" name="canModify"> <input type="checkbox" id="canModify" name="canModify">
<label class="form-check-label" for="canModify" th:text="#{addPassword.selectText.10}"></label> <label for="canModify" th:text="#{addPassword.selectText.10}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canModifyAnnotations" name="canModifyAnnotations"> <input type="checkbox" id="canModifyAnnotations" name="canModifyAnnotations">
<label class="form-check-label" for="canModifyAnnotations" th:text="#{addPassword.selectText.11}"></label> <label for="canModifyAnnotations" th:text="#{addPassword.selectText.11}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canPrint" name="canPrint"> <input type="checkbox" id="canPrint" name="canPrint">
<label class="form-check-label" for="canPrint" th:text="#{addPassword.selectText.12}"></label> <label for="canPrint" th:text="#{addPassword.selectText.12}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canPrintFaithful" name="canPrintFaithful"> <input type="checkbox" id="canPrintFaithful" name="canPrintFaithful">
<label class="form-check-label" for="canPrintFaithful" th:text="#{addPassword.selectText.13}"></label> <label for="canPrintFaithful" th:text="#{addPassword.selectText.13}"></label>
</div> </div>
</div> </div>
<br> <br>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{watermark.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">water_drop</span>
<span class="tool-header-text" th:text="#{watermark.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" action="api/v1/security/add-watermark"> <form method="post" enctype="multipart/form-data" action="api/v1/security/add-watermark">
<div class="mb-3"> <div class="mb-3">

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{autoRedact.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">ink_eraser</span>
<span class="tool-header-text" th:text="#{autoRedact.header}"></span>
</div>
<form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data"> <form action="api/v1/security/auto-redact" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf"> <input type="file" class="form-control" id="fileInput" name="fileInput" required accept="application/pdf">
@ -52,13 +55,13 @@
} }
</script> </script>
<div class="mb-3 form-check"> <div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="useRegex" name="useRegex"> <input type="checkbox" id="useRegex" name="useRegex">
<label class="form-check-label" for="useRegex" th:text="#{autoRedact.useRegexLabel}"></label> <label for="useRegex" th:text="#{autoRedact.useRegexLabel}"></label>
</div> </div>
<div class="mb-3 form-check"> <div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="wholeWordSearch" name="wholeWordSearch"> <input type="checkbox" id="wholeWordSearch" name="wholeWordSearch">
<label class="form-check-label" for="wholeWordSearch" th:text="#{autoRedact.wholeWordSearchLabel}"></label> <label for="wholeWordSearch" th:text="#{autoRedact.wholeWordSearchLabel}"></label>
</div> </div>
<div class="mb-3"> <div class="mb-3">
@ -67,8 +70,8 @@
</div> </div>
<div class="mb-3 form-check"> <div class="mb-3 form-check">
<input type="checkbox" class="form-check-input" id="convertPDFToImage" name="convertPDFToImage" checked> <input type="checkbox" id="convertPDFToImage" name="convertPDFToImage" checked>
<label class="form-check-label" for="convertPDFToImage" th:text="#{autoRedact.convertPDFToImageLabel}"></label> <label for="convertPDFToImage" th:text="#{autoRedact.convertPDFToImageLabel}"></label>
</div> </div>
<button type="submit" class="btn btn-primary" th:text="#{autoRedact.submitButton}"></button> <button type="submit" class="btn btn-primary" th:text="#{autoRedact.submitButton}"></button>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{certSign.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">workspace_premium</span>
<span class="tool-header-text" th:text="#{certSign.header}"></span>
</div>
<form action="api/v1/security/cert-sign" method="post" enctype="multipart/form-data"> <form action="api/v1/security/cert-sign" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label th:text="#{certSign.selectPDF}"></label> <label th:text="#{certSign.selectPDF}"></label>
@ -53,7 +56,7 @@
<label th:text="#{certSign.password}" for="password"></label> <label th:text="#{certSign.password}" for="password"></label>
<input type="password" class="form-control" id="password" name="password"> <input type="password" class="form-control" id="password" name="password">
</div> </div>
<div class="mb-3"> <div class="form-check mb-3">
<input type="checkbox" id="showSignature" name="showSignature"> <input type="checkbox" id="showSignature" name="showSignature">
<label th:text="#{certSign.showSig}" for="showSignature"></label> <label th:text="#{certSign.showSig}" for="showSignature"></label>
</div> </div>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{permissions.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">encrypted</span>
<span class="tool-header-text" th:text="#{permissions.header}"></span>
</div>
<p th:text="#{permissions.warning}"></p> <p th:text="#{permissions.warning}"></p>
<form action="api/v1/security/add-password" method="post" enctype="multipart/form-data"> <form action="api/v1/security/add-password" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
@ -20,38 +23,38 @@
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label th:text="#{permissions.selectText.2}"></label> <label class="mb-2" th:text="#{permissions.selectText.2}"></label>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canAssembleDocument" name="canAssembleDocument"> <input type="checkbox" id="canAssembleDocument" name="canAssembleDocument">
<label class="form-check-label" for="canAssembleDocument" th:text="#{permissions.selectText.3}"></label> <label for="canAssembleDocument" th:text="#{permissions.selectText.3}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canExtractContent" name="canExtractContent"> <input type="checkbox" id="canExtractContent" name="canExtractContent">
<label class="form-check-label" for="canExtractContent" th:text="#{permissions.selectText.4}"></label> <label for="canExtractContent" th:text="#{permissions.selectText.4}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canExtractForAccessibility" name="canExtractForAccessibility"> <input type="checkbox" id="canExtractForAccessibility" name="canExtractForAccessibility">
<label class="form-check-label" for="canExtractForAccessibility" th:text="#{permissions.selectText.5}"></label> <label for="canExtractForAccessibility" th:text="#{permissions.selectText.5}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canFillInForm" name="canFillInForm"> <input type="checkbox" id="canFillInForm" name="canFillInForm">
<label class="form-check-label" for="canFillInForm" th:text="#{permissions.selectText.6}"></label> <label for="canFillInForm" th:text="#{permissions.selectText.6}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canModify" name="canModify"> <input type="checkbox" id="canModify" name="canModify">
<label class="form-check-label" for="canModify" th:text="#{permissions.selectText.7}"></label> <label for="canModify" th:text="#{permissions.selectText.7}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canModifyAnnotations" name="canModifyAnnotations"> <input type="checkbox" id="canModifyAnnotations" name="canModifyAnnotations">
<label class="form-check-label" for="canModifyAnnotations" th:text="#{permissions.selectText.8}"></label> <label for="canModifyAnnotations" th:text="#{permissions.selectText.8}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canPrint" name="canPrint"> <input type="checkbox" id="canPrint" name="canPrint">
<label class="form-check-label" for="canPrint" th:text="#{permissions.selectText.9}"></label> <label for="canPrint" th:text="#{permissions.selectText.9}"></label>
</div> </div>
<div class="form-check"> <div class="form-check ms-3">
<input class="form-check-input" type="checkbox" id="canPrintFaithful" name="canPrintFaithful"> <input type="checkbox" id="canPrintFaithful" name="canPrintFaithful">
<label class="form-check-label" for="canPrintFaithful" th:text="#{permissions.selectText.10}"></label> <label for="canPrintFaithful" th:text="#{permissions.selectText.10}"></label>
</div> </div>
</div> </div>
<br> <br>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{getPdfInfo.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon other">info</span>
<span class="tool-header-text" th:text="#{getPdfInfo.header}"></span>
</div>
<form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{api/v1/security/get-info-on-pdf}"> <form id="pdfInfoForm" method="post" enctype="multipart/form-data" th:action="@{api/v1/security/get-info-on-pdf}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, remoteCall='false', accept='application/pdf')}"></div>
<br> <br>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{removePassword.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">lock_open_right</span>
<span class="tool-header-text" th:text="#{removePassword.header}"></span>
</div>
<form action="api/v1/security/remove-password" method="post" enctype="multipart/form-data"> <form action="api/v1/security/remove-password" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<label th:text="#{removePassword.selectText.1}"></label> <label th:text="#{removePassword.selectText.1}"></label>

View file

@ -11,8 +11,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{remove-watermark.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">water_drop</span>
<span class="tool-header-text" th:text="#{remove-watermark.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" action="api/v1/security/remove-watermark"> <form method="post" enctype="multipart/form-data" action="api/v1/security/remove-watermark">
<div class="mb-3"> <div class="mb-3">
<label th:text="#{remove-watermark.selectText.1}"></label> <label th:text="#{remove-watermark.selectText.1}"></label>

View file

@ -11,31 +11,34 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{sanitizePDF.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon security">sanitizer</span>
<span class="tool-header-text" th:text="#{sanitizePDF.header}"></span>
</div>
<form action="api/v1/security/sanitize-pdf" method="post" enctype="multipart/form-data"> <form action="api/v1/security/sanitize-pdf" method="post" enctype="multipart/form-data">
<div class="mb-3"> <div class="mb-3">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="removeJavaScript" name="removeJavaScript" checked> <input type="checkbox" id="removeJavaScript" name="removeJavaScript" checked>
<label class="form-check-label" for="removeJavaScript" th:text="#{sanitizePDF.selectText.1}"></label> <label for="removeJavaScript" th:text="#{sanitizePDF.selectText.1}"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="removeEmbeddedFiles" name="removeEmbeddedFiles" checked> <input type="checkbox" id="removeEmbeddedFiles" name="removeEmbeddedFiles" checked>
<label class="form-check-label" for="removeEmbeddedFiles" th:text="#{sanitizePDF.selectText.2}"></label> <label for="removeEmbeddedFiles" th:text="#{sanitizePDF.selectText.2}"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="removeMetadata" name="removeMetadata" checked> <input type="checkbox" id="removeMetadata" name="removeMetadata" checked>
<label class="form-check-label" for="removeMetadata" th:text="#{sanitizePDF.selectText.3}"></label> <label for="removeMetadata" th:text="#{sanitizePDF.selectText.3}"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="removeLinks" name="removeLinks"> <input type="checkbox" id="removeLinks" name="removeLinks">
<label class="form-check-label" for="removeLinks" th:text="#{sanitizePDF.selectText.4}"></label> <label for="removeLinks" th:text="#{sanitizePDF.selectText.4}"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="removeFonts" name="removeFonts"> <input type="checkbox" id="removeFonts" name="removeFonts">
<label class="form-check-label" for="removeFonts" th:text="#{sanitizePDF.selectText.5}"></label> <label for="removeFonts" th:text="#{sanitizePDF.selectText.5}"></label>
</div> </div>
<br> <br>
<div class="mb-3 text-center"> <div class="mb-3 text-center">

View file

@ -29,8 +29,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{sign.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon sign">signature</span>
<span class="tool-header-text" th:text="#{sign.header}"></span>
</div>
<!-- pdf selector --> <!-- pdf selector -->
<div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='pdf-upload', multiple=false, accept='application/pdf')}"></div>

View file

@ -12,8 +12,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{split-by-size-or-count.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">vertical_split</span>
<span class="tool-header-text" th:text="#{split-by-size-or-count.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{/api/v1/general/split-by-size-or-count}"> <form method="post" enctype="multipart/form-data" th:action="@{/api/v1/general/split-by-size-or-count}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<label for="splitType" th:text="#{split-by-size-or-count.type.label}">Split Type</label> <label for="splitType" th:text="#{split-by-size-or-count.type.label}">Split Type</label>

View file

@ -13,8 +13,11 @@
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h2 th:text="#{split-by-sections.header}"></h2> <div class="tool-header">
<span class="material-symbols-rounded tool-header-icon advance">grid_on</span>
<span class="tool-header-text" th:text="#{split-by-sections.header}"></span>
</div>
<form method="post" enctype="multipart/form-data" th:action="@{/api/v1/general/split-pdf-by-sections}"> <form method="post" enctype="multipart/form-data" th:action="@{/api/v1/general/split-pdf-by-sections}">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div> <div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<label for="horizontalDivisions" th:text="#{split-by-sections.horizontal.label}">Horizontal Divisions</label> <label for="horizontalDivisions" th:text="#{split-by-sections.horizontal.label}">Horizontal Divisions</label>
@ -23,8 +26,10 @@
<label for="verticalDivisions" th:text="#{split-by-sections.vertical.label}">Vertical Divisions</label> <label for="verticalDivisions" th:text="#{split-by-sections.vertical.label}">Vertical Divisions</label>
<input type="number" id="verticalDivisions" name="verticalDivisions" class="form-control" min="0" max="300" required value="1" th:placeholder="#{split-by-sections.vertical.placeholder}"> <input type="number" id="verticalDivisions" name="verticalDivisions" class="form-control" min="0" max="300" required value="1" th:placeholder="#{split-by-sections.vertical.placeholder}">
<br> <br>
<label for="merge" th:text="#{split-by-sections.merge}">merge PDFs into one</label> <div class="mb-3 form-check">
<input type="checkbox" id="merge" name="merge"> <input type="checkbox" id="merge" name="merge">
<label for="merge" th:text="#{split-by-sections.merge}">merge PDFs into one</label>
</div>
<br> <br>
<div id="pdfVisualAid" class="pdf-visual-aid"></div> <div id="pdfVisualAid" class="pdf-visual-aid"></div>
<script> <script>

View file

@ -1,42 +1,59 @@
<!DOCTYPE html> <!DOCTYPE html>
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="http://www.thymeleaf.org"> <html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
<head> xmlns:th="http://www.thymeleaf.org">
<head>
<th:block th:insert="~{fragments/common :: head(title=#{split.title}, header=#{split.header})}"></th:block> <th:block th:insert="~{fragments/common :: head(title=#{split.title}, header=#{split.header})}"></th:block>
</head> </head>
<body> <body>
<div id="page-container"> <div id="page-container">
<div id="content-wrap"> <div id="content-wrap">
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block> <th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
<br><br> <br><br>
<div class="container"> <div class="container">
<div class="row justify-content-center"> <div class="row justify-content-center">
<div class="col-md-6"> <div class="col-md-6" id="bg-card">
<h1 th:text="#{split.header}"></h1> <div class="tool-header">
<p th:text="#{split.desc.1}"></p> <span class="material-symbols-rounded tool-header-icon organize">cut</span>
<p th:text="#{split.desc.2}"></p> <span class="tool-header-text" th:text="#{split.header}"></span>
<p th:text="#{split.desc.3}"></p>
<p th:text="#{split.desc.4}"></p>
<p th:text="#{split.desc.5}"></p>
<p th:text="#{split.desc.6}"></p>
<p th:text="#{split.desc.7}"></p>
<p th:text="#{split.desc.8}"></p>
<form th:action="@{api/v1/general/split-pages}" method="post" enctype="multipart/form-data">
<div th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}"></div>
<div class="mb-3">
<label for="pageNumbers" th:text="#{split.splitPages}"></label>
<input type="text" class="form-control" id="pageNumbers" name="pageNumbers" placeholder="1,3,5-10" required>
</div>
<br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{split.submit}"></button>
</form>
</div> </div>
<form th:action="@{api/v1/general/split-pages}" method="post" enctype="multipart/form-data">
<div
th:replace="~{fragments/common :: fileSelector(name='fileInput', multiple=false, accept='application/pdf')}">
</div>
<div class="mb-3">
<label for="pageNumbers" th:text="#{split.splitPages}"></label>
<input type="text" class="form-control" id="pageNumbers" name="pageNumbers" placeholder="1,3,5-10"
required>
</div>
<p>
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
aria-expanded="false" aria-controls="info" th:text="#{info}"></a>
</p>
<div class="collapse" id="info">
<p th:text="#{split.desc.1}"></p>
<p th:text="#{split.desc.2}"></p>
<p th:text="#{split.desc.3}"></p>
<p th:text="#{split.desc.4}"></p>
<p th:text="#{split.desc.5}"></p>
<p th:text="#{split.desc.6}"></p>
<p th:text="#{split.desc.7}"></p>
<p th:text="#{split.desc.8}"></p>
</div>
<br>
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{split.submit}"></button>
</form>
</div> </div>
</div> </div>
</div> </div>
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div> </div>
</body> <th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
</div>
</body>
</html> </html>