diff --git a/src/main/java/stirling/software/SPDF/controller/api/other/AutoRenameController.java b/src/main/java/stirling/software/SPDF/controller/api/other/AutoRenameController.java index bfc7674e..66fd70a6 100644 --- a/src/main/java/stirling/software/SPDF/controller/api/other/AutoRenameController.java +++ b/src/main/java/stirling/software/SPDF/controller/api/other/AutoRenameController.java @@ -77,7 +77,7 @@ public class AutoRenameController { private static final Logger logger = LoggerFactory.getLogger(AutoRenameController.class); private static final float TITLE_FONT_SIZE_THRESHOLD = 20.0f; - private static final int LINE_LIMIT = 7; + private static final int LINE_LIMIT = 11; @PostMapping(consumes = "multipart/form-data", value = "/auto-rename") @Operation(summary = "Extract header from PDF file", description = "This endpoint accepts a PDF file and attempts to extract its title or header based on heuristics. Input:PDF Output:PDF Type:SISO") @@ -136,12 +136,25 @@ public class AutoRenameController { super.getText(doc); processLine(); // Process the last line - // Sort lines by font size in descending order and get the first one - lineInfos.sort(Comparator.comparing((LineInfo li) -> li.fontSize).reversed()); - String title = lineInfos.isEmpty() ? null : lineInfos.get(0).text; + // Merge lines with same font size + List mergedLineInfos = new ArrayList<>(); + for (int i = 0; i < lineInfos.size(); i++) { + String mergedText = lineInfos.get(i).text; + float fontSize = lineInfos.get(i).fontSize; + while (i + 1 < lineInfos.size() && lineInfos.get(i + 1).fontSize == fontSize) { + mergedText += " " + lineInfos.get(i + 1).text; + i++; + } + mergedLineInfos.add(new LineInfo(mergedText, fontSize)); + } - return title != null ? title : (useFirstTextAsFallback ? (lineInfos.isEmpty() ? null : lineInfos.get(lineInfos.size() - 1).text) : null); + // Sort lines by font size in descending order and get the first one + mergedLineInfos.sort(Comparator.comparing((LineInfo li) -> li.fontSize).reversed()); + String title = mergedLineInfos.isEmpty() ? null : mergedLineInfos.get(0).text; + + return title != null ? title : (useFirstTextAsFallback ? (mergedLineInfos.isEmpty() ? null : mergedLineInfos.get(mergedLineInfos.size() - 1).text) : null); } + }; String header = reader.getText(document); diff --git a/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java b/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java index e3c7a41b..8fa57d08 100644 --- a/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java +++ b/src/main/java/stirling/software/SPDF/controller/web/OtherWebController.java @@ -147,4 +147,6 @@ public class OtherWebController { return "other/auto-rename"; } + + } diff --git a/src/main/resources/messages_en_GB.properties b/src/main/resources/messages_en_GB.properties index f28286ba..15ff69d3 100644 --- a/src/main/resources/messages_en_GB.properties +++ b/src/main/resources/messages_en_GB.properties @@ -35,9 +35,11 @@ navbar.pageOps=Page Operations home.multiTool.title=PDF Multi Tool home.multiTool.desc=Merge, Rotate, Rearrange, and Remove pages +multiTool.tags=Multi Tool,Multi operation,UI,click drag,front end,client side home.merge.title=Merge home.merge.desc=Easily merge multiple PDFs into one. +merge.tags=merge,Page operations,Back end,server side home.split.title=Split home.split.desc=Split PDFs into multiple documents diff --git a/src/main/resources/static/css/home.css b/src/main/resources/static/css/home.css index 94414be9..998278e1 100644 --- a/src/main/resources/static/css/home.css +++ b/src/main/resources/static/css/home.css @@ -1,3 +1,17 @@ +#searchBar { + background-image: url('/images/search.svg'); + background-position: 16px 16px; + background-repeat: no-repeat; + width: 100%; + font-size: 16px; + margin-bottom: 12px; + padding: 12px 20px 12px 40px; + border: 1px solid #ddd; + + +} + + .features-container { display: grid; grid-template-columns: repeat(auto-fill, minmax(21rem, 3fr)); diff --git a/src/main/resources/static/css/navbar.css b/src/main/resources/static/css/navbar.css index 60b612c5..5bb99a5e 100644 --- a/src/main/resources/static/css/navbar.css +++ b/src/main/resources/static/css/navbar.css @@ -1,3 +1,41 @@ + + +#navbarSearch { + top: 100%; + right: 0; +} + +#searchForm { + width: 200px; /* Adjust this value as needed */ +} + +/* Style the search results to match the navbar */ +#searchResults { + max-height: 200px; /* Adjust this value as needed */ + overflow-y: auto; + width: 100%; +} + +#searchResults .dropdown-item { + display: flex; + align-items: center; + white-space: nowrap; + height: 50px; /* Fixed height */ + overflow: hidden; /* Hide overflow */ +} + +#searchResults .icon { + margin-right: 10px; +} + +#searchResults .icon-text { + display: inline; + overflow: hidden; /* Hide overflow */ + text-overflow: ellipsis; /* Add ellipsis for long text */ +} + + + .main-icon { width: 36px; height: 36px; diff --git a/src/main/resources/static/images/adjust-contrast.svg b/src/main/resources/static/images/adjust-contrast.svg new file mode 100644 index 00000000..fea76d92 --- /dev/null +++ b/src/main/resources/static/images/adjust-contrast.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/static/js/homecard.js b/src/main/resources/static/js/homecard.js index f3d3de35..fb962a12 100644 --- a/src/main/resources/static/js/homecard.js +++ b/src/main/resources/static/js/homecard.js @@ -1,3 +1,24 @@ +function filterCards() { + var input = document.getElementById('searchBar'); + var filter = input.value.toUpperCase(); + var cards = document.querySelectorAll('.feature-card'); + + for (var i = 0; i < cards.length; i++) { + var card = cards[i]; + var title = card.querySelector('h5.card-title').innerText; + var text = card.querySelector('p.card-text').innerText; + var tags = card.getAttribute('data-tags'); + var content = title + ' ' + text + ' ' + tags; + + if (content.toUpperCase().indexOf(filter) > -1) { + card.style.display = ""; + } else { + card.style.display = "none"; + } + } +} + + function toggleFavorite(element) { var img = element.querySelector('img'); var card = element.closest('.feature-card'); @@ -13,6 +34,7 @@ function toggleFavorite(element) { } reorderCards(); updateFavoritesDropdown(); + filterCards(); } function reorderCards() { @@ -45,5 +67,7 @@ function initializeCards() { }); reorderCards(); updateFavoritesDropdown(); + filterCards(); } + window.onload = initializeCards; \ No newline at end of file diff --git a/src/main/resources/static/js/search.js b/src/main/resources/static/js/search.js new file mode 100644 index 00000000..3c19ed84 --- /dev/null +++ b/src/main/resources/static/js/search.js @@ -0,0 +1,72 @@ +// Toggle search bar when the search icon is clicked +document.querySelector('#search-icon').addEventListener('click', function(e) { + e.preventDefault(); + var searchBar = document.querySelector('#navbarSearch'); + searchBar.classList.toggle('show'); +}); +window.onload = function() { + var items = document.querySelectorAll('.dropdown-item, .nav-link'); + var dummyContainer = document.createElement('div'); + dummyContainer.style.position = 'absolute'; + dummyContainer.style.visibility = 'hidden'; + dummyContainer.style.whiteSpace = 'nowrap'; // Ensure we measure full width + document.body.appendChild(dummyContainer); + + var maxWidth = 0; + + items.forEach(function(item) { + var clone = item.cloneNode(true); + dummyContainer.appendChild(clone); + var width = clone.offsetWidth; + if (width > maxWidth) { + maxWidth = width; + } + dummyContainer.removeChild(clone); + }); + + document.body.removeChild(dummyContainer); + + // Store max width for later use + window.navItemMaxWidth = maxWidth; +}; + +// Show search results as user types in search box +document.querySelector('#navbarSearchInput').addEventListener('input', function(e) { + var searchText = e.target.value.toLowerCase(); + var items = document.querySelectorAll('.dropdown-item, .nav-link'); + var resultsBox = document.querySelector('#searchResults'); + + // Clear any previous results + resultsBox.innerHTML = ''; + + items.forEach(function(item) { + var titleElement = item.querySelector('.icon-text'); + var iconElement = item.querySelector('.icon'); + var itemHref = item.getAttribute('href'); + if (titleElement && iconElement && itemHref !== '#') { + var title = titleElement.innerText.toLowerCase(); + if (title.indexOf(searchText) !== -1 && !resultsBox.querySelector(`a[href="${item.getAttribute('href')}"]`)) { + var result = document.createElement('a'); + result.href = itemHref; + result.classList.add('dropdown-item'); + + var resultIcon = document.createElement('img'); + resultIcon.src = iconElement.src; + resultIcon.alt = 'icon'; + resultIcon.classList.add('icon'); + result.appendChild(resultIcon); + + var resultText = document.createElement('span'); + resultText.textContent = title; + resultText.classList.add('icon-text'); + result.appendChild(resultText); + + resultsBox.appendChild(result); + } + } + }); + + // Set the width of the search results box to the maximum width + resultsBox.style.width = window.navItemMaxWidth + 'px'; +}); + diff --git a/src/main/resources/templates/fragments/card.html b/src/main/resources/templates/fragments/card.html index faa816a4..48142b03 100644 --- a/src/main/resources/templates/fragments/card.html +++ b/src/main/resources/templates/fragments/card.html @@ -1,4 +1,4 @@ -
+
+
diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html index 33bf6b42..145b65d1 100644 --- a/src/main/resources/templates/home.html +++ b/src/main/resources/templates/home.html @@ -20,8 +20,13 @@

-
- + + +
+ +
+ +
@@ -70,13 +75,13 @@
- +
- +
-
+
diff --git a/src/main/resources/templates/other/adjust-contrast.html b/src/main/resources/templates/other/adjust-contrast.html index 87496d4f..8250d609 100644 --- a/src/main/resources/templates/other/adjust-contrast.html +++ b/src/main/resources/templates/other/adjust-contrast.html @@ -13,15 +13,215 @@

+ + -
-
-
- - -
- -
+

Contrast: 100%

+ + +

Brightness: 100%

+ + +

Saturation: 100%

+ + + + + + + +