diff --git a/app.js b/app.js index 8df88e8..66f7e00 100644 --- a/app.js +++ b/app.js @@ -10,7 +10,8 @@ let currentBarcodeNumber = null; // DOM Elements const form = document.getElementById('stickerForm'); -const garageSelect = document.getElementById('garage'); +const garageSelectContainer = document.getElementById('garageSelect'); +const garageSelectInput = document.getElementById('garage'); const regNumberInput = document.getElementById('regNumber'); const fromDateInput = document.getElementById('fromDate'); const toDateInput = document.getElementById('toDate'); @@ -25,8 +26,9 @@ async function init() { setDefaultDates(); await loadTemplateList(); setupEventListeners(); + setupCustomSelect(); generateBarcodeNumber(); - await loadTemplate(garageSelect.value); + await loadTemplate(garageSelectInput.value); } // Load template list from index.json @@ -35,12 +37,24 @@ async function loadTemplateList() { const response = await fetch('templates/index.json'); const data = await response.json(); - garageSelect.innerHTML = ''; - data.templates.forEach(template => { - const option = document.createElement('option'); - option.value = template.id; + const optionsContainer = garageSelectContainer.querySelector('.custom-select-options'); + const valueDisplay = garageSelectContainer.querySelector('.custom-select-value'); + optionsContainer.innerHTML = ''; + + data.templates.forEach((template, index) => { + const option = document.createElement('div'); + option.className = 'custom-select-option'; + option.dataset.value = template.id; option.textContent = template.name; - garageSelect.appendChild(option); + + if (index === 0) { + option.classList.add('selected'); + valueDisplay.textContent = template.name; + valueDisplay.classList.remove('placeholder'); + garageSelectInput.value = template.id; + } + + optionsContainer.appendChild(option); }); } catch (error) { console.error('Failed to load template list:', error); @@ -170,13 +184,58 @@ function generateBarcodeNumber() { currentBarcodeNumber = Math.floor(1000000000 + Math.random() * 9000000000).toString(); } -// Setup event listeners -function setupEventListeners() { - // Template change - garageSelect.addEventListener('change', async () => { - await loadTemplate(garageSelect.value); +// Setup custom select dropdown +function setupCustomSelect() { + const trigger = garageSelectContainer.querySelector('.custom-select-trigger'); + const optionsContainer = garageSelectContainer.querySelector('.custom-select-options'); + const valueDisplay = garageSelectContainer.querySelector('.custom-select-value'); + + // Toggle dropdown on trigger click + trigger.addEventListener('click', (e) => { + e.stopPropagation(); + garageSelectContainer.classList.toggle('open'); }); + // Handle option selection + optionsContainer.addEventListener('click', async (e) => { + const option = e.target.closest('.custom-select-option'); + if (!option) return; + + // Update selected state + optionsContainer.querySelectorAll('.custom-select-option').forEach(opt => { + opt.classList.remove('selected'); + }); + option.classList.add('selected'); + + // Update display and hidden input + valueDisplay.textContent = option.textContent; + valueDisplay.classList.remove('placeholder'); + garageSelectInput.value = option.dataset.value; + + // Close dropdown + garageSelectContainer.classList.remove('open'); + + // Load the selected template + await loadTemplate(option.dataset.value); + }); + + // Close dropdown when clicking outside + document.addEventListener('click', (e) => { + if (!garageSelectContainer.contains(e.target)) { + garageSelectContainer.classList.remove('open'); + } + }); + + // Close on escape key + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape') { + garageSelectContainer.classList.remove('open'); + } + }); +} + +// Setup event listeners +function setupEventListeners() { // Real-time preview updates const updatePreview = () => renderTemplate(currentTemplateId); diff --git a/index.html b/index.html index 33556ba..379a398 100644 --- a/index.html +++ b/index.html @@ -60,12 +60,16 @@
- -
- - expand_more +
+
diff --git a/styles.css b/styles.css index fb62396..a9a21c6 100644 --- a/styles.css +++ b/styles.css @@ -390,6 +390,107 @@ body { pointer-events: none; } +/* Custom Select Dropdown */ +.custom-select { + position: relative; + width: 100%; +} + +.custom-select-trigger { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 16px; + border: 1px solid var(--md-sys-color-outline-variant); + border-radius: var(--md-sys-shape-corner-medium); + background-color: var(--md-sys-color-surface-container); + color: var(--md-sys-color-on-surface); + cursor: pointer; + transition: border-color 0.2s, box-shadow 0.2s; + font: var(--md-sys-typescale-body-large); +} + +.custom-select-trigger:hover { + border-color: var(--md-sys-color-outline); +} + +.custom-select.open .custom-select-trigger { + border-color: var(--md-sys-color-primary); + box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.15); +} + +.custom-select-value { + flex: 1; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.custom-select-value.placeholder { + color: var(--md-sys-color-outline); +} + +.custom-select-icon { + color: var(--md-sys-color-outline); + transition: transform 0.2s; +} + +.custom-select.open .custom-select-icon { + transform: rotate(180deg); +} + +.custom-select-options { + position: absolute; + top: calc(100% + 4px); + left: 0; + right: 0; + background-color: var(--md-sys-color-surface); + border: 1px solid var(--md-sys-color-outline-variant); + border-radius: var(--md-sys-shape-corner-medium); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + z-index: 100; + max-height: 240px; + overflow-y: auto; + opacity: 0; + visibility: hidden; + transform: translateY(-8px); + transition: opacity 0.2s, transform 0.2s, visibility 0.2s; +} + +.custom-select.open .custom-select-options { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.custom-select-option { + padding: 12px 16px; + cursor: pointer; + transition: background-color 0.15s; + font: var(--md-sys-typescale-body-large); +} + +.custom-select-option:hover { + background-color: var(--md-sys-color-surface-variant); +} + +.custom-select-option.selected { + background-color: var(--md-sys-color-primary); + color: var(--md-sys-color-on-primary); +} + +.custom-select-option:first-child { + border-radius: var(--md-sys-shape-corner-medium) var(--md-sys-shape-corner-medium) 0 0; +} + +.custom-select-option:last-child { + border-radius: 0 0 var(--md-sys-shape-corner-medium) var(--md-sys-shape-corner-medium); +} + +.custom-select-option:only-child { + border-radius: var(--md-sys-shape-corner-medium); +} + /* Form Row */ .form-row { display: grid;