Enhance POC dashboard with dynamic UI components
Adds comprehensive dashboard HTML with responsive design and interactive elements Implements: - Dark/light mode color variables - Responsive grid layout - Interactive booking and notification sections - Dynamic time and status tracking - Custom web components for dashboard functionality
This commit is contained in:
parent
196129b74a
commit
0fa5b60a6b
2 changed files with 1714 additions and 17 deletions
1385
wwwroot/poc-dashboard.html
Normal file
1385
wwwroot/poc-dashboard.html
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -898,6 +898,172 @@
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ADD VALUE DRAWER
|
||||||
|
========================================== */
|
||||||
|
swp-balance-info-box {
|
||||||
|
display: block;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-balance-info-box swp-current-amount {
|
||||||
|
display: block;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-balance-info-box swp-original-amount {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-new-balance-box {
|
||||||
|
display: block;
|
||||||
|
padding: 16px;
|
||||||
|
background: color-mix(in srgb, var(--color-green) 10%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-green) 30%, transparent);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-new-balance-box swp-new-amount {
|
||||||
|
display: block;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 700;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-new-balance-box swp-new-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-quick-amounts {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-quick-amount {
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-quick-amount:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-quick-amount.selected {
|
||||||
|
background: color-mix(in srgb, var(--color-teal) 10%, transparent);
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Toggle Slider (Ja/Nej) */
|
||||||
|
swp-toggle-slider {
|
||||||
|
display: inline-flex;
|
||||||
|
width: fit-content;
|
||||||
|
background: var(--color-background);
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-slider::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
width: calc(50% - 4px);
|
||||||
|
height: calc(100% - 4px);
|
||||||
|
background: color-mix(in srgb, var(--color-green) 18%, white);
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: transform 200ms ease, background 200ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-slider[data-value="no"]::before {
|
||||||
|
transform: translateX(100%);
|
||||||
|
background: color-mix(in srgb, var(--color-red) 18%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-option {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
padding: 5px 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 150ms ease;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-slider[data-value="yes"] swp-toggle-option:first-child {
|
||||||
|
color: var(--color-green);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-slider[data-value="no"] swp-toggle-option:last-child {
|
||||||
|
color: var(--color-red);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-date-extend {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-current-expiry {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-current-expiry i {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-current-expiry strong {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-date-extend input[type="date"] {
|
||||||
|
padding: 10px 12px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
transition: border-color 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-date-extend input[type="date"]:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
/* ==========================================
|
/* ==========================================
|
||||||
RESPONSIVE
|
RESPONSIVE
|
||||||
========================================== */
|
========================================== */
|
||||||
|
|
@ -948,20 +1114,12 @@
|
||||||
<swp-expiry-label>Udløbsdato</swp-expiry-label>
|
<swp-expiry-label>Udløbsdato</swp-expiry-label>
|
||||||
<swp-expiry-date>31. december 2025</swp-expiry-date>
|
<swp-expiry-date>31. december 2025</swp-expiry-date>
|
||||||
</swp-expiry-info>
|
</swp-expiry-info>
|
||||||
<swp-btn class="secondary" style="padding: 8px 12px; font-size: 12px;">
|
|
||||||
<i class="ph ph-calendar-plus"></i>
|
|
||||||
Forlæng
|
|
||||||
</swp-btn>
|
|
||||||
<swp-btn class="danger" style="padding: 8px 12px; font-size: 12px;">
|
|
||||||
<i class="ph ph-x-circle"></i>
|
|
||||||
Deaktiver
|
|
||||||
</swp-btn>
|
|
||||||
</swp-expiry-box>
|
</swp-expiry-box>
|
||||||
|
|
||||||
<swp-actions-row>
|
<swp-actions-row>
|
||||||
<swp-btn class="secondary">
|
<swp-btn class="secondary" id="openAddValueDrawer">
|
||||||
<i class="ph ph-plus-circle"></i>
|
<i class="ph ph-sliders-horizontal"></i>
|
||||||
Tilføj værdi
|
Juster
|
||||||
</swp-btn>
|
</swp-btn>
|
||||||
<swp-btn class="secondary" id="openEmailDrawer">
|
<swp-btn class="secondary" id="openEmailDrawer">
|
||||||
<i class="ph ph-envelope"></i>
|
<i class="ph ph-envelope"></i>
|
||||||
|
|
@ -997,6 +1155,15 @@
|
||||||
<swp-kv-label>Original værdi</swp-kv-label>
|
<swp-kv-label>Original værdi</swp-kv-label>
|
||||||
<swp-kv-value class="mono">500 DKK</swp-kv-value>
|
<swp-kv-value class="mono">500 DKK</swp-kv-value>
|
||||||
</swp-kv-row>
|
</swp-kv-row>
|
||||||
|
<swp-kv-row>
|
||||||
|
<swp-kv-label>Aktiv</swp-kv-label>
|
||||||
|
<swp-kv-value>
|
||||||
|
<swp-toggle-slider data-value="yes" id="activeToggle">
|
||||||
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
|
</swp-toggle-slider>
|
||||||
|
</swp-kv-value>
|
||||||
|
</swp-kv-row>
|
||||||
</swp-kv-list>
|
</swp-kv-list>
|
||||||
</swp-card>
|
</swp-card>
|
||||||
|
|
||||||
|
|
@ -1141,6 +1308,69 @@
|
||||||
</swp-drawer-footer>
|
</swp-drawer-footer>
|
||||||
</swp-drawer>
|
</swp-drawer>
|
||||||
|
|
||||||
|
<!-- Add Value Drawer -->
|
||||||
|
<swp-drawer id="addValueDrawer">
|
||||||
|
<swp-drawer-header>
|
||||||
|
<swp-drawer-title>Juster gavekort</swp-drawer-title>
|
||||||
|
<swp-drawer-close id="closeAddValueDrawer">
|
||||||
|
<i class="ph ph-x"></i>
|
||||||
|
</swp-drawer-close>
|
||||||
|
</swp-drawer-header>
|
||||||
|
|
||||||
|
<swp-drawer-content>
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Nuværende saldo</swp-form-label>
|
||||||
|
<swp-balance-info-box>
|
||||||
|
<swp-current-amount>350 DKK</swp-current-amount>
|
||||||
|
<swp-original-amount>af 500 DKK original værdi</swp-original-amount>
|
||||||
|
</swp-balance-info-box>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Beløb at tilføje</swp-form-label>
|
||||||
|
<input type="text" id="addValueAmount" class="mono" placeholder="Indtast beløb" value="100 DKK" />
|
||||||
|
<swp-quick-amounts>
|
||||||
|
<swp-quick-amount data-value="50">50 DKK</swp-quick-amount>
|
||||||
|
<swp-quick-amount data-value="100" class="selected">100 DKK</swp-quick-amount>
|
||||||
|
<swp-quick-amount data-value="200">200 DKK</swp-quick-amount>
|
||||||
|
<swp-quick-amount data-value="500">500 DKK</swp-quick-amount>
|
||||||
|
</swp-quick-amounts>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Ny saldo</swp-form-label>
|
||||||
|
<swp-new-balance-box>
|
||||||
|
<swp-new-amount id="newBalanceAmount">450 DKK</swp-new-amount>
|
||||||
|
<swp-new-label>Efter tilføjelse</swp-new-label>
|
||||||
|
</swp-new-balance-box>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Forlæng udløbsdato (valgfri)</swp-form-label>
|
||||||
|
<swp-date-extend>
|
||||||
|
<swp-current-expiry>
|
||||||
|
<i class="ph ph-calendar"></i>
|
||||||
|
<span>Nuværende: <strong>31. december 2025</strong></span>
|
||||||
|
</swp-current-expiry>
|
||||||
|
<input type="date" id="newExpiryDate" value="2026-12-31" />
|
||||||
|
</swp-date-extend>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Intern note</swp-form-label>
|
||||||
|
<textarea id="addValueNote" placeholder="Beskriv hvorfor værdi tilføjes..."></textarea>
|
||||||
|
</swp-form-field>
|
||||||
|
</swp-drawer-content>
|
||||||
|
|
||||||
|
<swp-drawer-footer>
|
||||||
|
<swp-btn class="secondary" id="cancelAddValue">Annuller</swp-btn>
|
||||||
|
<swp-btn class="primary" id="confirmAddValue">
|
||||||
|
<i class="ph ph-check"></i>
|
||||||
|
Gem ændringer
|
||||||
|
</swp-btn>
|
||||||
|
</swp-drawer-footer>
|
||||||
|
</swp-drawer>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// Elements
|
// Elements
|
||||||
const overlay = document.getElementById('overlay');
|
const overlay = document.getElementById('overlay');
|
||||||
|
|
@ -1197,7 +1427,6 @@
|
||||||
openEmailBtnAlt.addEventListener('click', openEmailDrawerFn);
|
openEmailBtnAlt.addEventListener('click', openEmailDrawerFn);
|
||||||
closeEmailBtn.addEventListener('click', closeEmailDrawerFn);
|
closeEmailBtn.addEventListener('click', closeEmailDrawerFn);
|
||||||
cancelEmailBtn.addEventListener('click', closeEmailDrawerFn);
|
cancelEmailBtn.addEventListener('click', closeEmailDrawerFn);
|
||||||
overlay.addEventListener('click', closeEmailDrawerFn);
|
|
||||||
|
|
||||||
// Real-time preview updates
|
// Real-time preview updates
|
||||||
personalMessageInput.addEventListener('input', updatePreview);
|
personalMessageInput.addEventListener('input', updatePreview);
|
||||||
|
|
@ -1209,13 +1438,96 @@
|
||||||
closeEmailDrawerFn();
|
closeEmailDrawerFn();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Close on Escape
|
|
||||||
document.addEventListener('keydown', (e) => {
|
|
||||||
if (e.key === 'Escape') closeEmailDrawerFn();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize preview
|
// Initialize preview
|
||||||
updatePreview();
|
updatePreview();
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// ADD VALUE DRAWER
|
||||||
|
// ==========================================
|
||||||
|
const addValueDrawer = document.getElementById('addValueDrawer');
|
||||||
|
const openAddValueBtn = document.getElementById('openAddValueDrawer');
|
||||||
|
const closeAddValueBtn = document.getElementById('closeAddValueDrawer');
|
||||||
|
const cancelAddValueBtn = document.getElementById('cancelAddValue');
|
||||||
|
const confirmAddValueBtn = document.getElementById('confirmAddValue');
|
||||||
|
const addValueAmountInput = document.getElementById('addValueAmount');
|
||||||
|
const newBalanceAmount = document.getElementById('newBalanceAmount');
|
||||||
|
const addValueQuickAmounts = document.querySelectorAll('#addValueDrawer swp-quick-amount');
|
||||||
|
|
||||||
|
const currentBalance = 350; // Demo value
|
||||||
|
|
||||||
|
// Open add value drawer
|
||||||
|
function openAddValueDrawerFn() {
|
||||||
|
overlay.classList.add('open');
|
||||||
|
addValueDrawer.classList.add('open');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
updateNewBalance();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close add value drawer
|
||||||
|
function closeAddValueDrawerFn() {
|
||||||
|
overlay.classList.remove('open');
|
||||||
|
addValueDrawer.classList.remove('open');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse amount from string
|
||||||
|
function parseAmount(str) {
|
||||||
|
const num = parseInt(str.replace(/[^\d]/g, ''), 10);
|
||||||
|
return isNaN(num) ? 0 : num;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update new balance calculation
|
||||||
|
function updateNewBalance() {
|
||||||
|
const addAmount = parseAmount(addValueAmountInput.value);
|
||||||
|
const newBalance = currentBalance + addAmount;
|
||||||
|
newBalanceAmount.textContent = newBalance.toLocaleString('da-DK') + ' DKK';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event listeners
|
||||||
|
openAddValueBtn.addEventListener('click', openAddValueDrawerFn);
|
||||||
|
closeAddValueBtn.addEventListener('click', closeAddValueDrawerFn);
|
||||||
|
cancelAddValueBtn.addEventListener('click', closeAddValueDrawerFn);
|
||||||
|
|
||||||
|
// Quick amount selection
|
||||||
|
addValueQuickAmounts.forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
addValueQuickAmounts.forEach(b => b.classList.remove('selected'));
|
||||||
|
btn.classList.add('selected');
|
||||||
|
const value = btn.dataset.value;
|
||||||
|
addValueAmountInput.value = Number(value).toLocaleString('da-DK') + ' DKK';
|
||||||
|
updateNewBalance();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Live update on input
|
||||||
|
addValueAmountInput.addEventListener('input', updateNewBalance);
|
||||||
|
|
||||||
|
// Confirm add value (demo)
|
||||||
|
confirmAddValueBtn.addEventListener('click', () => {
|
||||||
|
alert('Værdi tilføjet! (Demo)');
|
||||||
|
closeAddValueDrawerFn();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update overlay click to close any open drawer
|
||||||
|
overlay.addEventListener('click', () => {
|
||||||
|
closeEmailDrawerFn();
|
||||||
|
closeAddValueDrawerFn();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update Escape to close any drawer
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
closeEmailDrawerFn();
|
||||||
|
closeAddValueDrawerFn();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Toggle sliders (Ja/Nej)
|
||||||
|
document.querySelectorAll('swp-toggle-slider').forEach(slider => {
|
||||||
|
slider.addEventListener('click', () => {
|
||||||
|
slider.dataset.value = slider.dataset.value === 'yes' ? 'no' : 'yes';
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue