Applies JetBrains Mono font across key components Updates color scheme to use consistent teal palette Adjusts font sizes and weights for improved readability Enhances visual design tokens and styling for drawer components
1036 lines
30 KiB
HTML
1036 lines
30 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="da">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Detail Drawer POC</title>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
/* Import design tokens fra calendar-base.css */
|
|
:root {
|
|
--hour-height: 64px;
|
|
--time-axis-width: 60px;
|
|
--header-height: 70px;
|
|
|
|
/* Colors - UI */
|
|
--color-border: #e0e0e0;
|
|
--color-surface: #fff;
|
|
--color-background: #f5f5f5;
|
|
--color-background-hover: #f0f0f0;
|
|
--color-background-alt: #fafafa;
|
|
--color-text: #333333;
|
|
--color-text-secondary: #666;
|
|
--color-primary: #1976d2;
|
|
|
|
/* Named color palette */
|
|
--b-color-blue: #1e88e5;
|
|
--b-color-green: #43a047;
|
|
--b-color-red: #e53935;
|
|
--b-color-amber: #ffb300;
|
|
--b-color-purple: #8e24aa;
|
|
--b-color-teal: #00897b;
|
|
--b-mix: #fff;
|
|
|
|
/* Checkout style tokens */
|
|
--color-teal: #00897b;
|
|
--font-mono: 'JetBrains Mono', monospace;
|
|
|
|
/* Shadows */
|
|
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
|
|
/* Transitions */
|
|
--transition-fast: 150ms ease;
|
|
}
|
|
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
|
|
body {
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
background: var(--color-background);
|
|
}
|
|
|
|
/* Demo layout */
|
|
.demo-container {
|
|
padding: 16px;
|
|
}
|
|
|
|
.demo-buttons {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-bottom: 16px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.demo-btn {
|
|
padding: 6px 12px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
background: var(--color-surface);
|
|
font-size: 12px;
|
|
transition: background var(--transition-fast);
|
|
}
|
|
|
|
.demo-btn:hover {
|
|
background: var(--color-background-hover);
|
|
}
|
|
|
|
.demo-btn-primary {
|
|
background: var(--color-primary);
|
|
color: white;
|
|
border-color: var(--color-primary);
|
|
}
|
|
|
|
.demo-btn-primary:hover {
|
|
background: #1565c0;
|
|
}
|
|
|
|
/* Calendar mock */
|
|
.calendar-mock {
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 4px;
|
|
height: 500px;
|
|
display: grid;
|
|
grid-template-columns: repeat(5, 1fr);
|
|
}
|
|
|
|
.calendar-mock-column {
|
|
border-right: 1px solid var(--color-border);
|
|
padding: 8px;
|
|
}
|
|
|
|
.calendar-mock-column:last-child {
|
|
border-right: none;
|
|
}
|
|
|
|
.mock-event {
|
|
--b-primary: var(--b-color-blue);
|
|
background-color: color-mix(in srgb, var(--b-primary) 10%, var(--b-mix));
|
|
border-left: 4px solid var(--b-primary);
|
|
padding: 4px 6px;
|
|
margin-bottom: 8px;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
font-size: 12px;
|
|
transition: background-color 200ms ease;
|
|
}
|
|
|
|
.mock-event:hover {
|
|
background-color: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
}
|
|
|
|
.mock-event-time {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.mock-event-title {
|
|
font-size: 0.875rem;
|
|
}
|
|
|
|
/* ==========================================
|
|
DETAIL DRAWER
|
|
========================================== */
|
|
|
|
swp-detail-drawer-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.2);
|
|
opacity: 0;
|
|
visibility: hidden;
|
|
transition: opacity 200ms ease, visibility 200ms ease;
|
|
z-index: 1000;
|
|
}
|
|
|
|
swp-detail-drawer-overlay.open {
|
|
opacity: 1;
|
|
visibility: visible;
|
|
}
|
|
|
|
swp-detail-drawer {
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
width: 340px;
|
|
background: var(--color-surface);
|
|
border-left: 1px solid var(--color-border);
|
|
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
|
|
transform: translateX(100%);
|
|
transition: transform 200ms ease;
|
|
display: flex;
|
|
flex-direction: column;
|
|
z-index: 1001;
|
|
}
|
|
|
|
swp-detail-drawer.open {
|
|
transform: translateX(0);
|
|
}
|
|
|
|
/* Drawer header */
|
|
swp-drawer-header {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
padding: 0;
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-drawer-title {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: 14px 16px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
background: var(--color-background);
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
swp-drawer-title.source-web {
|
|
--b-primary: var(--b-color-blue);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
|
|
swp-drawer-title.source-recurring {
|
|
--b-primary: var(--b-color-purple);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
|
|
swp-drawer-title.source-manual {
|
|
--b-primary: var(--b-color-teal);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
|
|
swp-created-date {
|
|
font-size: 10px;
|
|
color: var(--color-text-secondary);
|
|
opacity: 0.8;
|
|
padding: 4px 16px 8px;
|
|
text-align: right;
|
|
background: var(--color-background-alt);
|
|
}
|
|
|
|
/* Drawer content */
|
|
swp-drawer-content {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
padding: 16px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 16px;
|
|
}
|
|
|
|
/* Section styling */
|
|
swp-drawer-section {
|
|
display: block;
|
|
}
|
|
|
|
swp-section-label {
|
|
display: block;
|
|
font-size: 11px;
|
|
font-weight: 400;
|
|
color: var(--color-text-secondary);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
/* Event time/date */
|
|
swp-event-info {
|
|
display: block;
|
|
padding-bottom: 16px;
|
|
border-bottom: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-event-time-display {
|
|
display: block;
|
|
font-size: 20px;
|
|
font-weight: 500;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
swp-event-date-display {
|
|
display: block;
|
|
font-size: 14px;
|
|
color: var(--color-text-secondary);
|
|
margin-top: 2px;
|
|
}
|
|
|
|
/* Customer section */
|
|
swp-customer-info {
|
|
display: block;
|
|
}
|
|
|
|
swp-customer-name {
|
|
display: block;
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
color: var(--color-text);
|
|
margin-bottom: 6px;
|
|
}
|
|
|
|
swp-customer-contact {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
swp-contact-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
font-size: 14px;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
swp-contact-item a {
|
|
color: var(--color-teal);
|
|
text-decoration: none;
|
|
}
|
|
|
|
swp-contact-item a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
/* Status */
|
|
swp-status-row {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 10px 12px;
|
|
background: var(--color-background-alt);
|
|
border-radius: 4px;
|
|
border: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-status-label {
|
|
font-size: 14px;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
swp-status-dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
border-radius: 50%;
|
|
}
|
|
|
|
/* Status variants - using color-mix like events */
|
|
.status-badge.status-created {
|
|
--b-primary: var(--b-color-purple);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
.status-badge.status-created swp-status-dot { background: var(--b-color-purple); }
|
|
|
|
.status-badge.status-arrived {
|
|
--b-primary: var(--b-color-green);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
.status-badge.status-arrived swp-status-dot { background: var(--b-color-green); }
|
|
|
|
.status-badge.status-paid {
|
|
--b-primary: var(--b-color-blue);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
.status-badge.status-paid swp-status-dot { background: var(--b-color-blue); }
|
|
|
|
.status-badge.status-noshow {
|
|
--b-primary: var(--b-color-red);
|
|
background: color-mix(in srgb, var(--b-primary) 15%, var(--b-mix));
|
|
color: var(--b-primary);
|
|
}
|
|
.status-badge.status-noshow swp-status-dot { background: var(--b-color-red); }
|
|
|
|
.status-badge.status-cancelled {
|
|
background: var(--color-background-alt);
|
|
color: var(--color-text-secondary);
|
|
border: 1px solid var(--color-border);
|
|
}
|
|
.status-badge.status-cancelled swp-status-dot { background: var(--color-text-secondary); }
|
|
|
|
/* Services list */
|
|
swp-services-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
}
|
|
|
|
swp-service-item {
|
|
--b-primary: var(--b-color-blue);
|
|
display: block;
|
|
padding: 10px 12px;
|
|
background: color-mix(in srgb, var(--b-primary) 5%, var(--b-mix));
|
|
border-left: 3px solid var(--b-primary);
|
|
border-radius: 3px;
|
|
}
|
|
|
|
swp-service-name {
|
|
display: block;
|
|
font-size: 15px;
|
|
font-weight: 500;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
swp-service-details {
|
|
display: block;
|
|
font-size: 13px;
|
|
color: var(--color-text-secondary);
|
|
margin-top: 2px;
|
|
}
|
|
|
|
swp-service-price {
|
|
font-family: var(--font-mono);
|
|
font-weight: 500;
|
|
}
|
|
|
|
swp-service-resource {
|
|
display: block;
|
|
font-size: 13px;
|
|
color: var(--color-text-secondary);
|
|
margin-top: 4px;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
/* Total */
|
|
swp-total-row {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 12px;
|
|
background: var(--color-text);
|
|
color: var(--color-surface);
|
|
border-radius: 4px;
|
|
}
|
|
|
|
swp-total-label {
|
|
font-size: 14px;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
swp-total-amount {
|
|
font-family: var(--font-mono);
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Notes */
|
|
swp-notes-box {
|
|
display: block;
|
|
padding: 10px 12px;
|
|
background: color-mix(in srgb, var(--b-color-amber) 10%, var(--b-mix));
|
|
border-left: 3px solid var(--b-color-amber);
|
|
border-radius: 3px;
|
|
font-size: 14px;
|
|
color: var(--color-text);
|
|
font-style: italic;
|
|
}
|
|
|
|
/* Journal link */
|
|
swp-journal-link {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 12px;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: all var(--transition-fast);
|
|
}
|
|
|
|
swp-journal-link:hover {
|
|
background: var(--color-background-hover);
|
|
border-color: var(--color-teal);
|
|
}
|
|
|
|
swp-journal-icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
swp-journal-icon img {
|
|
width: 20px;
|
|
height: 20px;
|
|
filter: invert(22%) sepia(14%) saturate(1042%) hue-rotate(164deg) brightness(102%) contrast(85%);
|
|
transition: filter 150ms ease;
|
|
}
|
|
|
|
swp-journal-link:hover swp-journal-icon img {
|
|
filter: invert(32%) sepia(98%) saturate(1234%) hue-rotate(196deg) brightness(93%) contrast(92%);
|
|
}
|
|
|
|
swp-journal-link.no-journal swp-journal-icon img {
|
|
filter: invert(45%) sepia(8%) saturate(0%) hue-rotate(0deg) brightness(95%) contrast(90%);
|
|
}
|
|
|
|
swp-journal-link.no-journal:hover swp-journal-icon img {
|
|
filter: invert(32%) sepia(98%) saturate(1234%) hue-rotate(196deg) brightness(93%) contrast(92%);
|
|
}
|
|
|
|
swp-journal-text {
|
|
flex: 1;
|
|
font-size: 14px;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
swp-journal-arrow {
|
|
font-size: 14px;
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
/* Journal not created state */
|
|
swp-journal-link.no-journal {
|
|
border-style: dashed;
|
|
background: var(--color-background-alt);
|
|
}
|
|
|
|
swp-journal-link.no-journal swp-journal-text {
|
|
color: var(--color-text-secondary);
|
|
}
|
|
|
|
swp-journal-link.no-journal:hover {
|
|
background: var(--color-surface);
|
|
border-color: var(--color-teal);
|
|
border-style: solid;
|
|
}
|
|
|
|
/* Customer stats */
|
|
swp-stats-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 8px;
|
|
}
|
|
|
|
swp-stat-item {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding: 10px 12px;
|
|
background: var(--color-background-alt);
|
|
border-radius: 4px;
|
|
border: 1px solid var(--color-border);
|
|
}
|
|
|
|
swp-stat-value {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
swp-stat-value.mono {
|
|
font-family: var(--font-mono);
|
|
}
|
|
|
|
swp-stat-label {
|
|
font-size: 11px;
|
|
color: var(--color-text-secondary);
|
|
margin-top: 2px;
|
|
}
|
|
|
|
/* Drawer footer */
|
|
swp-drawer-footer {
|
|
display: flex;
|
|
gap: 8px;
|
|
padding: 16px;
|
|
border-top: 1px solid var(--color-border);
|
|
background: var(--color-surface);
|
|
}
|
|
|
|
swp-footer-btn {
|
|
flex: 1;
|
|
padding: 12px 16px;
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all var(--transition-fast);
|
|
text-align: center;
|
|
}
|
|
|
|
swp-footer-btn.btn-primary {
|
|
background: var(--color-teal);
|
|
color: white;
|
|
border-color: var(--color-teal);
|
|
}
|
|
|
|
swp-footer-btn.btn-primary:hover {
|
|
background: #00796b;
|
|
}
|
|
|
|
swp-footer-btn.btn-secondary {
|
|
background: var(--color-surface);
|
|
color: var(--color-text);
|
|
}
|
|
|
|
swp-footer-btn.btn-secondary:hover {
|
|
background: var(--color-background-hover);
|
|
}
|
|
|
|
/* Footer states based on booking status */
|
|
swp-drawer-footer.status-paid swp-footer-btn.btn-primary {
|
|
background: var(--color-teal);
|
|
border-color: var(--color-teal);
|
|
opacity: 0.7;
|
|
cursor: default;
|
|
}
|
|
|
|
swp-drawer-footer.status-cancelled swp-footer-btn.btn-primary,
|
|
swp-drawer-footer.status-noshow swp-footer-btn.btn-primary {
|
|
background: var(--color-text-secondary);
|
|
border-color: var(--color-text-secondary);
|
|
cursor: not-allowed;
|
|
opacity: 0.6;
|
|
}
|
|
|
|
/* ==========================================
|
|
STATUS DROPDOWN (Popover API)
|
|
========================================== */
|
|
|
|
swp-status-row {
|
|
position: relative;
|
|
anchor-name: --status-row;
|
|
}
|
|
|
|
.status-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 3px 8px;
|
|
border: none;
|
|
border-radius: 3px;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
font-family: inherit;
|
|
cursor: pointer;
|
|
transition: transform var(--transition-fast);
|
|
}
|
|
|
|
.status-badge:hover {
|
|
transform: scale(1.02);
|
|
}
|
|
|
|
#statusText {
|
|
margin-top: -2px;
|
|
}
|
|
|
|
swp-status-dropdown {
|
|
margin: 0;
|
|
padding: 4px;
|
|
background: var(--color-surface);
|
|
border: 1px solid var(--color-border);
|
|
border-radius: 4px;
|
|
box-shadow: var(--shadow-md);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
|
|
/* Animation */
|
|
opacity: 0;
|
|
transform: translateY(-8px);
|
|
transition: opacity 150ms ease, transform 150ms ease, display 150ms ease allow-discrete;
|
|
}
|
|
|
|
swp-status-dropdown:popover-open {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
@starting-style {
|
|
swp-status-dropdown:popover-open {
|
|
opacity: 0;
|
|
transform: translateY(-8px);
|
|
}
|
|
}
|
|
|
|
swp-status-option {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
padding: 6px 10px;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
opacity: 0;
|
|
transform: translateX(10px);
|
|
transition: background var(--transition-fast), opacity 150ms ease, transform 150ms ease;
|
|
}
|
|
|
|
swp-status-dropdown:popover-open swp-status-option {
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
|
|
/* Stagger animation delays */
|
|
swp-status-dropdown:popover-open swp-status-option:nth-child(1) { transition-delay: 0ms; }
|
|
swp-status-dropdown:popover-open swp-status-option:nth-child(2) { transition-delay: 30ms; }
|
|
swp-status-dropdown:popover-open swp-status-option:nth-child(3) { transition-delay: 60ms; }
|
|
swp-status-dropdown:popover-open swp-status-option:nth-child(4) { transition-delay: 90ms; }
|
|
swp-status-dropdown:popover-open swp-status-option:nth-child(5) { transition-delay: 120ms; }
|
|
|
|
swp-status-option:hover {
|
|
background: var(--color-background-hover);
|
|
}
|
|
|
|
swp-status-option swp-status-dot {
|
|
width: 8px;
|
|
height: 8px;
|
|
}
|
|
|
|
swp-status-option swp-status-check {
|
|
margin-left: auto;
|
|
font-size: 12px;
|
|
opacity: 0;
|
|
}
|
|
|
|
swp-status-option.selected swp-status-check {
|
|
opacity: 1;
|
|
}
|
|
|
|
/* Status option colors */
|
|
swp-status-option.opt-created { color: var(--b-color-purple); }
|
|
swp-status-option.opt-created swp-status-dot { background: var(--b-color-purple); }
|
|
|
|
swp-status-option.opt-arrived { color: var(--b-color-green); }
|
|
swp-status-option.opt-arrived swp-status-dot { background: var(--b-color-green); }
|
|
|
|
swp-status-option.opt-paid { color: var(--b-color-blue); }
|
|
swp-status-option.opt-paid swp-status-dot { background: var(--b-color-blue); }
|
|
|
|
swp-status-option.opt-noshow { color: var(--b-color-red); }
|
|
swp-status-option.opt-noshow swp-status-dot { background: var(--b-color-red); }
|
|
|
|
swp-status-option.opt-cancelled { color: var(--color-text-secondary); }
|
|
swp-status-option.opt-cancelled swp-status-dot { background: var(--color-text-secondary); }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="demo-container">
|
|
<p style="font-size: 12px; color: var(--color-text-secondary); margin-bottom: 12px;">
|
|
Dobbeltklik på en event eller brug knapperne
|
|
</p>
|
|
|
|
<div class="demo-buttons">
|
|
<button class="demo-btn demo-btn-primary" onclick="openDrawer('arrived', 'web', true)">Online + journal</button>
|
|
<button class="demo-btn" onclick="openDrawer('created', 'manual', false)">Manuel</button>
|
|
<button class="demo-btn" onclick="openDrawer('paid', 'recurring', true)">Recurring</button>
|
|
<button class="demo-btn" onclick="openDrawer('noshow', 'web', false)">No-show</button>
|
|
<button class="demo-btn" onclick="openDrawer('cancelled', 'manual', true)">Cancelled</button>
|
|
</div>
|
|
|
|
<div class="calendar-mock">
|
|
<div class="calendar-mock-column">
|
|
<div class="mock-event" ondblclick="openDrawer('arrived')">
|
|
<div class="mock-event-time">10:00 - 11:00</div>
|
|
<div class="mock-event-title">Sofie Nielsen</div>
|
|
</div>
|
|
<div class="mock-event" ondblclick="openDrawer('created')">
|
|
<div class="mock-event-time">14:00 - 15:30</div>
|
|
<div class="mock-event-title">Lars Pedersen</div>
|
|
</div>
|
|
</div>
|
|
<div class="calendar-mock-column">
|
|
<div class="mock-event" ondblclick="openDrawer('paid')">
|
|
<div class="mock-event-time">09:00 - 10:00</div>
|
|
<div class="mock-event-title">Marie Hansen</div>
|
|
</div>
|
|
</div>
|
|
<div class="calendar-mock-column">
|
|
<div class="mock-event" ondblclick="openDrawer('noshow')">
|
|
<div class="mock-event-time">11:00 - 12:00</div>
|
|
<div class="mock-event-title">Peter Jensen</div>
|
|
</div>
|
|
</div>
|
|
<div class="calendar-mock-column"></div>
|
|
<div class="calendar-mock-column"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Overlay -->
|
|
<swp-detail-drawer-overlay id="drawerOverlay" onclick="closeDrawer()"></swp-detail-drawer-overlay>
|
|
|
|
<!-- Detail Drawer -->
|
|
<swp-detail-drawer id="detailDrawer">
|
|
<swp-drawer-header>
|
|
<swp-drawer-title id="drawerTitle" class="source-web">Online Booking</swp-drawer-title>
|
|
<swp-created-date>oprettet 5. aug 2025, 14:32</swp-created-date>
|
|
</swp-drawer-header>
|
|
|
|
<swp-drawer-content>
|
|
<!-- Event time/date -->
|
|
<swp-event-info>
|
|
<swp-event-time-display>10:00 - 11:00</swp-event-time-display>
|
|
<swp-event-date-display>Mandag 9. december 2025</swp-event-date-display>
|
|
</swp-event-info>
|
|
|
|
<!-- Customer -->
|
|
<swp-drawer-section>
|
|
<swp-customer-info>
|
|
<swp-customer-name>Sofie Nielsen</swp-customer-name>
|
|
<swp-customer-contact>
|
|
<swp-contact-item>
|
|
<span>Tel</span>
|
|
<a href="tel:+4523456789">+45 23 45 67 89</a>
|
|
</swp-contact-item>
|
|
<swp-contact-item>
|
|
<span>Mail</span>
|
|
<a href="mailto:sofie@email.dk">sofie@email.dk</a>
|
|
</swp-contact-item>
|
|
</swp-customer-contact>
|
|
</swp-customer-info>
|
|
</swp-drawer-section>
|
|
|
|
<!-- Status -->
|
|
<swp-drawer-section>
|
|
<swp-status-row>
|
|
<swp-status-label>Status</swp-status-label>
|
|
<button class="status-badge status-arrived" id="statusBadge" popovertarget="statusDropdown">
|
|
<swp-status-dot></swp-status-dot>
|
|
<span id="statusText">Ankommet</span>
|
|
</button>
|
|
<swp-status-dropdown id="statusDropdown" popover>
|
|
<swp-status-option class="opt-created" data-status="created" onclick="selectStatus('created')">
|
|
<swp-status-dot></swp-status-dot>
|
|
<span>Oprettet</span>
|
|
<swp-status-check>✓</swp-status-check>
|
|
</swp-status-option>
|
|
<swp-status-option class="opt-arrived" data-status="arrived" onclick="selectStatus('arrived')">
|
|
<swp-status-dot></swp-status-dot>
|
|
<span>Ankommet</span>
|
|
<swp-status-check>✓</swp-status-check>
|
|
</swp-status-option>
|
|
<swp-status-option class="opt-paid" data-status="paid" onclick="selectStatus('paid')">
|
|
<swp-status-dot></swp-status-dot>
|
|
<span>Betalt</span>
|
|
<swp-status-check>✓</swp-status-check>
|
|
</swp-status-option>
|
|
<swp-status-option class="opt-noshow" data-status="noshow" onclick="selectStatus('noshow')">
|
|
<swp-status-dot></swp-status-dot>
|
|
<span>Udeblevet</span>
|
|
<swp-status-check>✓</swp-status-check>
|
|
</swp-status-option>
|
|
<swp-status-option class="opt-cancelled" data-status="cancelled" onclick="selectStatus('cancelled')">
|
|
<swp-status-dot></swp-status-dot>
|
|
<span>Aflyst</span>
|
|
<swp-status-check>✓</swp-status-check>
|
|
</swp-status-option>
|
|
</swp-status-dropdown>
|
|
</swp-status-row>
|
|
</swp-drawer-section>
|
|
|
|
<!-- Services -->
|
|
<swp-drawer-section>
|
|
<swp-section-label>Services</swp-section-label>
|
|
<swp-services-list>
|
|
<swp-service-item>
|
|
<swp-service-name>Klipning og styling</swp-service-name>
|
|
<swp-service-details>60 min · <swp-service-price>500 kr</swp-service-price></swp-service-details>
|
|
<swp-service-resource>Emma (EMP001)</swp-service-resource>
|
|
</swp-service-item>
|
|
<swp-service-item>
|
|
<swp-service-name>Bundfarve</swp-service-name>
|
|
<swp-service-details>90 min · <swp-service-price>800 kr</swp-service-price></swp-service-details>
|
|
<swp-service-resource>Emma (EMP001)</swp-service-resource>
|
|
</swp-service-item>
|
|
</swp-services-list>
|
|
</swp-drawer-section>
|
|
|
|
<!-- Total -->
|
|
<swp-drawer-section>
|
|
<swp-total-row>
|
|
<swp-total-label>Total</swp-total-label>
|
|
<swp-total-amount>1.300 kr</swp-total-amount>
|
|
</swp-total-row>
|
|
</swp-drawer-section>
|
|
|
|
<!-- Notes -->
|
|
<swp-drawer-section>
|
|
<swp-section-label>Noter</swp-section-label>
|
|
<swp-notes-box>
|
|
Kunden foretrækker naturlige farver og ønsker lidt ekstra tid til konsultation
|
|
</swp-notes-box>
|
|
</swp-drawer-section>
|
|
|
|
<!-- Journal -->
|
|
<swp-drawer-section>
|
|
<swp-section-label>Journal</swp-section-label>
|
|
<swp-journal-link id="journalLink">
|
|
<swp-journal-icon><img id="journalIcon" src="icons/journal-alt.svg" alt=""></swp-journal-icon>
|
|
<swp-journal-text>Åbn journal</swp-journal-text>
|
|
<swp-journal-arrow>→</swp-journal-arrow>
|
|
</swp-journal-link>
|
|
</swp-drawer-section>
|
|
|
|
<!-- Customer stats -->
|
|
<swp-drawer-section>
|
|
<swp-section-label>Kundehistorik</swp-section-label>
|
|
<swp-stats-grid>
|
|
<swp-stat-item>
|
|
<swp-stat-value class="mono">14</swp-stat-value>
|
|
<swp-stat-label>Besøg</swp-stat-label>
|
|
</swp-stat-item>
|
|
<swp-stat-item>
|
|
<swp-stat-value class="mono">8.450 kr</swp-stat-value>
|
|
<swp-stat-label>Omsætning</swp-stat-label>
|
|
</swp-stat-item>
|
|
<swp-stat-item>
|
|
<swp-stat-value>12. nov</swp-stat-value>
|
|
<swp-stat-label>Sidste besøg</swp-stat-label>
|
|
</swp-stat-item>
|
|
<swp-stat-item>
|
|
<swp-stat-value>Olaplex</swp-stat-value>
|
|
<swp-stat-label>Sidste produkt</swp-stat-label>
|
|
</swp-stat-item>
|
|
</swp-stats-grid>
|
|
</swp-drawer-section>
|
|
</swp-drawer-content>
|
|
|
|
<swp-drawer-footer id="drawerFooter">
|
|
<swp-footer-btn class="btn-primary" id="payBtn">Gå til betaling</swp-footer-btn>
|
|
</swp-drawer-footer>
|
|
</swp-detail-drawer>
|
|
|
|
<script>
|
|
const statusLabels = {
|
|
created: 'Oprettet',
|
|
arrived: 'Ankommet',
|
|
paid: 'Betalt',
|
|
noshow: 'Udeblevet',
|
|
cancelled: 'Aflyst'
|
|
};
|
|
|
|
const sourceTitles = {
|
|
manual: 'Manuel Booking',
|
|
web: 'Online Booking',
|
|
recurring: 'Gentagende Booking'
|
|
};
|
|
|
|
function openDrawer(status = 'arrived', source = 'web', hasJournal = true) {
|
|
document.getElementById('drawerOverlay').classList.add('open');
|
|
document.getElementById('detailDrawer').classList.add('open');
|
|
|
|
// Update current status for dropdown
|
|
currentStatus = status;
|
|
|
|
// Update status badge
|
|
const badge = document.getElementById('statusBadge');
|
|
const text = document.getElementById('statusText');
|
|
badge.className = 'status-badge status-' + status;
|
|
text.textContent = statusLabels[status];
|
|
|
|
// Update drawer title based on source
|
|
const title = document.getElementById('drawerTitle');
|
|
title.textContent = sourceTitles[source];
|
|
title.className = 'source-' + source;
|
|
|
|
// Update journal link
|
|
const journalLink = document.getElementById('journalLink');
|
|
const journalText = journalLink.querySelector('swp-journal-text');
|
|
const journalIcon = document.getElementById('journalIcon');
|
|
|
|
if (hasJournal) {
|
|
journalLink.classList.remove('no-journal');
|
|
journalIcon.src = 'icons/journal-alt.svg';
|
|
journalText.textContent = 'Åbn journal';
|
|
} else {
|
|
journalLink.classList.add('no-journal');
|
|
journalIcon.src = 'icons/square-plus.svg';
|
|
journalText.textContent = 'Opret journal';
|
|
}
|
|
|
|
// Update footer based on status
|
|
const footer = document.getElementById('drawerFooter');
|
|
const payBtn = document.getElementById('payBtn');
|
|
footer.className = 'status-' + status;
|
|
|
|
const btnLabels = {
|
|
created: 'Gå til betaling',
|
|
arrived: 'Gå til betaling',
|
|
paid: 'Betalt ✓',
|
|
noshow: 'Udeblevet',
|
|
cancelled: 'Aflyst'
|
|
};
|
|
payBtn.textContent = btnLabels[status];
|
|
}
|
|
|
|
function closeDrawer() {
|
|
document.getElementById('drawerOverlay').classList.remove('open');
|
|
document.getElementById('detailDrawer').classList.remove('open');
|
|
}
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') closeDrawer();
|
|
});
|
|
|
|
// Status dropdown (Popover API)
|
|
let currentStatus = 'arrived';
|
|
const dropdown = document.getElementById('statusDropdown');
|
|
const badge = document.getElementById('statusBadge');
|
|
|
|
// Update selection when popover is about to open
|
|
dropdown.addEventListener('beforetoggle', (e) => {
|
|
if (e.newState === 'open') {
|
|
updateDropdownSelection();
|
|
}
|
|
});
|
|
|
|
// Position after popover opens
|
|
dropdown.addEventListener('toggle', (e) => {
|
|
if (e.newState === 'open') {
|
|
const rect = badge.getBoundingClientRect();
|
|
dropdown.style.position = 'fixed';
|
|
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
dropdown.style.left = `${rect.right - dropdown.offsetWidth}px`;
|
|
}
|
|
});
|
|
|
|
function updateDropdownSelection() {
|
|
const options = document.querySelectorAll('swp-status-option');
|
|
options.forEach(opt => {
|
|
opt.classList.toggle('selected', opt.dataset.status === currentStatus);
|
|
});
|
|
}
|
|
|
|
function selectStatus(status) {
|
|
currentStatus = status;
|
|
|
|
// Update badge
|
|
const badge = document.getElementById('statusBadge');
|
|
const text = document.getElementById('statusText');
|
|
badge.className = 'status-badge status-' + status;
|
|
text.textContent = statusLabels[status];
|
|
|
|
// Update footer
|
|
const footer = document.getElementById('drawerFooter');
|
|
const payBtn = document.getElementById('payBtn');
|
|
footer.className = 'status-' + status;
|
|
|
|
const btnLabels = {
|
|
created: 'Gå til betaling',
|
|
arrived: 'Gå til betaling',
|
|
paid: 'Betalt ✓',
|
|
noshow: 'Udeblevet',
|
|
cancelled: 'Aflyst'
|
|
};
|
|
payBtn.textContent = btnLabels[status];
|
|
|
|
// Close popover
|
|
dropdown.hidePopover();
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|