diff --git a/templates/base.html b/templates/base.html index bcf882b..842bf0c 100644 --- a/templates/base.html +++ b/templates/base.html @@ -5,19 +5,7 @@ <head> <title>{{ title }}</title> <meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no"> <!-- CSS Reset --> -<link href="https://cdn.jsdelivr.net/npm/simple-datatables@latest/dist/style.css" rel="stylesheet" type="text/css"> - -<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css"> - - -<!-- Milligram CSS --> -<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css"> -<link - rel="stylesheet" - href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.min.css" -/> - -<script src="https://cdn.jsdelivr.net/npm/simple-datatables@latest" type="text/javascript"></script> +<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/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> @@ -261,13 +249,13 @@ background-color: white; <div class="header" id='myHeader'> <span><h2>{{ tmp }} - {{ title }} </h2></span> - <span><button style="background-color: white;color: black;border: 1px dotted black;width: 98%;margin: 1%;" onclick="goToPage('/')">Home</button></span> + <span><button class="button is-link" style="width: 98%;margin: 1%;" onclick="goToPage('/')">Home</button></span> </div> <div class="container"> <center> - <img class="lightbox-trigger" id="cover" style='height: 100px; width: auto; object-fit: contain' src="/static/sets/{{ tmp }}/cover.jpg" alt="Image"> + <img class="lightbox-trigger" id="cover" style='height: 100px; width: auto; object-fit: contain' src="/static/sets/{{ tmp }}.jpg" alt="Image"> {% block content %}{% endblock %} </div> {% block scripts %}{% endblock %} diff --git a/templates/create.html b/templates/create.html new file mode 100644 index 0000000..250702a --- /dev/null +++ b/templates/create.html @@ -0,0 +1,41 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <title></title> + <link + rel="stylesheet" + href="https://cdn.jsdelivr.net/npm/bulma@1.0.0/css/bulma.min.css"> + </head> + <body> + + <section class="section"> + <div class="container"> + <form id="createForm" action="/create" method="post"> + <div class="field"> + <label class="label" for="inputField">Input:</label> + <div class="control"> + <input class="input" type="text" id="inputField" name="inputField"> + </div> + </div> + <div class="field"> + <div class="control"> + <label class="checkbox"> + <input type="checkbox" name="addDuplicate" value="true"> + Add duplicate + </label> + </div> + </div> + <div class="field"> + <div class="control"> + <button class="button is-primary" type="submit">Submit</button> + </div> + </div> + </form> + </div> + </section> + + </body> +</html> + diff --git a/templates/index.html b/templates/index.html index da8704a..1f625ac 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,17 +1,479 @@ <!DOCTYPE html> -<html lang="en"> -<head> +<html data-theme="light"> + <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>Flask App - Insert Number</title> -</head> -<body> - <h1>Insert Number</h1> - <form action="/saveNumber" method="post"> - <label for="numberInput">Number:</label> - <input type="number" id="numberInput" name="numberInput"> - <button type="submit">Save Number</button> - </form> -</body> -</html> + <title>Set Overview</title> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/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> +body { + margin: 0; + padding: 0; + font-family: Arial, sans-serif; +} + + .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 */ + } + } + + .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 */ + } + + .button { + background-color: black; + border-color: black; + } + .button.button-clear, + .button.button-outline { + background-color: transparent; + color: black; + } + .button.button-clear { + border-color: transparent; + } + .search-container { + padding: 10px; + } + </style> + </head> + <body> + <div class="search-container"> + <input type="text" id="searchInput" onkeyup="searchFunction()" placeholder="Search..."> + </select> + <center> + <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> + <select id="themeDropdown"> + <option value="">Select Theme</option> +</select> + + <!-- 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-two-thirds" style="text-align: left;"> + <p class="is-size-5"> + <span style="font-weight: bold;" class="set_id">{{ i[0] }}</span> <span style="font-weight: bold;" class="set_name">{{ i[1] }}</span> + <span class="is-size-7">{{ i[8] }}</span> + </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[8] }}"> + <img style='height: 100%; width: 100%; object-fit: contain' src="/static/sets/{{ i[0] }}.jpg" alt="Image"> + </a> + </figure> + </div> + + <div class="column is-half" style="margin:0;padding:0;"> + <div class="is-size-7"> + <label class="checkbox" > + <input type="hidden" id="set_num" value="{{ i[0] }}"> + <input class="s_fig" id="s_fig" type="checkbox" checked /> + Minifigs Collected + </label> + <br> + <label class="checkbox" > + <input type="hidden" id="set_num" value="{{ i['set_num'] }}"> + <input class="s_check" id="s_check" type="checkbox" checked /> + Set is checked + </label> + <br> + <label class="checkbox" > + <input type="hidden" id="set_num" value="{{ i['set_num'] }}"> + <input class="s_col" id="s_col" type="checkbox" checked /> + Set is collected and boxed + </label> + <br> + <label class="checkbox" > + <input type="checkbox" class="s_com" onclick="return false;"/> Set is missing pieces + </label> + </div> + </div> + </div> + <footer class="card-footer" style=""> + <p class="card-footer-item"> + <span> + <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> + </p> + + <p class="card-footer-item"> + <span> + <a class="is-size-6" style="color: #363636;" href="/{{ i['set_num'] }}">Inventory</a> + </span> + </p> + + <p class="card-footer-item"> + <span> + <a class="is-size-6" style="color: #363636;" href="/{{ i['set_num'] }}">Instructions</a> + </span> + </p> + </footer> + </div> + </div> + + {% endfor %} + </div> + <script> + 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'); + + for (i = 0; i < gridItems.length; i++) { + txtValue = gridItems[i].textContent || gridItems[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(); + index = $(this).siblings('#index').val(); + + $.ajax({ + url: '/', + type: 'POST', + data: { + 'set_num': set_num, + 'minif': minif, + 'index': index + } + }); + }); + + $("body").on("change", "#s_check", function (event) { + scheck = $(this).prop('checked'); + set_num = $(this).siblings('#set_num').val(); + index = $(this).siblings('#index').val(); + + $.ajax({ + url: '/', + type: 'POST', + data: { + 'set_num': set_num, + 'scheck': scheck, + 'index': index + } + }); + }); + + $("body").on("change", "#s_col", function (event) { + scol = $(this).prop('checked'); + set_num = $(this).siblings('#set_num').val(); + index = $(this).siblings('#index').val(); + + $.ajax({ + url: '/', + type: 'POST', + data: { + 'set_num': set_num, + 'scol': scol, + 'index': index + } + }); + }); + + 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 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); + } + }); + + // Create options for the dropdown list + themes.forEach(function(theme) { + const option = document.createElement('option'); + option.value = theme; + option.textContent = theme; + themeDropdown.appendChild(option); + }); + + // Add event listener to filter grid items + themeDropdown.addEventListener('change', function() { + 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) { + item.style.display = 'block'; // Show the grid item + } else { + item.style.display = 'none'; // Hide the grid item + } + }); + } +}); + + + </script> + </body> +</html> diff --git a/templates/table.html b/templates/table.html new file mode 100644 index 0000000..e67d67d --- /dev/null +++ b/templates/table.html @@ -0,0 +1,237 @@ +{% extends "base.html" %} + +{% block content %} +<center><button class="hidden-desktop button is-primary" id="expand-button">Expand Columns</button></center> + + +{{ inventory_list[0][5] }} + + +<div class="center-table"> +<table id="data" class="table"> + <thead> + <tr> + <th class="fixed-width" style="width:50px;"></th> + <th style="text-align:left;margin:0px;" class="fixed-width hidden-mobile">Name</th> + <th class="hidden-mobile">Color</th> + <th style="text-align: center;">Qty</th> + <th style="text-align: center;">Missing</th> + </tr> + </thead> + <tbody> + {% for brick in inventory_list %} + <tr> + <td class="fixed-width" style="width:50px;"><img src="{{ '/static/parts/' + brick[5] + '.jpg' }}" class="lightbox-trigger" class="fixed-width" style="height: 50px; width: 50px;"></td> + <td style="text-align:left;margin:0px;" class="hidden-mobile">{{ brick[3] }}</td> + <td class="hidden-mobile">{{ brick[7] }}</td> + <td>{{ brick[8] }}</td> + <td class="centered-cell"> + <div class="inputContainer"> + {% set ns = namespace(count='') %} + <form id="number-form"> + <input type="hidden" id="set_num" value="{{ brick[0] }}"> + <input type="hidden" id="id" value="{{ brick[1] }}"> + <input type="hidden" id="part_num" value="{{ brick[2] }}"> + <input type="hidden" id="color_id" value="{{ brick[6] }}"> + <input type="hidden" id="element_id" value="{{ brick[10] }}"> + <input type="hidden" id="u_id" value="{{ brick[11] }}"> + + + <div class='inputField'> + {% for missing in missing_list %} + {% if missing[1] == brick[1] and missing[2] == brick[2] and missing[3] == brick[6] and missing[5] == brick[10] %} + {% set ns.count = missing[4] %} + {% endif %} + {% endfor %} + <input type="tel" style="text-align:center;font-size: 16px;" id="missing" value="{{ ns.count }}" pattern="\d+"> + <button class="square-button" id="bnumber-form" type="submit"> + <img src="/static/save.svg" alt="Save Icon"> + </button> + </div> + </form> + </div> + </td> + </tr> + {% endfor %} + </tbody> + </table> +</div> + +<div id="lightbox-modal"> + <div class="lightbox-wrapper"> + <span class="close">×</span> + <img class="lightbox-content" id="lightbox-image"> + <div class="text-container" id="lightbox-text"></div> + </div> +</div> + + + {% endblock %} + + + +{% block scripts %} + +<script> +// $(document).ready( function () { +// $('#data').DataTable(); +// } ); + + + + + +// document.addEventListener('DOMContentLoaded', function () { +// const myDataTable = document.getElementById('data'); + +// myDataTable.addEventListener('click', function (event) { +// const clickedRow = event.target.closest('td'); +// if (clickedRow) { +// // Remove highlighting from all rows +// const rows = myDataTable.querySelectorAll('tr'); +// rows.forEach(row => row.classList.remove('highlighted')); + +// // Add highlighting to the clicked row +// if (clickedRow.classList.contains('highlighted')) { + +// clickedRow.classList.remove('highlighted'); +// } else { +// clickedRow.classList.add('highlighted'); +// } +// } +// }); +// }); + + function goToPage(url) { + window.location.href = url; + } + + const expandButton = document.getElementById('expand-button'); +const myDataTable = document.getElementById('data'); +let isExpanded = false; + +expandButton.addEventListener('click', () => { + const hiddenColumns = myDataTable.querySelectorAll('.hidden-mobile'); + hiddenColumns.forEach(column => { + if (isExpanded) { + column.style.display = 'none'; + expandButton.textContent = 'Expand Columns'; + } else { + column.style.display = 'table-cell'; + expandButton.textContent = 'Hide Columns'; + } + }); + isExpanded = !isExpanded; +}); + +document.addEventListener('DOMContentLoaded', function () { + const lightboxTrigger = document.querySelectorAll('.lightbox-trigger'); + const lightboxModal = document.getElementById('lightbox-modal'); + const lightboxImage = document.getElementById('lightbox-image'); + const lightboxText = document.getElementById('lightbox-text'); + const closeModal = document.querySelector('.close'); + + lightboxTrigger.forEach(function (element) { + element.addEventListener('click', function () { + const imgSrc = element.getAttribute('src'); + textContent = ''; +try { + textContent = element.closest('tr').querySelector('td:nth-child(2)').textContent; // Adjust the index accordingly + lightboxText.textContent = textContent; +} catch (e) { + textContent = ''; +} + + lightboxImage.setAttribute('src', imgSrc); + lightboxModal.style.display = 'block'; + }); + }); + + closeModal.addEventListener('click', function () { + lightboxModal.style.display = 'none'; + }); + + lightboxModal.addEventListener('click', function (event) { + if (event.target === lightboxModal || event.target === lightboxImage || event.target === lightboxText) { + // Dismiss only if the clicked element is part of the content area + lightboxModal.style.display = 'none'; + } + }); + + // Dismiss the lightbox when clicking outside the content area (i.e., the background) + lightboxModal.addEventListener('click', function (event) { + if (event.target != lightboxModal) { + lightboxModal.style.display = 'none'; + } + }); +}); + + document.addEventListener('DOMContentLoaded', function () { + const numberInput = document.getElementById('missing'); + + // Add event listener to input to prevent non-numeric input + numberInput.addEventListener('input', function () { + // Remove non-numeric characters + this.value = this.value.replace(/\D/g, ''); + }); + + // Force numeric keyboard on mobile devices + numberInput.setAttribute('inputmode', 'numeric'); +}); + + +$("body").on("submit", "#number-form", function (event) { +// $('#number-form').submit(function(event) { + event.preventDefault(); + console.log($(this)[0]); + + set_num = $(this)[0][0].value; + id = $(this)[0][1].value; + part_num = $(this)[0][2].value; + color_id = $(this)[0][3].value; + element_id = $(this)[0][4].value; + u_id = $(this)[0][5].value; + missing = $(this)[0][6].value + + // console.log('set_num: ' + set_num); + // console.log('id: ' + id); + // console.log('part_num: ' + part_num); + // console.log('color_id: ' + color_id); + // console.log('element_id: ' + element_id); + // console.log('u_id: ' + u_id); + // console.log('missing: ' + missing); + + $.ajax({ + url: '/'+set_num+'/'+u_id, + type: 'POST', + data: { + 'set_num': set_num, + 'id': id, + 'part_num': part_num, + 'color_id': color_id, + 'element_id': element_id, + 'u_id': u_id, + 'missing': missing + } + + }); + + + + // part_num = request.form.get('brickpartpart_num') + // color = request.form.get('brickcolorname') + // index = request.form.get('index') + // number = request.form.get('numberInput') + // is_spare = request.form.get('is_spare') + +}); + + + + + +</script> + + +{% endblock %} +