Frooodle/license (#1994)

This commit is contained in:
Anthony Stirling
2024-10-14 22:34:41 +01:00
committed by GitHub
parent ceeecc37ab
commit c85463bc18
124 changed files with 4323 additions and 501 deletions

File diff suppressed because one or more lines are too long

View File

@@ -77,7 +77,7 @@ label {
flex-direction: column;
padding: 1rem;
border-radius: 25px;
overflow-y: hidden;
overflow-y: auto;
overflow-x: auto;
min-height: 275px;
margin: 0 0 30px 0;

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) / "";
@@ -320,3 +328,26 @@ span.icon-text::after {
display: none;
}
}
.go-pro-link {
position: relative;
padding: 0.5rem 1rem;
transition: all 0.3s ease;
}
.go-pro-badge {
display: inline-block;
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
font-weight: bold;
color: #ffffff;
background-color: #007bff;
border-radius: 0.25rem;
text-transform: uppercase;
transition: all 0.3s ease;
}
.go-pro-link:hover .go-pro-badge {
background-color: #0056b3;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

View File

@@ -27,3 +27,16 @@
display: flex;
justify-content: space-around;
}
#pdf-preview-large {
margin: 0 auto;
display: block;
max-width: calc(100% - 30px);
max-height: calc(100% - 30px);
box-shadow: 0 0 4px rgba(100, 100, 100, 0.25);
transition: rotate 0.3s;
position: absolute;
top: 50%;
left: 50%;
translate: -50% -50%;
}

View File

@@ -5,6 +5,22 @@ function showErrorBanner(message, stackTrace) {
document.querySelector("#errorContainer p").textContent = message;
document.querySelector("#traceContent").textContent = stackTrace;
}
function showSessionExpiredPrompt() {
const errorContainer = document.getElementById("errorContainer");
errorContainer.style.display = "block";
document.querySelector("#errorContainer .alert-heading").textContent = sessionExpired;
document.querySelector("#errorContainer p").textContent = sessionExpired;
document.querySelector("#traceContent").textContent = "";
// Optional: Add a refresh button
const refreshButton = document.createElement("button");
refreshButton.textContent = "Refresh Page";
refreshButton.className = "btn btn-primary mt-3";
refreshButton.onclick = () => location.reload();
errorContainer.appendChild(refreshButton);
}
let firstErrorOccurred = false;
$(document).ready(function () {
@@ -79,6 +95,11 @@ async function handleSingleDownload(url, formData, isMulti = false, isZip = fals
const contentType = response.headers.get("content-type");
if (!response.ok) {
if (response.status === 401) {
// Handle 401 Unauthorized error
showSessionExpiredPrompt();
return;
}
if (contentType && contentType.includes("application/json")) {
console.error("Throwing error banner, response was not okay");
return handleJsonResponse(response);
@@ -97,7 +118,7 @@ async function handleSingleDownload(url, formData, isMulti = false, isZip = fals
}
} catch (error) {
console.error("Error in handleSingleDownload:", error);
throw error; // Re-throw the error if you want it to be handled higher up.
throw error;
}
}

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

@@ -25,29 +25,38 @@ function filterCards() {
function updateFavoritesSection() {
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
favoritesContainer.style.maxHeight = "none";
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);
favoritesContainer.style.maxHeight = favoritesContainer.scrollHeight + "px";
};
}
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");
@@ -59,7 +68,31 @@ 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();
@@ -181,7 +214,10 @@ function expandCollapseAll(expandAll) {
})
}
window.onload = initializeCards;
window.onload = function() {
initializeCards();
syncFavorites(); // Ensure everything is in sync on page load
};
document.addEventListener("DOMContentLoaded", function () {
const materialIcons = new FontFaceObserver('Material Symbols Rounded');
@@ -223,7 +259,5 @@ document.addEventListener("DOMContentLoaded", function () {
})
}, 500);
showFavoritesOnly();
});
});

View File

@@ -192,6 +192,7 @@ class PdfActionsManager {
return div;
}
}
export default PdfActionsManager;

View File

@@ -117,6 +117,7 @@ class PdfContainer {
const newAngle = lastAngle + deg;
element.style.rotate = newAngle + "deg";
}
async addPdfFile(file, nextSiblingElement) {
@@ -326,6 +327,9 @@ class PdfContainer {
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
}
}
pdfDoc.setCreator(stirlingPDFLabel);
pdfDoc.setProducer(stirlingPDFLabel);
const pdfBytes = await pdfDoc.save();
const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });

View File

@@ -1,27 +1,32 @@
const scrollDivHorizontally = (id) => {
var scrollDelta = 0; // variable to store the accumulated scroll delta
var scrollDeltaX = 0; // variable to store the accumulated horizontal scroll delta
var scrollDeltaY = 0; // variable to store the accumulated vertical scroll delta
var isScrolling = false; // variable to track if scroll is already in progress
const divToScrollHorizontally = document.getElementById(id);
const divToScroll = document.getElementById(id);
function scrollLoop() {
// Scroll the div horizontally by a fraction of the accumulated scroll delta
divToScrollHorizontally.scrollLeft += scrollDelta * 0.1;
// Scroll the div horizontally and vertically by a fraction of the accumulated scroll delta
divToScroll.scrollLeft += scrollDeltaX * 0.1;
divToScroll.scrollTop += scrollDeltaY * 0.1;
// Reduce the accumulated scroll delta by a fraction
scrollDelta *= 0.9;
scrollDeltaX *= 0.9;
scrollDeltaY *= 0.9;
// If scroll delta is still significant, continue the scroll loop
if (Math.abs(scrollDelta) > 0.1) {
if (Math.abs(scrollDeltaX) > 0.1 || Math.abs(scrollDeltaY) > 0.1) {
requestAnimationFrame(scrollLoop);
} else {
isScrolling = false; // Reset scroll in progress flag
}
}
divToScrollHorizontally.addEventListener("wheel", function (e) {
divToScroll.addEventListener("wheel", function (e) {
e.preventDefault(); // prevent default mousewheel behavior
// Accumulate the horizontal scroll delta
scrollDelta -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY;
// Accumulate the horizontal and vertical scroll delta
scrollDeltaX -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY;
scrollDeltaY -= e.deltaY || e.wheelDeltaY || -e.deltaX || -e.wheelDeltaX;
// If scroll is not already in progress, start the scroll loop
if (!isScrolling) {
@@ -31,4 +36,4 @@ const scrollDivHorizontally = (id) => {
});
};
export default scrollDivHorizontally;
export default scrollDivHorizontally;