<!DOCTYPE html> <html data-theme="light" class="has-navbar-fixed-top"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Set Overview</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <style> @media only screen and (max-width: 480px) { /* horizontal scrollbar for tables if mobile screen */ .hidden-mobile { display: none !important; } } .dropdown-menu { width: max-content; /* Remove default width */ overflow-wrap: break-word; } .dropdown.is-right .dropdown-menu { right: 0; /* Align dropdown to the right of the trigger */ left: auto; } .dropdown.is-left .dropdown-menu { left: 0; /* Align dropdown to the left of the trigger */ right: auto; } .grid-container { display: grid; /* grid-template-columns: repeat(auto-fit, minmax(10%, 23%)); /* Between 33% and 50% width */ grid-template-columns: repeat(4, 1fr); gap: 10px; padding: 10px; } .grid-item { height:auto; } .card { height: 100%; border: 1px solid #ccc; padding: 10px; box-sizing: border-box; padding-bottom:30px; /* Height of the footer */ } /* Adjust height for smaller screens */ @media (max-width: 768px) { .card { height: auto; /* Let the height adjust dynamically */ } .grid-container { grid-template-columns: 100%; /* On mobile, set width to 100% */ } .grid-item { height: auto; /* Let the height adjust dynamically */ overflow: visible; /* Allow content to overflow if necessary */ } .navbar-item { &.has-dropdown { .navbar-dropdown { display: none; } &.is-hoverable:hover { .navbar-dropdown { display: block; } } } } } .grid-item img { max-width: 100%; display: block; } .card p { margin: 0; /* Remove default margin */ } .card-footer { position:absolute; bottom:0; width:90%; height:30px; /* Height of the footer */ } .search-container { padding: 10px; } </style> </head> <body> <nav class="navbar is-dark is-fixed-top is-size-6" role="navigation" aria-label="main navigation"> <div class="navbar-brand"> <a class="navbar-item" href="/"> Home </a> <a class="navbar-item" href="/create"> Add Set </a> <a class="navbar-item hidden-mobile" href="/missing"> Missing </a> <a class="navbar-item hidden-mobile" href="/parts"> Parts </a> <a class="navbar-item hidden-mobile" href="/minifigs"> Minifigs </a> <a class="navbar-item hidden-mobile" href="/wishlist"> Wishlist </a> <a class="navbar-item hidden-mobile" href="/config"> Config </a> <a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="navMenu"> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> <span aria-hidden="true"></span> </a> </div> <div id="navMenu" class="navbar-menu"> <div class="navbar-start"> </div> <div class="navbar-end"> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link"> Show </a> <div class="navbar-dropdown"> <a class="navbar-item" id="toggleButton"> Collected and boxed </a> <a class="navbar-item" id="toggleButton2"> Checked for missing pieces </a> <a class="navbar-item" id="toggleButton3"> Complete set without missing pieces </a> <a class="navbar-item" id="toggleButton4"> Sets with missing pieces </a> <a class="navbar-item" id="toggleButton5"> Missing instructions </a> </div> </div> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link"> Select Theme </a> <div class="navbar-dropdown" id="themeDropdown"> </div> </div> <div class="navbar-item has-dropdown is-hoverable"> <a class="navbar-link"> Sort by </a> <div class="navbar-dropdown"> <a class="navbar-item" onclick="dynamicSort('set_id')"> ID </a> <a class="navbar-item" onclick="dynamicSort('set_year')"> Year </a> <a class="navbar-item" onclick="dynamicSort('set_parts')"> Parts </a> <a class="navbar-item" onclick="dynamicSort('set_theme')"> Theme </a> <a class="navbar-item" onclick="dynamicSort('set_name')"> Name </a> </div> </div> </div> </div> </nav> <div class="search-container"> <input class="input"type="text" id="searchInput" onkeyup="searchFunction()" placeholder="Search title or set number..."> <!-- <center hidden="true"> <button class="button button-outline" onclick="dynamicSort('set_id')">Sort by ID</button> <button class="button button-outline" onclick="dynamicSort('set_year')">Sort by Year</button> <button class="button button-outline" onclick="dynamicSort('set_parts')">Sort by Parts</button> <button class="button button-outline" onclick="dynamicSort('set_theme')">Sort by Theme</button> <button class="button button-outline" onclick="dynamicSort('set_name')">Sort by Name</button> <button class="button button-outline" onclick="dynamicSort('s_col')">Sort by Collected</button> <button class="button button-outline" onclick="dynamicSort('s_check')">Sort by Checked</button> </center> --> <!-- <center> <button class="button button-outline" id="toggleButton">Show Collected</button> <button class="button button-outline" id="toggleButton2">Show Checked</button> <button class="button button-outline" id="toggleButton3">Show Complete</button> </center> --> <!-- Add more buttons for other text values if needed --> </div> <div class="grid-container" id="gridContainer"> {% for i in set_list %} <div class="grid-item"> <div class="card"> <div class="columns" style=""> <div class="column is-full" style="text-align: left;"> <p class="is-size-5 searchTitle"> {% if links == 'True' %} <a style="font-weight: bold;" href="https://rebrickable.com/sets/{{ i[0] }}" target="_blank" class="has-text-dark set_id">{{ i[0] }}</a> <span style="font-weight: bold;" class="has-text-dark set_name">{{ i[1] }}</span><br> {% else %} <span style="font-weight: bold;" class="has-text-dark set_id">{{ i[0] }}</span> <span style="font-weight: bold;" class="has-text-dark set_name">{{ i[1] }}</span><br> {% endif %} <a class="is-size-7 set_theme" style="color: #363636;">{{ i[3] }}</a> <a class="is-size-7" style="color: #363636;"> (<span class='set_year'>{{ i[2] }}</span>)</a> <span></span> <a class="is-size-5" style="color: #363636;float:right;"><b>Parts:</b> {{ i[4] }}</a> </p> </div> <!--<div class="column" style="text-align: left;"> <div class="is-size-5"> <b>Parts:</b> <span class='set_parts'>{{ i[4] }}</span> </div> </div> --> </div> <div class="columns" style=""> <div class="column is-half" style=""> <figure class="image is-4by3"> <a href="/{{ i[0] }}/{{ i[11] }}"> <img style='height: 100%; width: 100%; object-fit: contain' src="/static/sets/{{ i[0] }}.jpg" alt="Image" loading="lazy"> </a> </figure> </div> <div class="column is-half" style="display: flex;align-items: center;"> <div class="is-size-7"> {% if i[0] in minifigs %} <label class="checkbox" > <input type="hidden" id="set_num" value="{{ i[0] }}"> <input type="hidden" id="u_id" value="{{ i[11] }}"> {% if i[8] == 0 %} <input class="s_fig" id="s_fig" type="checkbox" /> {% else %} <input class="s_fig" id="s_fig" type="checkbox" checked /> {% endif %} <!-- {{ i[8] }}<br> {{ i[9] }}<br> {{ i[10] }}<br> --> Minifigs Collected </label> <br> {% endif %} <label class="checkbox" > <input type="hidden" id="set_num" value="{{ i[0] }}"> <input type="hidden" id="u_id" value="{{ i[11] }}"> {% if i[9] == 0 %} <input class="s_check" id="s_check" type="checkbox" /> {% else %} <input class="s_check" id="s_check" type="checkbox" checked /> {% endif %} Set is checked </label> <br> <label class="checkbox" > <input type="hidden" id="set_num" value="{{ i[0] }}"> <input type="hidden" id="u_id" value="{{ i[11] }}"> {% if i[10] == 0 %} <input class="s_col" id="s_col" type="checkbox" /> {% else %} <input class="s_col" id="s_col" type="checkbox" checked /> {% endif %} Set is collected and boxed </label> <br> <!-- <fieldset disabled> --> <label class="checkbox" > {% if i[11] in missing_list %} <input type="checkbox" class="s_com" onclick="return false;" checked/> Set is missing pieces {% else %} <input type="checkbox" class="s_com" onclick="return false;"/> Set is missing pieces {% endif %} </label> <!-- </fieldset> --> </div> </div> </div> <footer class="card-footer" style="width:95%;"> <p class="card-footer-item"style=""> <span> <span class="is-size-7">{{ i[11] }}</span> </span> </p> {% set ns = namespace(found=false) %} {% for file in files %} {% if ns.found is sameas false and file.startswith(i[0]) %} <div class="card-footer-item dropdown"> <div class="dropdown-trigger"> <button class="is-size-6" aria-haspopup="true" aria-controls="dropdown-menu3"> <span> <a id="inst-link" class="is-size-6" style="color: #363636;">Inst.</a> </span> </button> </div> <div class="dropdown-menu" id="dropdown-menu3" role="menu"> <div class="dropdown-content" style="width:max-content;"> <!-- <a class="js-modal-trigger is-size-6" style="color: #363636;" data-id="{{ i[0] }}" data-target="modal-inst">Inst.</a> --> {% for x in files %} {% if x.startswith(i[0]) %} <a href="/files/{{ x }}" target="_blank" class="dropdown-item">{{ x }}</a> {% endif %} {% endfor %} </div> </div> </div> {% set ns.found = true %} {% endif %} {% endfor %} <p class="card-footer-item" style=""> <span> <a class="is-size-6" style="color: #363636;" href="/{{ i[0] }}/{{ i[11] }}">Inv.</a> </span> </p> </footer> </div> </div> <div class="modal" id="modal-inst"> <div class="modal-background"></div> <div class="modal-card"> <header class="modal-card-head"> <p class="modal-card-title">Instructions</p> <button class="delete" aria-label="close"></button> </header> <section class="modal-card-body"> <span> {% for file in files %} <span> <a> {{ file }} </a></span> {% if file.startswith(i[0]) %} <a class="inst is-size-6" style="color: #363636;" href="/files/{{ file }}.pdf">{{ file }}</a> {% endif %} {% endfor %} </span> </section> <footer class="modal-card-foot"> <div class="buttons"> <button class="button">Cancel</button> </div> </footer> </div> </div> {% endfor %} </div> <script> //var observer = new IntersectionObserver(function(entries, observer) { // entries.forEach(function(entry) { // if (entry.isIntersecting) { // var link = entry.target; // var pdfUrl = link.getAttribute('href'); // var xhr = new XMLHttpRequest(); // xhr.open('HEAD', pdfUrl, true); // xhr.onload = function() { // if (xhr.status !== 200) { // If PDF is not found, disable the link // link.style.pointerEvents = 'none'; // link.style.color = '#ccc'; // Optionally, change link color to indicate it's disabled // } else { // link.style.pinterEvents = 'auto'; // } // }; // xhr.send(); // observer.unobserve(link); // } // }); // }); // var links = document.querySelectorAll('.inst'); // links.forEach(function(link) { // observer.observe(link); // }); function testURL(pdfUrl,link){ var xhr = new XMLHttpRequest(); xhr.open('HEAD', pdfUrl, true); xhr.onload = function() { if (xhr.status !== 200) { // If PDF is not found, disable the link link.style.pointerEvents = 'none'; console.log('not') link.style.color = '#ccc'; // Optionally, change link color to indicate it's disabled } else { link.style.pinterEvents = 'auto'; } }; xhr.send(); } window.addEventListener('DOMContentLoaded', function() { }); function searchFunction() { var input, filter, gridContainer, gridItems, i, txtValue; input = document.getElementById('searchInput'); filter = input.value.toUpperCase(); gridContainer = document.getElementById('gridContainer'); gridItems = gridContainer.getElementsByClassName('grid-item'); searchTerm = gridContainer.getElementsByClassName('searchTitle'); for (i = 0; i < searchTerm.length; i++) { txtValue = searchTerm[i].textContent || searchTerm[i].innerText; if (txtValue.toUpperCase().indexOf(filter) > -1) { gridItems[i].style.display = ""; } else { gridItems[i].style.display = "none"; } } } function sortFunction() { var sortSelect, sortValue, gridContainer, gridItems, sortedItems, i; sortSelect = document.getElementById('sortSelect'); sortValue = sortSelect.value; gridContainer = document.getElementById('gridContainer'); gridItems = gridContainer.getElementsByClassName('grid-item'); sortedItems = Array.from(gridItems); if (sortValue === 'alphabetical') { sortedItems.sort(function(a, b) { var textA = a.textContent.trim().toUpperCase(); var textB = b.textContent.trim().toUpperCase(); if (textA < textB) { return -1; } if (textA > textB) { return 1; } return 0; }); } // Remove existing items while (gridContainer.firstChild) { gridContainer.removeChild(gridContainer.firstChild); } // Append sorted items for (i = 0; i < sortedItems.length; i++) { gridContainer.appendChild(sortedItems[i]); } } var sortOrder = 'asc'; function dynamicSort(className) { console.log(className); var gridContainer, gridItems, sortedItems, i; gridContainer = document.getElementById('gridContainer'); gridItems = gridContainer.getElementsByClassName('grid-item'); sortedItems = Array.from(gridItems); sortedItems.sort(function(a, b) { var textA = a.getElementsByClassName(className)[0].textContent.trim(); var textB = b.getElementsByClassName(className)[0].textContent.trim(); // Check if the className corresponds to a checkbox if (className == 's_col' || className == 's_check') { var checkedA = a.getElementsByClassName(className)[0].checked; var checkedB = b.getElementsByClassName(className)[0].checked; // Sort by checked checkboxes (true first, false last) return (checkedA === checkedB) ? 0 : checkedA ? -1 : 1; } // Remove digits after hyphen if present textA = textA.replace(/-\d+$/, '').trim(); textB = textB.replace(/-\d+$/, '').trim(); // If text1 is an integer, parse it as a number if (!isNaN(textA) && !isNaN(textB)) { var result = parseInt(textA) - parseInt(textB); // Toggle result based on current sort order return sortOrder === 'asc' ? result : -result; } // If text1 is not an integer, treat it as a string else { textA = textA.toUpperCase(); textB = textB.toUpperCase(); var result = textA.localeCompare(textB); // Toggle result based on current sort order return sortOrder === 'asc' ? result : -result; } }); // Reverse sort order for next click sortOrder = sortOrder === 'asc' ? 'desc' : 'asc'; // Remove existing items while (gridContainer.firstChild) { gridContainer.removeChild(gridContainer.firstChild); } // Append sorted items for (i = 0; i < sortedItems.length; i++) { gridContainer.appendChild(sortedItems[i]); } } $("body").on("change", "#s_fig", function (event) { minif = $(this).prop('checked'); set_num = $(this).siblings('#set_num').val(); u_id = $(this).siblings('#u_id').val(); $.ajax({ url: '/', type: 'POST', data: { 'set_num': set_num, 'minif': minif, 'u_id': u_id } }); }); $("body").on("change", "#s_check", function (event) { scheck = $(this).prop('checked'); set_num = $(this).siblings('#set_num').val(); u_id = $(this).siblings('#u_id').val(); $.ajax({ url: '/', type: 'POST', data: { 'set_num': set_num, 'scheck': scheck, 'u_id': u_id } }); }); $("body").on("change", "#s_col", function (event) { scol = $(this).prop('checked'); set_num = $(this).siblings('#set_num').val(); u_id = $(this).siblings('#u_id').val(); $.ajax({ url: '/', type: 'POST', data: { 'set_num': set_num, 'scol': scol, 'u_id': u_id } }); }); document.addEventListener('DOMContentLoaded', function () { const toggleButton = document.getElementById('toggleButton'); let isHidden = true; // Initially, only show checked grid items // Initialize visibility based on isHidden updateVisibility(); toggleButton.addEventListener('click', function() { // Toggle visibility and update grid items isHidden = !isHidden; updateVisibility(); }); function updateVisibility() { // Get all grid items const gridItems = document.querySelectorAll('.grid-item'); // Iterate over each grid item gridItems.forEach(function(item) { // Check if the corresponding checkbox is checked const checkbox = item.querySelector('.s_col'); if (isHidden || (checkbox && checkbox.checked)) { // Show the grid item if it's hidden or the checkbox is checked item.style.display = 'block'; } else { // Hide the grid item if the checkbox is not checked item.style.display = 'none'; } }); } }); document.addEventListener('DOMContentLoaded', function () { const toggleButton = document.getElementById('toggleButton2'); let isHidden = true; // Initially, only show checked grid items // Initialize visibility based on isHidden updateVisibility(); toggleButton.addEventListener('click', function() { // Toggle visibility and update grid items isHidden = !isHidden; updateVisibility(); }); function updateVisibility() { // Get all grid items const gridItems = document.querySelectorAll('.grid-item'); // Iterate over each grid item gridItems.forEach(function(item) { // Check if the corresponding checkbox is checked const checkbox = item.querySelector('.s_check'); if (isHidden || (checkbox && checkbox.checked)) { // Show the grid item if it's hidden or the checkbox is checked item.style.display = 'block'; } else { // Hide the grid item if the checkbox is not checked item.style.display = 'none'; } }); } }); document.addEventListener('DOMContentLoaded', function () { const toggleButton = document.getElementById('toggleButton3'); let isHidden = true; // Initially, only show checked grid items // Initialize visibility based on isHidden updateVisibility(); toggleButton.addEventListener('click', function() { // Toggle visibility and update grid items isHidden = !isHidden; updateVisibility(); }); function updateVisibility() { // Get all grid items const gridItems = document.querySelectorAll('.grid-item'); // Iterate over each grid item gridItems.forEach(function(item) { // Check if the corresponding checkbox is checked const checkbox = item.querySelector('.s_com'); if (isHidden || (checkbox && !checkbox.checked)) { // Show the grid item if it's hidden or the checkbox is checked item.style.display = 'block'; } else { // Hide the grid item if the checkbox is not checked item.style.display = 'none'; } }); } }); document.addEventListener('DOMContentLoaded', function () { const toggleButton = document.getElementById('toggleButton4'); let isHidden = true; // Initially, only show checked grid items // Initialize visibility based on isHidden updateVisibility(); toggleButton.addEventListener('click', function() { // Toggle visibility and update grid items isHidden = !isHidden; updateVisibility(); }); function updateVisibility() { // Get all grid items const gridItems = document.querySelectorAll('.grid-item'); // Iterate over each grid item gridItems.forEach(function(item) { // Check if the corresponding checkbox is checked const checkbox = item.querySelector('.s_com'); if (isHidden || (checkbox && checkbox.checked)) { // Show the grid item if it's hidden or the checkbox is checked item.style.display = 'block'; } else { // Hide the grid item if the checkbox is not checked item.style.display = 'none'; } }); } }); document.addEventListener('DOMContentLoaded', function () { const toggleButton = document.getElementById('toggleButton5'); let isHidden = true; // Initially, only show checked grid items // Initialize visibility based on isHidden updateVisibility(); toggleButton.addEventListener('click', function() { // Toggle visibility and update grid items isHidden = !isHidden; updateVisibility(); }); function updateVisibility() { // Get all grid items const gridItems = document.querySelectorAll('.grid-item'); // Iterate over each grid item gridItems.forEach(function(item) { const hasInst = item.querySelector('#inst-link'); if (isHidden || !hasInst ) { // Show the grid item if it's hidden or the checkbox is checked item.style.display = 'block'; } else { // Hide the grid item if the checkbox is not checked item.style.display = 'none'; } }); } }); function customSort(a, b) { // Function to remove leading articles function removeArticle(theme) { return theme.replace(/^(a |the )/i, ''); } // Get the themes without leading articles const themeA = removeArticle(a); const themeB = removeArticle(b); // Compare the themes without leading articles return themeA.localeCompare(themeB); } document.addEventListener('DOMContentLoaded', function () { const themeDropdown = document.getElementById('themeDropdown'); // Retrieve all unique values from the <a> elements const themes = []; const themeLinks = document.querySelectorAll('.set_theme'); themeLinks.forEach(function(link) { const themeId = link.textContent.trim(); if (!themes.includes(themeId)) { themes.push(themeId); } }); themes.sort(customSort); themes.unshift('> Show all <'); // Create options for the dropdown list themes.forEach(function(theme) { const option = document.createElement('a'); option.className = "navbar-item"; option.value = theme; option.textContent = theme; themeDropdown.appendChild(option); option.addEventListener('click', function() { filterGridItems(theme); }); }); // Add event listener to filter grid items // themeDropdown.addEventListener('click', function() { // console.log($(this)); // const selectedTheme = themeDropdown.value; // filterGridItems(selectedTheme); // }); function filterGridItems(selectedTheme) { const gridItems = document.querySelectorAll('.grid-item'); gridItems.forEach(function(item) { const themeLink = item.querySelector('.set_theme'); const themeId = themeLink.textContent.trim(); if (!selectedTheme || themeId === selectedTheme || selectedTheme == '> Show all <') { item.style.display = 'block'; // Show the grid item } else { item.style.display = 'none'; // Hide the grid item } }); } }); $(document).ready(function() { // Check for click events on the navbar burger icon $(".navbar-burger").click(function() { // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" $(".navbar-burger").toggleClass("is-active"); $(".navbar-menu").toggleClass("is-active"); }); }); $(document).ready(function() { // Check for click events on the navbar burger icon $(".navbar-item").click(function() { // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" $(".navbar-burger").removeClass("is-active"); $(".navbar-menu").removeClass("is-active"); }); }); document.addEventListener('DOMContentLoaded', () => { // Functions to open and close a modal function openModal($el) { $el.classList.add('is-active'); } function closeModal($el) { $el.classList.remove('is-active'); } function closeAllModals() { (document.querySelectorAll('.modal') || []).forEach(($modal) => { closeModal($modal); }); } // Add a click event on buttons to open a specific modal (document.querySelectorAll('.js-modal-trigger') || []).forEach(($trigger) => { const modal = $trigger.dataset.target; const $target = document.getElementById(modal); $trigger.addEventListener('click', () => { openModal($target); }); }); // Add a click event on various child elements to close the parent modal (document.querySelectorAll('.modal-background, .modal-close, .modal-card-head .delete, .modal-card-foot .button') || []).forEach(($close) => { const $target = $close.closest('.modal'); $close.addEventListener('click', () => { closeModal($target); }); }); // Add a keyboard event to close all modals document.addEventListener('keydown', (event) => { if(event.key === "Escape") { closeAllModals(); } }); }); //var dropdown = document.querySelector('.dropdown'); //dropdown.addEventListener('click', function(event) { // event.stopPropagation(); // dropdown.classList.toggle('is-active'); //}); // Get all dropdowns on the page that aren't hoverable. const dropdowns = document.querySelectorAll('.dropdown:not(.is-hoverable)'); if (dropdowns.length > 0) { // For each dropdown, add event handler to open/close on click. dropdowns.forEach(function(el) { el.addEventListener('click', function(e) { // Prevent click from propagating to document e.stopPropagation(); // Toggle the 'is-active' class, which will open or close the dropdown el.classList.toggle('is-active'); }); }); // If user clicks outside dropdown, close it. document.addEventListener('click', function(e) { closeDropdowns(); }); } /* * Close dropdowns by removing `is-active` class. */ function closeDropdowns() { dropdowns.forEach(function(el) { el.classList.remove('is-active'); }); } // Close dropdowns if ESC pressed document.addEventListener('keydown', function (event) { let e = event || window.event; if (e.key === 'Esc' || e.key === 'Escape') { closeDropdowns(); } }); </script> </body> </html>