navbar enhancements

Signed-off-by: a <a>
This commit is contained in:
a 2024-09-21 11:59:36 +01:00
parent 6ca14edaf1
commit 28c55ca80c
6 changed files with 167 additions and 55 deletions

View File

@ -126,6 +126,7 @@ navbar.sections.convertFrom=Convert from PDF
navbar.sections.security=Sign & Security
navbar.sections.advance=Advanced
navbar.sections.edit=View & Edit
navbar.sections.popular=Popular
#############
# SETTINGS #

View File

@ -89,6 +89,14 @@
width: 80%;
}
.close-icon {
color: var(--md-sys-color-secondary);
}
.close-icon:hover {
transform: scale(1.15);
}
span.icon-text::after {
content: attr(data-text);
content: attr(data-text) / "";

View File

@ -1,45 +1,73 @@
function updateFavoritesDropdown() {
var dropdown = document.querySelector("#favoritesDropdown");
// Check if dropdown exists
if (!dropdown) {
console.error('Dropdown element with ID "favoritesDropdown" not found!');
return; // Exit the function
return;
}
dropdown.innerHTML = ""; // Clear the current favorites
dropdown.innerHTML = "";
var hasFavorites = false;
var addedFeatures = new Set();
for (var i = 0; i < localStorage.length; i++) {
var key = localStorage.key(i);
if (localStorage.getItem(key) === "favorite") {
// Find the corresponding navbar entry
var value = localStorage.getItem(key);
if (value === "favorite") {
var navbarEntry = document.querySelector(`a[href='${key}']`);
if (navbarEntry) {
// Create a new dropdown entry
var dropdownItem = document.createElement("a");
dropdownItem.className = "dropdown-item";
dropdownItem.href = navbarEntry.href;
dropdownItem.innerHTML = navbarEntry.innerHTML;
dropdown.appendChild(dropdownItem);
hasFavorites = true;
var featureName = navbarEntry.textContent.trim();
if (!addedFeatures.has(featureName)) {
var dropdownItem = document.createElement("div");
dropdownItem.className = "dropdown-item d-flex justify-content-between align-items-center";
// Create a wrapper for the original content
var contentWrapper = document.createElement("div");
contentWrapper.className = "d-flex align-items-center flex-grow-1";
contentWrapper.style.textDecoration = "none";
contentWrapper.style.color = "inherit";
// Clone the original content
var originalContent = navbarEntry.querySelector('div').cloneNode(true);
contentWrapper.appendChild(originalContent);
// Create the remove button
var removeButton = document.createElement("button");
removeButton.className = "btn btn-sm btn-link p-0 ml-2";
removeButton.innerHTML = '<i class="material-symbols-rounded close-icon" style="font-size: 18px;">close</i>';
removeButton.onclick = function(itemKey, event) {
event.preventDefault();
event.stopPropagation();
localStorage.removeItem(itemKey);
updateFavoritesSection();
updateFavoritesDropdown();
filterCards();
}.bind(null, key);
// Add click event to the content wrapper
contentWrapper.onclick = function(itemHref, event) {
event.preventDefault();
window.location.href = itemHref;
}.bind(null, navbarEntry.href);
dropdownItem.appendChild(contentWrapper);
dropdownItem.appendChild(removeButton);
dropdown.appendChild(dropdownItem);
hasFavorites = true;
addedFeatures.add(featureName);
}
} else {
console.warn(`Navbar entry not found for key: ${key}`);
}
}
}
// Show or hide the default item based on whether there are any favorites
if (!hasFavorites) {
var defaultItem = document.createElement("a");
defaultItem.className = "dropdown-item";
defaultItem.textContent = noFavourites;
defaultItem.textContent = noFavourites || "No favorites added";
dropdown.appendChild(defaultItem);
}
}
// Ensure that the DOM content has been fully loaded before calling the function
document.addEventListener("DOMContentLoaded", function () {
console.log("DOMContentLoaded event fired");
updateFavoritesDropdown();
});

View File

@ -24,28 +24,37 @@ function filterCards() {
function updateFavoritesSection() {
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
favoritesContainer.innerHTML = "";
const cards = Array.from(document.querySelectorAll(".feature-card"));
favoritesContainer.innerHTML = ""; // Clear the container first
const cards = Array.from(document.querySelectorAll(".feature-card:not(.duplicate)"));
const addedCardIds = new Set(); // To keep track of added card IDs
let favoritesAmount = 0;
cards.forEach(card => {
if (localStorage.getItem(card.id) === "favorite") {
if (localStorage.getItem(card.id) === "favorite" && !addedCardIds.has(card.id)) {
const duplicate = card.cloneNode(true);
duplicate.classList.add("duplicate");
favoritesContainer.appendChild(duplicate);
addedCardIds.add(card.id); // Mark this card as added
favoritesAmount++;
}
});
if (favoritesAmount === 0) {
document.getElementById("groupFavorites").style.display = "none";
} else {
document.getElementById("groupFavorites").style.display = "flex";
};
}
reorderCards(favoritesContainer);
};
}
function toggleFavorite(element) {
var span = element.querySelector("span.material-symbols-rounded");
var card = element.closest(".feature-card");
var cardId = card.id;
// Prevent the event from bubbling up to parent elements
event.stopPropagation();
if (span.classList.contains("no-fill")) {
span.classList.remove("no-fill");
span.classList.add("fill");
@ -57,7 +66,33 @@ function toggleFavorite(element) {
card.classList.remove("favorite");
localStorage.removeItem(cardId);
}
reorderCards(card.parentNode);
// Use setTimeout to ensure this runs after the current call stack is clear
setTimeout(() => {
reorderCards(card.parentNode);
updateFavoritesSection();
updateFavoritesDropdown();
filterCards();
}, 0);
}
function syncFavorites() {
const cards = Array.from(document.querySelectorAll(".feature-card"));
cards.forEach(card => {
const isFavorite = localStorage.getItem(card.id) === "favorite";
const starIcon = card.querySelector(".favorite-icon span.material-symbols-rounded");
if (isFavorite) {
starIcon.classList.remove("no-fill");
starIcon.classList.add("fill");
card.classList.add("favorite");
} else {
starIcon.classList.remove("fill");
starIcon.classList.add("no-fill");
card.classList.remove("favorite");
}
});
updateFavoritesSection();
updateFavoritesDropdown();
filterCards();
@ -213,5 +248,8 @@ document.addEventListener("DOMContentLoaded", function () {
}
})
showFavoritesOnly();
window.onload = function() {
initializeCards();
syncFavorites(); // Add this line to ensure everything is in sync on page load
};
});

View File

@ -15,7 +15,7 @@
</div>
</a>
<div class="favorite-icon" onclick="toggleFavorite(this)">
<span class="material-symbols-rounded no-fill">
<span class="material-symbols-rounded">
star
</span>
</div>

View File

@ -68,11 +68,39 @@
</div>
</div>
<div id="popularTools" class="feature-group">
<div
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.popular})}">
</div>
<div class="feature-group-container">
<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='organize')}">
</div>
<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='compress-pdf', cardTitle=#{home.compressPdfs.title}, cardText=#{home.compressPdfs.desc}, cardLink='compress-pdf', toolIcon='zoom_in_map', tags=#{compressPdfs.tags}, toolGroup='advance')}">
</div>
</div>
</div>
<div id="groupOrganize" class="feature-group">
<div
th:replace="~{fragments/featureGroupHeader :: featureGroupHeader(groupTitle=#{navbar.sections.organize})}">
</div>
<div class="feature-group-container">
<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='organize')}">
</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>
@ -199,6 +227,9 @@
<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>
<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>
</div>
@ -215,9 +246,7 @@
<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='change-metadata', cardTitle=#{home.changeMetadata.title}, cardText=#{home.changeMetadata.desc}, cardLink='change-metadata', toolIcon='assignment', tags=#{changeMetadata.tags}, toolGroup='other')}">
</div>
@ -227,9 +256,6 @@
<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='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='flatten', cardTitle=#{home.flatten.title}, cardText=#{home.flatten.desc}, cardLink='flatten', toolIcon='layers_clear', tags=#{flatten.tags}, toolGroup='other')}">
</div>
@ -259,15 +285,15 @@
<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='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='adjust-contrast', cardTitle=#{home.adjust-contrast.title}, cardText=#{home.adjust-contrast.desc}, cardLink='adjust-contrast', toolIcon='palette', tags=#{adjust-contrast.tags}, toolGroup='advance')}">
</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='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='repair', cardTitle=#{home.repair.title}, cardText=#{home.repair.desc}, cardLink='repair', toolIcon='build', tags=#{repair.tags}, toolGroup='advance')}">
</div>
@ -299,8 +325,7 @@
<!-- Survey Modal -->
<div class="modal fade" id="surveyModal" tabindex="-1" role="dialog" aria-labelledby="surveyModalLabel"
aria-hidden="true">
<div class="modal fade" id="surveyModal" tabindex="-1" role="dialog" aria-labelledby="surveyModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered" role="document">
<div class="modal-content">
<div class="modal-header">
@ -308,13 +333,12 @@
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p th:text="#{survey.description}">Stirling-PDF has no tracking so we want to hear from our users to improve
Stirling-PDF!</h5>
<p th:text="#{survey.changes}">Stirling-PDF has changed since the last survey! To find out more please check our blog post here:</h5>
<a href="https://stirlingpdf.info/blog/stirling-pdf-survey-results" target="_blank" th:text="#{survey.changes2}">https://stirlingpdf.info/blog/stirling-pdf-survey-results</a>
<p th:text="#{survey.changes2}">With these changes we are getting paid business support and funding</p>
<p th:text="#{survey.please}">Please consider taking our survey!</p>
<p th:text="#{survey.disabled}">Survey popup will be disabled in following updates but available at foot of
page)</p>
<a href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" target="_blank" class="btn btn-primary"
id="takeSurvey" th:text="#{survey.button}">Take Survey</a>
<p th:text="#{survey.disabled}">Survey popup will be disabled in following updates but available at foot of page)</p>
<a href="https://stirlingpdf.info/s/clwzgtfw7000gltkmwz1n212m" target="_blank" class="btn btn-primary" id="takeSurvey"th:text="#{survey.button}" >Take Survey</a>
</div>
<div class="modal-footer">
<div class="form-check mb-3">
@ -330,17 +354,34 @@
</div>
<script>
/*
document.addEventListener("DOMContentLoaded", function() {
const surveyVersion = "1.1";
const surveyVersion = "2.0";
const modal = new bootstrap.Modal(document.getElementById('surveyModal'));
const dontShowAgain = document.getElementById('dontShowAgain');
const takeSurveyButton = document.getElementById('takeSurvey');
if (localStorage.getItem('surveyVersion') !== surveyVersion || !localStorage.getItem('dontShowSurvey')) {
modal.show();
const viewThresholds = [5, 15, 30, 50, 75, 100, 150, 200];
let pageViews = parseInt(localStorage.getItem('pageViews') || '0');
pageViews++;
localStorage.setItem('pageViews', pageViews.toString());
function shouldShowSurvey() {
if (localStorage.getItem('dontShowSurvey') === 'true' || localStorage.getItem('surveyTaken') === 'true') {
return false;
}
if (localStorage.getItem('surveyVersion') !== surveyVersion) {
return true;
}
return viewThresholds.includes(pageViews);
}
if (shouldShowSurvey()) {
modal.show();
}
dontShowAgain.addEventListener('change', function() {
if (this.checked) {
@ -353,15 +394,11 @@
});
takeSurveyButton.addEventListener('click', function() {
localStorage.setItem('dontShowSurvey', 'true');
localStorage.setItem('surveyTaken', 'true');
localStorage.setItem('surveyVersion', surveyVersion);
modal.hide();
});
if (localStorage.getItem('dontShowSurvey')) {
modal.hide();
}
});*/
});
</script>