3482 lines
110 KiB
HTML
3482 lines
110 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>
|
||
|
|
@font-face {
|
||
|
|
font-family: 'Poppins';
|
||
|
|
src: url('fonts/Poppins-Regular.woff') format('woff');
|
||
|
|
font-weight: 400;
|
||
|
|
font-style: normal;
|
||
|
|
font-display: swap;
|
||
|
|
}
|
||
|
|
@font-face {
|
||
|
|
font-family: 'Poppins';
|
||
|
|
src: url('fonts/Poppins-Medium.woff') format('woff');
|
||
|
|
font-weight: 500;
|
||
|
|
font-style: normal;
|
||
|
|
font-display: swap;
|
||
|
|
}
|
||
|
|
@font-face {
|
||
|
|
font-family: 'Poppins';
|
||
|
|
src: url('fonts/Poppins-SemiBold.woff') format('woff');
|
||
|
|
font-weight: 600;
|
||
|
|
font-style: normal;
|
||
|
|
font-display: swap;
|
||
|
|
}
|
||
|
|
@font-face {
|
||
|
|
font-family: 'Poppins';
|
||
|
|
src: url('fonts/Poppins-Bold.woff') format('woff');
|
||
|
|
font-weight: 700;
|
||
|
|
font-style: normal;
|
||
|
|
font-display: swap;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 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: 'Poppins', -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: 900;
|
||
|
|
}
|
||
|
|
|
||
|
|
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: 1000; /* Drawer 1 - top */
|
||
|
|
}
|
||
|
|
|
||
|
|
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-row {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-name {
|
||
|
|
font-size: 18px;
|
||
|
|
font-weight: 500;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-phone {
|
||
|
|
font-size: 14px;
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-phone a {
|
||
|
|
color: var(--color-teal);
|
||
|
|
text-decoration: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-phone a:hover {
|
||
|
|
text-decoration: underline;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-details-link {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 4px;
|
||
|
|
font-size: 13px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
cursor: pointer;
|
||
|
|
margin-top: 6px;
|
||
|
|
transition: color 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-details-link:hover {
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Chevron icon styling */
|
||
|
|
.link-chevron {
|
||
|
|
width: 18px;
|
||
|
|
height: 18px;
|
||
|
|
transition: transform 200ms ease;
|
||
|
|
filter: invert(45%) sepia(0%) saturate(0%) brightness(90%);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-details-link:hover .link-chevron,
|
||
|
|
swp-journal-details-link:hover .link-chevron {
|
||
|
|
filter: invert(32%) sepia(98%) saturate(1234%) hue-rotate(152deg) brightness(93%) contrast(92%);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-details-link.panel-open .link-chevron,
|
||
|
|
swp-journal-details-link.panel-open .link-chevron {
|
||
|
|
transform: rotate(90deg);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 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 0;
|
||
|
|
border-top: 1px solid var(--color-border);
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
margin-top: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-total-label {
|
||
|
|
font-size: 16px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-total-amount {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 24px;
|
||
|
|
font-weight: 700;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journal Panel - slides out from left of drawer */
|
||
|
|
swp-journal-panel {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
right: 340px;
|
||
|
|
bottom: 0;
|
||
|
|
width: 440px;
|
||
|
|
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%);
|
||
|
|
opacity: 0;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
opacity 200ms ease;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
z-index: 990; /* Drawer 2 - middle */
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-panel.open {
|
||
|
|
transform: translateX(0);
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-header {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
padding: 16px 20px;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-header-title {
|
||
|
|
font-size: 16px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-close {
|
||
|
|
background: none;
|
||
|
|
border: none;
|
||
|
|
font-size: 18px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
cursor: pointer;
|
||
|
|
padding: 4px 8px;
|
||
|
|
border-radius: 4px;
|
||
|
|
transition: background 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-close:hover {
|
||
|
|
background: var(--color-background-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journal Tabs - Traditional style */
|
||
|
|
swp-journal-tabs {
|
||
|
|
display: flex;
|
||
|
|
padding: 0 20px;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 8px;
|
||
|
|
padding: 14px 18px;
|
||
|
|
font-size: 13px;
|
||
|
|
font-weight: 500;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
background: transparent;
|
||
|
|
border: none;
|
||
|
|
border-bottom: 2px solid transparent;
|
||
|
|
margin-bottom: -1px;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab:hover:not(.disabled) {
|
||
|
|
color: var(--color-text);
|
||
|
|
background: var(--color-background-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab.active {
|
||
|
|
color: var(--color-text);
|
||
|
|
background: var(--color-surface);
|
||
|
|
border-bottom-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab.disabled {
|
||
|
|
opacity: 0.5;
|
||
|
|
cursor: not-allowed;
|
||
|
|
}
|
||
|
|
|
||
|
|
.tab-indicator {
|
||
|
|
width: 8px;
|
||
|
|
height: 8px;
|
||
|
|
border-radius: 2px;
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.tab-indicator.blue {
|
||
|
|
background: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
|
||
|
|
.tab-indicator.amber {
|
||
|
|
background: var(--b-color-amber);
|
||
|
|
}
|
||
|
|
|
||
|
|
.tab-indicator.gray {
|
||
|
|
background: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
.tab-indicator.purple {
|
||
|
|
background: #8b5cf6;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Tab Content Container */
|
||
|
|
swp-journal-tab-content {
|
||
|
|
display: none;
|
||
|
|
flex-direction: column;
|
||
|
|
flex: 1;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab-content.active {
|
||
|
|
display: flex;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Tab Content Header */
|
||
|
|
swp-journal-tab-header {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 8px;
|
||
|
|
padding: 16px 20px;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab-title {
|
||
|
|
font-size: 15px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab-title span {
|
||
|
|
font-weight: 400;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tab-desc {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
line-height: 1.4;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-add-btn {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 4px;
|
||
|
|
padding: 8px 14px;
|
||
|
|
font-size: 13px;
|
||
|
|
font-weight: 500;
|
||
|
|
color: white;
|
||
|
|
background: var(--color-teal);
|
||
|
|
border-radius: 6px;
|
||
|
|
cursor: pointer;
|
||
|
|
margin-top: 4px;
|
||
|
|
align-self: flex-start;
|
||
|
|
transition: background 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-add-btn:hover {
|
||
|
|
background: #00796b;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journal Content */
|
||
|
|
swp-journal-content {
|
||
|
|
flex: 1;
|
||
|
|
overflow-y: auto;
|
||
|
|
padding: 16px 20px;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journal Entry Card */
|
||
|
|
swp-journal-entry {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 10px;
|
||
|
|
padding: 14px 16px;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-radius: 8px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-meta {
|
||
|
|
display: flex;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
align-items: center;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-type {
|
||
|
|
padding: 4px 10px;
|
||
|
|
font-size: 11px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--b-color-blue);
|
||
|
|
background: color-mix(in srgb, var(--b-color-blue) 15%, var(--b-mix));
|
||
|
|
border-radius: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-type.farveformel {
|
||
|
|
color: var(--color-teal);
|
||
|
|
background: color-mix(in srgb, var(--color-teal) 15%, var(--b-mix));
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-type.analyse {
|
||
|
|
color: #7c3aed;
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-date {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-author {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-tags {
|
||
|
|
display: flex;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
gap: 6px;
|
||
|
|
margin-left: auto;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-tag {
|
||
|
|
padding: 3px 10px;
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
background: var(--color-surface);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Tag Colors - Journal Panel */
|
||
|
|
swp-journal-tag.tag-note,
|
||
|
|
swp-journal-tag:contains('Fri note') {
|
||
|
|
background: color-mix(in srgb, var(--b-color-blue) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-sensitiv {
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
color: #7c3aed;
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-allergi {
|
||
|
|
background: color-mix(in srgb, var(--b-color-red) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-red);
|
||
|
|
color: var(--b-color-red);
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-praference {
|
||
|
|
background: color-mix(in srgb, var(--color-teal) 15%, var(--b-mix));
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-anbefaling {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
color: #b45309;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Farveformel Tags */
|
||
|
|
swp-journal-tag.tag-farveformel {
|
||
|
|
background: color-mix(in srgb, var(--color-teal) 15%, var(--b-mix));
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-kold-tone {
|
||
|
|
background: color-mix(in srgb, var(--b-color-blue) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-toning {
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
color: #7c3aed;
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-balayage {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
color: #b45309;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-delete {
|
||
|
|
padding: 4px 6px;
|
||
|
|
font-size: 14px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
cursor: pointer;
|
||
|
|
border-radius: 4px;
|
||
|
|
transition: all 150ms ease;
|
||
|
|
opacity: 0.6;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-delete:hover {
|
||
|
|
color: var(--b-color-red);
|
||
|
|
background: color-mix(in srgb, var(--b-color-red) 10%, var(--b-mix));
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-text {
|
||
|
|
font-size: 13px;
|
||
|
|
color: var(--color-text);
|
||
|
|
line-height: 1.5;
|
||
|
|
white-space: pre-line;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-text .mono {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Entry Footer - Dato, Synlighed & Markering */
|
||
|
|
swp-journal-entry-footer {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
margin-top: 10px;
|
||
|
|
padding-top: 10px;
|
||
|
|
border-top: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-footer swp-journal-entry-date {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-icons {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-visibility,
|
||
|
|
swp-journal-entry-marking {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 5px;
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-visibility .entry-icon,
|
||
|
|
swp-journal-entry-marking .entry-icon {
|
||
|
|
width: 18px;
|
||
|
|
height: 18px;
|
||
|
|
filter: invert(22%) sepia(14%) saturate(1042%) hue-rotate(164deg) brightness(102%) contrast(85%);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry-marking.hidden {
|
||
|
|
display: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Preview Entry */
|
||
|
|
swp-journal-entry.preview {
|
||
|
|
border: 2px dashed var(--color-teal);
|
||
|
|
opacity: 1;
|
||
|
|
transform: translateY(0);
|
||
|
|
transition: opacity 200ms ease, transform 200ms ease, max-height 300ms ease;
|
||
|
|
max-height: 2000px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-entry.preview.hidden {
|
||
|
|
opacity: 0;
|
||
|
|
transform: translateY(-20px);
|
||
|
|
max-height: 0;
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
overflow: hidden;
|
||
|
|
border: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journal Profile Section */
|
||
|
|
swp-journal-profile-section {
|
||
|
|
padding: 16px 20px;
|
||
|
|
border-top: 1px solid var(--color-border);
|
||
|
|
background: var(--color-surface);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-profile-toggle {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 6px;
|
||
|
|
font-size: 13px;
|
||
|
|
color: var(--color-teal);
|
||
|
|
cursor: pointer;
|
||
|
|
transition: color 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-profile-toggle:hover {
|
||
|
|
color: #00796b;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-profile-toggle .toggle-arrow {
|
||
|
|
font-size: 10px;
|
||
|
|
transition: transform 200ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-profile-toggle.collapsed .toggle-arrow {
|
||
|
|
transform: rotate(-90deg);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-profile-boxes {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: 1fr 1fr;
|
||
|
|
gap: 8px;
|
||
|
|
margin-top: 12px;
|
||
|
|
max-height: 200px;
|
||
|
|
overflow: hidden;
|
||
|
|
transition: max-height 200ms ease, margin-top 200ms ease, opacity 200ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-profile-boxes.collapsed {
|
||
|
|
max-height: 0;
|
||
|
|
margin-top: 0;
|
||
|
|
opacity: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Customer Details Panel - double width drawer, slides under like journal */
|
||
|
|
swp-customer-panel {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
right: 340px;
|
||
|
|
bottom: 0;
|
||
|
|
width: 680px;
|
||
|
|
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%);
|
||
|
|
opacity: 0;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
opacity 200ms ease;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
z-index: 1000;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-panel.open {
|
||
|
|
transform: translateX(0);
|
||
|
|
opacity: 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-panel-header {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
padding: 20px 24px;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-panel-title {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 8px;
|
||
|
|
font-size: 18px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
.panel-header-icon {
|
||
|
|
width: 20px;
|
||
|
|
height: 20px;
|
||
|
|
filter: invert(22%) sepia(14%) saturate(1042%) hue-rotate(164deg) brightness(102%) contrast(85%);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-panel-close {
|
||
|
|
background: none;
|
||
|
|
border: none;
|
||
|
|
font-size: 20px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
cursor: pointer;
|
||
|
|
padding: 4px 8px;
|
||
|
|
border-radius: 4px;
|
||
|
|
transition: background 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-panel-close:hover {
|
||
|
|
background: var(--color-background-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-panel-content {
|
||
|
|
flex: 1;
|
||
|
|
overflow-y: auto;
|
||
|
|
overflow-x: hidden;
|
||
|
|
padding: 24px;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 24px;
|
||
|
|
min-height: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Customer info header */
|
||
|
|
swp-customer-header-section {
|
||
|
|
display: flex;
|
||
|
|
gap: 24px;
|
||
|
|
padding-bottom: 20px;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-avatar {
|
||
|
|
width: 80px;
|
||
|
|
height: 80px;
|
||
|
|
border-radius: 50%;
|
||
|
|
background: linear-gradient(135deg, var(--color-teal), #4db6ac);
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: center;
|
||
|
|
font-size: 32px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: white;
|
||
|
|
flex-shrink: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-info {
|
||
|
|
flex: 1;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-top {
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: flex-start;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-left {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-name {
|
||
|
|
font-size: 24px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-contact {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 6px;
|
||
|
|
align-items: flex-end;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-contact-item {
|
||
|
|
font-size: 14px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-contact-item a {
|
||
|
|
color: var(--color-teal);
|
||
|
|
text-decoration: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-header-contact-item a:hover {
|
||
|
|
text-decoration: underline;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-customer-since {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Fact boxes grid */
|
||
|
|
swp-fact-boxes {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(4, 1fr);
|
||
|
|
gap: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-fact-box {
|
||
|
|
padding: 16px;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-radius: 8px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
text-align: center;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-fact-box-value {
|
||
|
|
display: block;
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 20px;
|
||
|
|
font-weight: 700;
|
||
|
|
color: var(--color-text);
|
||
|
|
margin-bottom: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-fact-box-label {
|
||
|
|
display: block;
|
||
|
|
font-size: 11px;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.5px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-fact-box.highlight {
|
||
|
|
background: linear-gradient(135deg, rgba(0, 137, 123, 0.1), rgba(0, 137, 123, 0.05));
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-fact-box.highlight swp-fact-box-value {
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Chart section */
|
||
|
|
swp-chart-section {
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-header {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-title {
|
||
|
|
font-size: 11px;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.5px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-legend {
|
||
|
|
display: flex;
|
||
|
|
gap: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-legend-item {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 6px;
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-legend-dot {
|
||
|
|
width: 8px;
|
||
|
|
height: 8px;
|
||
|
|
border-radius: 50%;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-legend-dot.services {
|
||
|
|
background: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-legend-dot.products {
|
||
|
|
background: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-chart-container {
|
||
|
|
display: block;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-radius: 8px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Products list */
|
||
|
|
swp-products-section {
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-products-list {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-product-item {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
padding: 12px 14px;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-radius: 6px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-product-info {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 2px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-product-name {
|
||
|
|
font-size: 14px;
|
||
|
|
font-weight: 500;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-product-date {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-product-price {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
font-size: 14px;
|
||
|
|
font-weight: 500;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Preferences section */
|
||
|
|
swp-preferences-section {
|
||
|
|
display: block;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-preferences-grid {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: 1fr 1fr;
|
||
|
|
gap: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-preference-item {
|
||
|
|
padding: 12px 14px;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-radius: 6px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-preference-label {
|
||
|
|
display: block;
|
||
|
|
font-size: 11px;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.5px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
margin-bottom: 4px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-preference-value {
|
||
|
|
font-size: 14px;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 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;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Profile boxes */
|
||
|
|
swp-profile-boxes {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: 1fr 1fr;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-profile-box {
|
||
|
|
padding: 10px 12px;
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
border-radius: 4px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-profile-box.warning {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 10%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-profile-box-label {
|
||
|
|
display: block;
|
||
|
|
font-size: 10px;
|
||
|
|
text-transform: uppercase;
|
||
|
|
letter-spacing: 0.5px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
margin-bottom: 3px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-profile-box.warning swp-profile-box-label {
|
||
|
|
color: #b8860b;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-profile-box-value {
|
||
|
|
display: block;
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text);
|
||
|
|
line-height: 1.3;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-details-link {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 4px;
|
||
|
|
font-size: 13px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
cursor: pointer;
|
||
|
|
margin-top: 10px;
|
||
|
|
transition: color 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-details-link:hover {
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-journal-details-link.no-journal {
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* 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); }
|
||
|
|
|
||
|
|
/* ==========================================
|
||
|
|
ADD NOTE PANEL
|
||
|
|
========================================== */
|
||
|
|
swp-add-note-panel {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
right: 340px; /* Same as journal - starts behind it */
|
||
|
|
bottom: 0;
|
||
|
|
width: 440px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
border-left: 1px solid var(--color-border);
|
||
|
|
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
|
||
|
|
transform: translateX(0); /* Behind journal panel */
|
||
|
|
visibility: hidden;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
visibility 0ms 250ms;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
z-index: 980; /* Drawer 3 - bottom */
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-panel.open {
|
||
|
|
transform: translateX(-100%); /* Slide out to the left */
|
||
|
|
visibility: visible;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
visibility 0ms 0ms;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-header {
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
justify-content: space-between;
|
||
|
|
padding: 16px 20px;
|
||
|
|
border-bottom: 1px solid var(--color-border);
|
||
|
|
background: var(--color-background-alt);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-title {
|
||
|
|
font-size: 16px;
|
||
|
|
font-weight: 600;
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-close {
|
||
|
|
cursor: pointer;
|
||
|
|
padding: 4px 8px;
|
||
|
|
border-radius: 4px;
|
||
|
|
font-size: 18px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
transition: background 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-close:hover {
|
||
|
|
background: var(--color-background-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-content {
|
||
|
|
flex: 1;
|
||
|
|
overflow-y: auto;
|
||
|
|
padding: 20px;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-desc {
|
||
|
|
font-size: 13px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
line-height: 1.4;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-field {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-label {
|
||
|
|
font-size: 12px;
|
||
|
|
color: var(--color-text-secondary);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Tags */
|
||
|
|
swp-add-note-tags {
|
||
|
|
display: flex;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
gap: 8px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-tag-option {
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 6px;
|
||
|
|
padding: 6px 14px;
|
||
|
|
font-size: 13px;
|
||
|
|
border-radius: 16px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
cursor: pointer;
|
||
|
|
transition: all 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-tag-option::before {
|
||
|
|
content: '';
|
||
|
|
width: 8px;
|
||
|
|
height: 8px;
|
||
|
|
border-radius: 50%;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
transition: all 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-tag-option:hover {
|
||
|
|
background: var(--color-background-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-tag-option.selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-blue) 12%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Tag Colors - Add Note Panel */
|
||
|
|
swp-add-note-tag-option[data-tag="note"].selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-blue) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="sensitiv"].selected {
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
color: #7c3aed;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="allergi"].selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-red) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-red);
|
||
|
|
color: var(--b-color-red);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="praference"].selected {
|
||
|
|
background: color-mix(in srgb, var(--color-teal) 15%, var(--b-mix));
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="anbefaling"].selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
color: #b45309;
|
||
|
|
}
|
||
|
|
/* Farveformel tags */
|
||
|
|
swp-add-note-tag-option[data-tag="farveformel"].selected {
|
||
|
|
background: color-mix(in srgb, var(--color-teal) 15%, var(--b-mix));
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="kold-tone"].selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-blue) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="toning"].selected {
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
color: #7c3aed;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="balayage"].selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
color: #b45309;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-tag-option.selected::before {
|
||
|
|
background: var(--b-color-blue);
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="note"].selected::before {
|
||
|
|
background: var(--b-color-blue);
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="sensitiv"].selected::before {
|
||
|
|
background: #8b5cf6;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="allergi"].selected::before {
|
||
|
|
background: var(--b-color-red);
|
||
|
|
border-color: var(--b-color-red);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="praference"].selected::before {
|
||
|
|
background: var(--color-teal);
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="anbefaling"].selected::before {
|
||
|
|
background: var(--b-color-amber);
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
}
|
||
|
|
/* Farveformel tags ::before */
|
||
|
|
swp-add-note-tag-option[data-tag="farveformel"].selected::before {
|
||
|
|
background: var(--color-teal);
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="kold-tone"].selected::before {
|
||
|
|
background: var(--b-color-blue);
|
||
|
|
border-color: var(--b-color-blue);
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="toning"].selected::before {
|
||
|
|
background: #8b5cf6;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="balayage"].selected::before {
|
||
|
|
background: var(--b-color-amber);
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-tip {
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--color-teal);
|
||
|
|
font-style: italic;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Textarea */
|
||
|
|
swp-add-note-content textarea {
|
||
|
|
width: 100%;
|
||
|
|
min-height: 120px;
|
||
|
|
padding: 12px;
|
||
|
|
font-family: inherit;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
resize: vertical;
|
||
|
|
line-height: 1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-content textarea:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Dropdowns */
|
||
|
|
swp-add-note-dropdowns {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: 1fr 1fr;
|
||
|
|
gap: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-dropdown-group {
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
gap: 6px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-dropdown-group select {
|
||
|
|
padding: 10px 12px;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-dropdown-group select:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-help {
|
||
|
|
font-size: 11px;
|
||
|
|
color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Footer */
|
||
|
|
swp-add-note-footer {
|
||
|
|
display: flex;
|
||
|
|
gap: 8px;
|
||
|
|
padding: 16px 20px;
|
||
|
|
border-top: 1px solid var(--color-border);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-btn {
|
||
|
|
flex: 1;
|
||
|
|
padding: 10px 16px;
|
||
|
|
font-size: 13px;
|
||
|
|
font-weight: 500;
|
||
|
|
border-radius: 6px;
|
||
|
|
cursor: pointer;
|
||
|
|
text-align: center;
|
||
|
|
transition: all 150ms ease;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-btn.primary {
|
||
|
|
background: var(--color-teal);
|
||
|
|
color: white;
|
||
|
|
border: none;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-btn.primary:hover {
|
||
|
|
background: #00796b;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-btn.secondary {
|
||
|
|
background: var(--color-surface);
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
color: var(--color-text);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-btn.secondary:hover {
|
||
|
|
background: var(--color-background-hover);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==========================================
|
||
|
|
FARVEFORMEL PANEL (extends add-note styles)
|
||
|
|
========================================== */
|
||
|
|
swp-farveformel-panel {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
right: 340px;
|
||
|
|
bottom: 0;
|
||
|
|
width: 440px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
border-left: 1px solid var(--color-border);
|
||
|
|
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
|
||
|
|
transform: translateX(0);
|
||
|
|
visibility: hidden;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
visibility 0ms 250ms;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
z-index: 980;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-farveformel-panel.open {
|
||
|
|
transform: translateX(-100%);
|
||
|
|
visibility: visible;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
visibility 0ms 0ms;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Farveformel-specific: 2-column grid layout */
|
||
|
|
swp-add-note-row {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: 1fr 1fr;
|
||
|
|
gap: 16px;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-add-note-field.full-width {
|
||
|
|
grid-column: 1 / -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Input styling for farveformel */
|
||
|
|
swp-farveformel-panel input[type="text"] {
|
||
|
|
padding: 10px 12px;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Monospace for formula fields */
|
||
|
|
swp-farveformel-panel input#ffFormel,
|
||
|
|
swp-farveformel-panel input#ffBlandingsforhold {
|
||
|
|
font-family: var(--font-mono);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-farveformel-panel input[type="text"]:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-farveformel-panel select {
|
||
|
|
padding: 10px 12px;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-farveformel-panel select:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-farveformel-panel textarea {
|
||
|
|
width: 100%;
|
||
|
|
min-height: 100px;
|
||
|
|
padding: 12px;
|
||
|
|
font-family: inherit;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
resize: vertical;
|
||
|
|
line-height: 1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-farveformel-panel textarea:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: var(--color-teal);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ==========================================
|
||
|
|
ANALYSE PANEL (extends add-note styles)
|
||
|
|
========================================== */
|
||
|
|
swp-analyse-panel {
|
||
|
|
position: fixed;
|
||
|
|
top: 0;
|
||
|
|
right: 340px;
|
||
|
|
bottom: 0;
|
||
|
|
width: 440px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
border-left: 1px solid var(--color-border);
|
||
|
|
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
|
||
|
|
transform: translateX(0);
|
||
|
|
visibility: hidden;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
visibility 0ms 250ms;
|
||
|
|
display: flex;
|
||
|
|
flex-direction: column;
|
||
|
|
z-index: 980;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel.open {
|
||
|
|
transform: translateX(-100%);
|
||
|
|
visibility: visible;
|
||
|
|
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
|
||
|
|
visibility 0ms 0ms;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel input[type="text"] {
|
||
|
|
padding: 10px 12px;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel input[type="text"]:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel select {
|
||
|
|
padding: 10px 12px;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
cursor: pointer;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel select:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel textarea {
|
||
|
|
width: 100%;
|
||
|
|
min-height: 80px;
|
||
|
|
padding: 12px;
|
||
|
|
font-family: inherit;
|
||
|
|
font-size: 13px;
|
||
|
|
border: 1px solid var(--color-border);
|
||
|
|
border-radius: 6px;
|
||
|
|
background: var(--color-surface);
|
||
|
|
resize: vertical;
|
||
|
|
line-height: 1.5;
|
||
|
|
}
|
||
|
|
|
||
|
|
swp-analyse-panel textarea:focus {
|
||
|
|
outline: none;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Analyse tags */
|
||
|
|
swp-add-note-tag-option[data-tag="analyse"].selected {
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
color: #7c3aed;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="hovedbund"].selected {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
color: #b45309;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="analyse"].selected::before {
|
||
|
|
background: #8b5cf6;
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
}
|
||
|
|
swp-add-note-tag-option[data-tag="hovedbund"].selected::before {
|
||
|
|
background: var(--b-color-amber);
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Journal tag for analyse */
|
||
|
|
swp-journal-tag.tag-analyse {
|
||
|
|
background: color-mix(in srgb, #8b5cf6 15%, var(--b-mix));
|
||
|
|
border-color: #8b5cf6;
|
||
|
|
color: #7c3aed;
|
||
|
|
}
|
||
|
|
swp-journal-tag.tag-hovedbund {
|
||
|
|
background: color-mix(in srgb, var(--b-color-amber) 15%, var(--b-mix));
|
||
|
|
border-color: var(--b-color-amber);
|
||
|
|
color: #b45309;
|
||
|
|
}
|
||
|
|
</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>
|
||
|
|
|
||
|
|
<!-- Journal Panel -->
|
||
|
|
<swp-journal-panel id="journalPanel">
|
||
|
|
<swp-journal-header>
|
||
|
|
<swp-journal-header-title>Journal</swp-journal-header-title>
|
||
|
|
<swp-journal-close onclick="closeJournal()">✕</swp-journal-close>
|
||
|
|
</swp-journal-header>
|
||
|
|
|
||
|
|
<!-- Tabs -->
|
||
|
|
<swp-journal-tabs>
|
||
|
|
<swp-journal-tab class="active" data-tab="noter" onclick="switchJournalTab('noter')"><span class="tab-indicator blue"></span>Noter</swp-journal-tab>
|
||
|
|
<swp-journal-tab data-tab="farveformler" onclick="switchJournalTab('farveformler')"><span class="tab-indicator amber"></span>Farveformler</swp-journal-tab>
|
||
|
|
<swp-journal-tab data-tab="analyse" onclick="switchJournalTab('analyse')"><span class="tab-indicator purple"></span>Analyse</swp-journal-tab>
|
||
|
|
</swp-journal-tabs>
|
||
|
|
|
||
|
|
<!-- Tab: Noter -->
|
||
|
|
<swp-journal-tab-content id="tabNoter" class="active">
|
||
|
|
<swp-journal-tab-header>
|
||
|
|
<swp-journal-tab-title>Kunde-journal <span>(langsigtet)</span></swp-journal-tab-title>
|
||
|
|
<swp-journal-tab-desc>Private noter om hår, reaktioner og anbefalinger. Kunden ser det ikke.</swp-journal-tab-desc>
|
||
|
|
<swp-journal-add-btn onclick="openAddNote()">+ Tilføj note</swp-journal-add-btn>
|
||
|
|
</swp-journal-tab-header>
|
||
|
|
|
||
|
|
<swp-journal-content>
|
||
|
|
<!-- Preview Entry for Notes -->
|
||
|
|
<swp-journal-entry id="previewEntry" class="preview hidden">
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type>Note</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-tags id="previewTags"></swp-journal-entry-tags>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text id="previewText">(Tom note)</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date id="previewDate">I dag</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility id="previewVisibility">
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
<swp-journal-entry-marking id="previewMarking" class="hidden"></swp-journal-entry-marking>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
|
||
|
|
<swp-journal-entry>
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type>Note</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-tags>
|
||
|
|
<swp-journal-tag class="tag-allergi">Hovedbund</swp-journal-tag>
|
||
|
|
<swp-journal-tag class="tag-sensitiv">Sensitiv</swp-journal-tag>
|
||
|
|
</swp-journal-entry-tags>
|
||
|
|
<swp-journal-entry-delete title="Slet">🗑</swp-journal-entry-delete>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text>
|
||
|
|
Let irritation ved hårgrænsen. Anbefalet parfumefri shampoo + mild kur.<br>
|
||
|
|
Kunden reagerer på stærk parfume.
|
||
|
|
</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date>2. sep 2025 · Af: Nina</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility>
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
</swp-journal-content>
|
||
|
|
</swp-journal-tab-content>
|
||
|
|
|
||
|
|
<!-- Tab: Farveformler -->
|
||
|
|
<swp-journal-tab-content id="tabFarveformler">
|
||
|
|
<swp-journal-tab-header>
|
||
|
|
<swp-journal-tab-title>Farveformler <span>(historik)</span></swp-journal-tab-title>
|
||
|
|
<swp-journal-tab-desc>Gemte farveformler for denne kunde. Nem genbrug og konsistens.</swp-journal-tab-desc>
|
||
|
|
<swp-journal-add-btn onclick="openFarveformel()">+ Tilføj farveformel</swp-journal-add-btn>
|
||
|
|
</swp-journal-tab-header>
|
||
|
|
|
||
|
|
<swp-journal-content>
|
||
|
|
<!-- Preview Entry for Farveformler -->
|
||
|
|
<swp-journal-entry id="previewEntryFarveformel" class="preview hidden">
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type class="farveformel">Farveformel</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-tags id="previewTagsFarveformel"></swp-journal-entry-tags>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text id="previewTextFarveformel">(Udfyld felter...)</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date>I dag</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility>
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
|
||
|
|
<swp-journal-entry>
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type class="farveformel">Farveformel</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-delete title="Slet">🗑</swp-journal-entry-delete>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text>
|
||
|
|
• Mål/tone: Kold<br>
|
||
|
|
• Oxidant: <span class="mono">1.9%</span><br>
|
||
|
|
• Formel: <span class="mono">7/1 + 7/0 (1:1)</span><br>
|
||
|
|
• Virketid: <span class="mono">15 min</span><br>
|
||
|
|
• Placering: Hele håret<br><br>
|
||
|
|
Resultat: neutral/kold, god glans. Undgå varme toner næste gang.
|
||
|
|
</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date>12. nov 2025 · Af: Maja</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility>
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
|
||
|
|
<swp-journal-entry>
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type class="farveformel">Farveformel</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-delete title="Slet">🗑</swp-journal-entry-delete>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text>
|
||
|
|
• Mål/tone: Neutral<br>
|
||
|
|
• Oxidant: <span class="mono">3%</span><br>
|
||
|
|
• Formel: <span class="mono">6/0 + 7/1 (2:1)</span><br>
|
||
|
|
• Virketid: <span class="mono">20 min</span><br>
|
||
|
|
• Placering: Rødder<br><br>
|
||
|
|
Første besøg. Kunden ønskede naturlig look.
|
||
|
|
</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date>15. aug 2025 · Af: Maja</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility>
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
</swp-journal-content>
|
||
|
|
</swp-journal-tab-content>
|
||
|
|
|
||
|
|
<!-- Tab: Analyse -->
|
||
|
|
<swp-journal-tab-content id="tabAnalyse">
|
||
|
|
<swp-journal-tab-header>
|
||
|
|
<swp-journal-tab-title>Hår & hovedbund <span>(analyse)</span></swp-journal-tab-title>
|
||
|
|
<swp-journal-tab-desc>Struktureret analyse af hår og hovedbund. Kan blive til advarsel.</swp-journal-tab-desc>
|
||
|
|
<swp-journal-add-btn onclick="openAnalyse()">+ Tilføj analyse</swp-journal-add-btn>
|
||
|
|
</swp-journal-tab-header>
|
||
|
|
|
||
|
|
<swp-journal-content>
|
||
|
|
<!-- Preview Entry for Analyse -->
|
||
|
|
<swp-journal-entry id="previewEntryAnalyse" class="preview hidden">
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type class="analyse">Analyse</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-tags id="previewTagsAnalyse"></swp-journal-entry-tags>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text id="previewTextAnalyse">(Udfyld felter...)</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date>I dag</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility>
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
|
||
|
|
<swp-journal-entry>
|
||
|
|
<swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-type class="analyse">Analyse</swp-journal-entry-type>
|
||
|
|
<swp-journal-entry-tags>
|
||
|
|
<swp-journal-tag class="tag-analyse">Hovedbund</swp-journal-tag>
|
||
|
|
<swp-journal-tag class="tag-sensitiv">Sensitiv</swp-journal-tag>
|
||
|
|
</swp-journal-entry-tags>
|
||
|
|
<swp-journal-entry-delete title="Slet">🗑</swp-journal-entry-delete>
|
||
|
|
</swp-journal-entry-meta>
|
||
|
|
<swp-journal-entry-text>
|
||
|
|
• Hovedbund: Let irriteret<br>
|
||
|
|
• Hår: <span class="mono">Medium · Bølget</span><br>
|
||
|
|
• Porøsitet: <span class="mono">Medium</span><br>
|
||
|
|
• Kemisk beh.: Nej<br><br>
|
||
|
|
Let rødme ved hårgrænsen. Anbefalet parfumefri shampoo.
|
||
|
|
</swp-journal-entry-text>
|
||
|
|
<swp-journal-entry-footer>
|
||
|
|
<swp-journal-entry-date>2. sep 2025 · Af: Nina</swp-journal-entry-date>
|
||
|
|
<swp-journal-entry-icons>
|
||
|
|
<swp-journal-entry-visibility>
|
||
|
|
<img src="icons/eye.svg" class="entry-icon" alt="">
|
||
|
|
<span>Alle</span>
|
||
|
|
</swp-journal-entry-visibility>
|
||
|
|
<swp-journal-entry-marking class="warning">
|
||
|
|
<img src="icons/warning.svg" class="entry-icon" alt="">
|
||
|
|
<span>Advarsel</span>
|
||
|
|
</swp-journal-entry-marking>
|
||
|
|
</swp-journal-entry-icons>
|
||
|
|
</swp-journal-entry-footer>
|
||
|
|
</swp-journal-entry>
|
||
|
|
</swp-journal-content>
|
||
|
|
</swp-journal-tab-content>
|
||
|
|
|
||
|
|
<!-- Kundeprofil Toggle -->
|
||
|
|
<swp-journal-profile-section>
|
||
|
|
<swp-journal-profile-toggle onclick="toggleJournalProfile()">
|
||
|
|
<span class="toggle-arrow">▼</span> Vis "Kundeprofil" (hurtige facts)
|
||
|
|
</swp-journal-profile-toggle>
|
||
|
|
<swp-journal-profile-boxes id="journalProfileBoxes">
|
||
|
|
<swp-profile-box>
|
||
|
|
<swp-profile-box-label>Hårtype</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Medium • Bølget</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
<swp-profile-box>
|
||
|
|
<swp-profile-box-label>Porøsitet</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Medium</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
<swp-profile-box>
|
||
|
|
<swp-profile-box-label>Præference</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Kold tone, ikke for mørk</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
<swp-profile-box class="warning">
|
||
|
|
<swp-profile-box-label>Advarsler</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Parfume-allergi • Sensitiv hovedbund</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
</swp-journal-profile-boxes>
|
||
|
|
</swp-journal-profile-section>
|
||
|
|
</swp-journal-panel>
|
||
|
|
|
||
|
|
<!-- Add Note Panel -->
|
||
|
|
<swp-add-note-panel id="addNotePanel">
|
||
|
|
<swp-add-note-header>
|
||
|
|
<swp-add-note-title>Opret ny note</swp-add-note-title>
|
||
|
|
<swp-add-note-close onclick="closeAddNote()">✕</swp-add-note-close>
|
||
|
|
</swp-add-note-header>
|
||
|
|
|
||
|
|
<swp-add-note-content>
|
||
|
|
<swp-add-note-desc>God til observationer, præferencer, reaktioner og næste gang-plan.</swp-add-note-desc>
|
||
|
|
|
||
|
|
<!-- Tags -->
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Tags (klik for at tilføje)</swp-add-note-label>
|
||
|
|
<swp-add-note-tags>
|
||
|
|
<swp-add-note-tag-option class="selected" data-tag="note">Fri note</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="sensitiv">Sensitiv</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="allergi">Allergi</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="praference">Præference</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="anbefaling">Anbefaling</swp-add-note-tag-option>
|
||
|
|
</swp-add-note-tags>
|
||
|
|
<swp-add-note-tip>Tip: I et rigtigt system kan tags være søgbare/standardiserede.</swp-add-note-tip>
|
||
|
|
</swp-add-note-field>
|
||
|
|
|
||
|
|
<!-- Note Textarea -->
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Note</swp-add-note-label>
|
||
|
|
<textarea placeholder="Fx: Kunden vil have kold tone og ikke for mørk. Reagerer på parfume. Næste gang: kortere pandehår."></textarea>
|
||
|
|
</swp-add-note-field>
|
||
|
|
|
||
|
|
<!-- Dropdowns -->
|
||
|
|
<swp-add-note-dropdowns>
|
||
|
|
<swp-add-note-dropdown-group>
|
||
|
|
<swp-add-note-label>Synlighed</swp-add-note-label>
|
||
|
|
<select>
|
||
|
|
<option>Hele salonen</option>
|
||
|
|
<option>Kun mig</option>
|
||
|
|
</select>
|
||
|
|
<swp-add-note-help>Hvis I er flere frisører, kan "Kun mig" være nyttigt.</swp-add-note-help>
|
||
|
|
</swp-add-note-dropdown-group>
|
||
|
|
<swp-add-note-dropdown-group>
|
||
|
|
<swp-add-note-label>Markering</swp-add-note-label>
|
||
|
|
<select>
|
||
|
|
<option>Ingen</option>
|
||
|
|
<option>Vigtigt</option>
|
||
|
|
<option>Advarsel</option>
|
||
|
|
</select>
|
||
|
|
<swp-add-note-help>"Advarsel" kan vise ikon på kundekortet.</swp-add-note-help>
|
||
|
|
</swp-add-note-dropdown-group>
|
||
|
|
</swp-add-note-dropdowns>
|
||
|
|
</swp-add-note-content>
|
||
|
|
|
||
|
|
<swp-add-note-footer>
|
||
|
|
<swp-add-note-btn class="secondary" onclick="closeAddNote()">Annuller</swp-add-note-btn>
|
||
|
|
<swp-add-note-btn class="primary">Gem note</swp-add-note-btn>
|
||
|
|
</swp-add-note-footer>
|
||
|
|
</swp-add-note-panel>
|
||
|
|
|
||
|
|
<!-- Farveformel Panel -->
|
||
|
|
<swp-farveformel-panel id="farveformelPanel">
|
||
|
|
<swp-add-note-header>
|
||
|
|
<swp-add-note-title>Farveformel</swp-add-note-title>
|
||
|
|
<swp-add-note-close onclick="closeFarveformel()">✕</swp-add-note-close>
|
||
|
|
</swp-add-note-header>
|
||
|
|
|
||
|
|
<swp-add-note-content>
|
||
|
|
<swp-add-note-desc>Struktureret nok til at kunne genskabes. Gemmes som journalnote.</swp-add-note-desc>
|
||
|
|
|
||
|
|
<!-- Row 1: Mål/tone + Oxidant -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Mål / tone</swp-add-note-label>
|
||
|
|
<select id="ffMaalTone">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Kold">Kold</option>
|
||
|
|
<option value="Varm">Varm</option>
|
||
|
|
<option value="Neutral">Neutral</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Oxidant / styrke</swp-add-note-label>
|
||
|
|
<select id="ffOxidant">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="1.9%">1.9%</option>
|
||
|
|
<option value="3%">3%</option>
|
||
|
|
<option value="6%">6%</option>
|
||
|
|
<option value="9%">9%</option>
|
||
|
|
<option value="12%">12%</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Row 2: Formel + Blandingsforhold -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Formel (skriv som du vil)</swp-add-note-label>
|
||
|
|
<input type="text" id="ffFormel" placeholder="Fx: 7/1 + 7/0 (1:1)">
|
||
|
|
<swp-add-note-tip>Monospace gør formler nemmere at læse.</swp-add-note-tip>
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Blandingsforhold</swp-add-note-label>
|
||
|
|
<input type="text" id="ffBlandingsforhold" placeholder="Fx: 1:2">
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Row 3: Virketid + Placering -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Virketid</swp-add-note-label>
|
||
|
|
<input type="text" id="ffVirketid" placeholder="Fx: 15 min">
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Placering</swp-add-note-label>
|
||
|
|
<select id="ffPlacering">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Hele håret">Hele håret</option>
|
||
|
|
<option value="Rødder">Rødder</option>
|
||
|
|
<option value="Længder">Længder</option>
|
||
|
|
<option value="Spidser">Spidser</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Resultat / note -->
|
||
|
|
<swp-add-note-field class="full-width">
|
||
|
|
<swp-add-note-label>Resultat / note</swp-add-note-label>
|
||
|
|
<textarea id="ffResultat" placeholder="Fx: Resultat kold/neutral, god glans. Undgå varme toner næste gang."></textarea>
|
||
|
|
</swp-add-note-field>
|
||
|
|
|
||
|
|
</swp-add-note-content>
|
||
|
|
|
||
|
|
<swp-add-note-footer>
|
||
|
|
<swp-add-note-btn class="secondary" onclick="closeFarveformel()">Annuller</swp-add-note-btn>
|
||
|
|
<swp-add-note-btn class="primary" onclick="saveFarveformel()">Gem farveformel</swp-add-note-btn>
|
||
|
|
</swp-add-note-footer>
|
||
|
|
</swp-farveformel-panel>
|
||
|
|
|
||
|
|
<!-- Analyse Panel -->
|
||
|
|
<swp-analyse-panel id="analysePanel">
|
||
|
|
<swp-add-note-header>
|
||
|
|
<swp-add-note-title>Shampoo & hovedbund-analyse</swp-add-note-title>
|
||
|
|
<swp-add-note-close onclick="closeAnalyse()">✕</swp-add-note-close>
|
||
|
|
</swp-add-note-header>
|
||
|
|
|
||
|
|
<swp-add-note-content>
|
||
|
|
<swp-add-note-desc>Hurtige valg + bemærkning. Kan blive til "sticky warning".</swp-add-note-desc>
|
||
|
|
|
||
|
|
<!-- Row 1: Hovedbund + Irritation -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Hovedbund (tilstand)</swp-add-note-label>
|
||
|
|
<select id="anHovedbund">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Normal">Normal</option>
|
||
|
|
<option value="Tør">Tør</option>
|
||
|
|
<option value="Fedtet">Fedtet</option>
|
||
|
|
<option value="Let irriteret">Let irriteret</option>
|
||
|
|
<option value="Irriteret">Irriteret</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Irritation</swp-add-note-label>
|
||
|
|
<select id="anIrritation">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Ingen">Ingen</option>
|
||
|
|
<option value="Let">Let</option>
|
||
|
|
<option value="Moderat">Moderat</option>
|
||
|
|
<option value="Kraftig">Kraftig</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Row 2: Hår tykkelse + struktur -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Hår (tykkelse)</swp-add-note-label>
|
||
|
|
<select id="anHaarTykkelse">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Fint">Fint</option>
|
||
|
|
<option value="Medium">Medium</option>
|
||
|
|
<option value="Tykt">Tykt</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Hår (struktur)</swp-add-note-label>
|
||
|
|
<select id="anHaarStruktur">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Glat">Glat</option>
|
||
|
|
<option value="Bølget">Bølget</option>
|
||
|
|
<option value="Krøllet">Krøllet</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Row 3: Porøsitet + Kemisk behandling -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Porøsitet</swp-add-note-label>
|
||
|
|
<select id="anPorositet">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Lav">Lav</option>
|
||
|
|
<option value="Medium">Medium</option>
|
||
|
|
<option value="Høj">Høj</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Tidligere kemisk behandling?</swp-add-note-label>
|
||
|
|
<select id="anKemisk">
|
||
|
|
<option value="">Vælg...</option>
|
||
|
|
<option value="Nej">Nej</option>
|
||
|
|
<option value="Ja">Ja</option>
|
||
|
|
</select>
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Row 4: Shampoo + Hjemmepleje -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Anvendt shampoo</swp-add-note-label>
|
||
|
|
<input type="text" id="anShampoo" placeholder="Fx: Kerastase Bain">
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Anbefalet hjemmepleje</swp-add-note-label>
|
||
|
|
<input type="text" id="anHjemmepleje" placeholder="Fx: Parfumefri shampoo">
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
|
||
|
|
<!-- Bemærkning -->
|
||
|
|
<swp-add-note-field class="full-width">
|
||
|
|
<swp-add-note-label>Bemærkning</swp-add-note-label>
|
||
|
|
<textarea id="anBemaerkning" placeholder="Fx: Let rødme ved hårgrænsen. Undgå parfume og stærke sulfater."></textarea>
|
||
|
|
</swp-add-note-field>
|
||
|
|
|
||
|
|
<!-- Row 5: Advarsel + Tags -->
|
||
|
|
<swp-add-note-row>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Gør til advarsel på kundekort?</swp-add-note-label>
|
||
|
|
<select id="anAdvarsel">
|
||
|
|
<option value="Nej">Nej</option>
|
||
|
|
<option value="Ja">Ja</option>
|
||
|
|
</select>
|
||
|
|
<swp-add-note-help>Brug "Ja" ved fx allergi/sensitivitet.</swp-add-note-help>
|
||
|
|
</swp-add-note-field>
|
||
|
|
<swp-add-note-field>
|
||
|
|
<swp-add-note-label>Tags</swp-add-note-label>
|
||
|
|
<swp-add-note-tags>
|
||
|
|
<swp-add-note-tag-option class="selected" data-tag="analyse">Analyse</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="hovedbund">Hovedbund</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="sensitiv">Sensitiv</swp-add-note-tag-option>
|
||
|
|
<swp-add-note-tag-option data-tag="allergi">Allergi</swp-add-note-tag-option>
|
||
|
|
</swp-add-note-tags>
|
||
|
|
</swp-add-note-field>
|
||
|
|
</swp-add-note-row>
|
||
|
|
</swp-add-note-content>
|
||
|
|
|
||
|
|
<swp-add-note-footer>
|
||
|
|
<swp-add-note-btn class="secondary" onclick="closeAnalyse()">Annuller</swp-add-note-btn>
|
||
|
|
<swp-add-note-btn class="primary" onclick="saveAnalyse()">Gem analyse</swp-add-note-btn>
|
||
|
|
</swp-add-note-footer>
|
||
|
|
</swp-analyse-panel>
|
||
|
|
|
||
|
|
<!-- Customer Details Panel -->
|
||
|
|
<swp-customer-panel id="customerPanel">
|
||
|
|
<swp-customer-panel-header>
|
||
|
|
<swp-customer-panel-title><img src="icons/user.svg" class="panel-header-icon" alt="">Kundedetaljer</swp-customer-panel-title>
|
||
|
|
<swp-customer-panel-close onclick="closeCustomerPanel()">✕</swp-customer-panel-close>
|
||
|
|
</swp-customer-panel-header>
|
||
|
|
<swp-customer-panel-content>
|
||
|
|
<!-- Customer header with avatar -->
|
||
|
|
<swp-customer-header-section>
|
||
|
|
<swp-customer-avatar>SN</swp-customer-avatar>
|
||
|
|
<swp-customer-header-info>
|
||
|
|
<swp-customer-header-top>
|
||
|
|
<swp-customer-header-left>
|
||
|
|
<swp-customer-header-name>Sofie Nielsen</swp-customer-header-name>
|
||
|
|
<swp-customer-since>Kunde siden marts 2024</swp-customer-since>
|
||
|
|
</swp-customer-header-left>
|
||
|
|
<swp-customer-header-contact>
|
||
|
|
<swp-customer-header-contact-item>
|
||
|
|
<a href="tel:+4523456789">+45 23 45 67 89</a>
|
||
|
|
</swp-customer-header-contact-item>
|
||
|
|
<swp-customer-header-contact-item>
|
||
|
|
<a href="mailto:sofie@email.dk">sofie@email.dk</a>
|
||
|
|
</swp-customer-header-contact-item>
|
||
|
|
</swp-customer-header-contact>
|
||
|
|
</swp-customer-header-top>
|
||
|
|
</swp-customer-header-info>
|
||
|
|
</swp-customer-header-section>
|
||
|
|
|
||
|
|
<!-- Fact boxes -->
|
||
|
|
<swp-fact-boxes>
|
||
|
|
<swp-fact-box class="highlight">
|
||
|
|
<swp-fact-box-value>12.450 kr</swp-fact-box-value>
|
||
|
|
<swp-fact-box-label>Total omsætning</swp-fact-box-label>
|
||
|
|
</swp-fact-box>
|
||
|
|
<swp-fact-box>
|
||
|
|
<swp-fact-box-value>14</swp-fact-box-value>
|
||
|
|
<swp-fact-box-label>Besøg</swp-fact-box-label>
|
||
|
|
</swp-fact-box>
|
||
|
|
<swp-fact-box>
|
||
|
|
<swp-fact-box-value>889 kr</swp-fact-box-value>
|
||
|
|
<swp-fact-box-label>Gns. pr. besøg</swp-fact-box-label>
|
||
|
|
</swp-fact-box>
|
||
|
|
<swp-fact-box>
|
||
|
|
<swp-fact-box-value>32 dage</swp-fact-box-value>
|
||
|
|
<swp-fact-box-label>Gns. interval</swp-fact-box-label>
|
||
|
|
</swp-fact-box>
|
||
|
|
</swp-fact-boxes>
|
||
|
|
|
||
|
|
<!-- Chart -->
|
||
|
|
<swp-chart-section>
|
||
|
|
<swp-chart-header>
|
||
|
|
<swp-chart-title>Omsætning (sidste 6 mdr)</swp-chart-title>
|
||
|
|
<swp-chart-legend>
|
||
|
|
<swp-chart-legend-item>
|
||
|
|
<swp-chart-legend-dot class="services"></swp-chart-legend-dot>
|
||
|
|
<span>Services</span>
|
||
|
|
</swp-chart-legend-item>
|
||
|
|
<swp-chart-legend-item>
|
||
|
|
<swp-chart-legend-dot class="products"></swp-chart-legend-dot>
|
||
|
|
<span>Produkter</span>
|
||
|
|
</swp-chart-legend-item>
|
||
|
|
</swp-chart-legend>
|
||
|
|
</swp-chart-header>
|
||
|
|
<swp-chart-container id="customerRevenueChart"></swp-chart-container>
|
||
|
|
</swp-chart-section>
|
||
|
|
|
||
|
|
<!-- Last 5 products -->
|
||
|
|
<swp-products-section>
|
||
|
|
<swp-section-label>Seneste produktkøb</swp-section-label>
|
||
|
|
<swp-products-list>
|
||
|
|
<swp-product-item>
|
||
|
|
<swp-product-info>
|
||
|
|
<swp-product-name>Olaplex No. 3</swp-product-name>
|
||
|
|
<swp-product-date>9. dec 2025</swp-product-date>
|
||
|
|
</swp-product-info>
|
||
|
|
<swp-product-price>300 kr</swp-product-price>
|
||
|
|
</swp-product-item>
|
||
|
|
<swp-product-item>
|
||
|
|
<swp-product-info>
|
||
|
|
<swp-product-name>Kevin Murphy Hydrate-Me Wash</swp-product-name>
|
||
|
|
<swp-product-date>12. nov 2025</swp-product-date>
|
||
|
|
</swp-product-info>
|
||
|
|
<swp-product-price>275 kr</swp-product-price>
|
||
|
|
</swp-product-item>
|
||
|
|
<swp-product-item>
|
||
|
|
<swp-product-info>
|
||
|
|
<swp-product-name>Olaplex No. 4 Bond Shampoo</swp-product-name>
|
||
|
|
<swp-product-date>18. okt 2025</swp-product-date>
|
||
|
|
</swp-product-info>
|
||
|
|
<swp-product-price>320 kr</swp-product-price>
|
||
|
|
</swp-product-item>
|
||
|
|
<swp-product-item>
|
||
|
|
<swp-product-info>
|
||
|
|
<swp-product-name>Moroccanoil Treatment</swp-product-name>
|
||
|
|
<swp-product-date>5. sep 2025</swp-product-date>
|
||
|
|
</swp-product-info>
|
||
|
|
<swp-product-price>399 kr</swp-product-price>
|
||
|
|
</swp-product-item>
|
||
|
|
<swp-product-item>
|
||
|
|
<swp-product-info>
|
||
|
|
<swp-product-name>Olaplex No. 5 Conditioner</swp-product-name>
|
||
|
|
<swp-product-date>12. aug 2025</swp-product-date>
|
||
|
|
</swp-product-info>
|
||
|
|
<swp-product-price>320 kr</swp-product-price>
|
||
|
|
</swp-product-item>
|
||
|
|
</swp-products-list>
|
||
|
|
</swp-products-section>
|
||
|
|
|
||
|
|
<!-- Preferences -->
|
||
|
|
<swp-preferences-section>
|
||
|
|
<swp-section-label>Præferencer & noter</swp-section-label>
|
||
|
|
<swp-preferences-grid>
|
||
|
|
<swp-preference-item>
|
||
|
|
<swp-preference-label>Foretrukken frisør</swp-preference-label>
|
||
|
|
<swp-preference-value>Emma Larsen</swp-preference-value>
|
||
|
|
</swp-preference-item>
|
||
|
|
<swp-preference-item>
|
||
|
|
<swp-preference-label>Hårtype</swp-preference-label>
|
||
|
|
<swp-preference-value>Fint, medium tykkelse</swp-preference-value>
|
||
|
|
</swp-preference-item>
|
||
|
|
<swp-preference-item>
|
||
|
|
<swp-preference-label>Farvehistorik</swp-preference-label>
|
||
|
|
<swp-preference-value>7.3 + 7.4 blanding</swp-preference-value>
|
||
|
|
</swp-preference-item>
|
||
|
|
<swp-preference-item>
|
||
|
|
<swp-preference-label>Allergier</swp-preference-label>
|
||
|
|
<swp-preference-value>Ingen kendte</swp-preference-value>
|
||
|
|
</swp-preference-item>
|
||
|
|
</swp-preferences-grid>
|
||
|
|
</swp-preferences-section>
|
||
|
|
</swp-customer-panel-content>
|
||
|
|
</swp-customer-panel>
|
||
|
|
|
||
|
|
<!-- 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-section-label>Kunde</swp-section-label>
|
||
|
|
<swp-customer-info>
|
||
|
|
<swp-customer-row>
|
||
|
|
<swp-customer-name>Sofie Nielsen</swp-customer-name>
|
||
|
|
<swp-customer-phone><a href="tel:+4523456789">+45 23 45 67 89</a></swp-customer-phone>
|
||
|
|
</swp-customer-row>
|
||
|
|
<swp-customer-details-link id="customerDetailsLink" onclick="openCustomerPanel()">Vis detaljer <img src="icons/angle-small-right.svg" class="link-chevron" alt=""></swp-customer-details-link>
|
||
|
|
</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>
|
||
|
|
|
||
|
|
<!-- Customer profile boxes -->
|
||
|
|
<swp-drawer-section>
|
||
|
|
<swp-section-label>Profil</swp-section-label>
|
||
|
|
<swp-profile-boxes>
|
||
|
|
<swp-profile-box>
|
||
|
|
<swp-profile-box-label>Hårtype</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Medium • Bølget</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
<swp-profile-box>
|
||
|
|
<swp-profile-box-label>Porøsitet</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Medium</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
<swp-profile-box>
|
||
|
|
<swp-profile-box-label>Præference</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Kold tone, ikke for mørk</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
<swp-profile-box class="warning">
|
||
|
|
<swp-profile-box-label>Advarsler</swp-profile-box-label>
|
||
|
|
<swp-profile-box-value>Parfume-allergi • Sensitiv hovedbund</swp-profile-box-value>
|
||
|
|
</swp-profile-box>
|
||
|
|
</swp-profile-boxes>
|
||
|
|
<swp-journal-details-link id="journalLink" onclick="toggleJournal()">Se journal <img src="icons/angle-small-right.svg" class="link-chevron" alt=""></swp-journal-details-link>
|
||
|
|
</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 chevronImg = '<img src="icons/angle-small-right.svg" class="link-chevron" alt="">';
|
||
|
|
|
||
|
|
if (hasJournal) {
|
||
|
|
journalLink.classList.remove('no-journal');
|
||
|
|
journalLink.innerHTML = 'Se journal ' + chevronImg;
|
||
|
|
} else {
|
||
|
|
journalLink.classList.add('no-journal');
|
||
|
|
journalLink.innerHTML = '+ 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.getElementById('journalPanel').classList.remove('open');
|
||
|
|
document.getElementById('customerPanel').classList.remove('open');
|
||
|
|
document.getElementById('addNotePanel').classList.remove('open');
|
||
|
|
document.getElementById('journalLink').classList.remove('panel-open');
|
||
|
|
document.getElementById('customerDetailsLink').classList.remove('panel-open');
|
||
|
|
}
|
||
|
|
|
||
|
|
function toggleJournal() {
|
||
|
|
const journalLink = document.getElementById('journalLink');
|
||
|
|
// Don't open journal if it's the "create" state
|
||
|
|
if (journalLink.classList.contains('no-journal')) {
|
||
|
|
// Could show create journal flow here
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const journalPanel = document.getElementById('journalPanel');
|
||
|
|
journalPanel.classList.toggle('open');
|
||
|
|
journalLink.classList.toggle('panel-open', journalPanel.classList.contains('open'));
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeJournal() {
|
||
|
|
document.getElementById('journalPanel').classList.remove('open');
|
||
|
|
document.getElementById('journalLink').classList.remove('panel-open');
|
||
|
|
closeAddNote();
|
||
|
|
closeFarveformel();
|
||
|
|
closeAnalyse();
|
||
|
|
}
|
||
|
|
|
||
|
|
function switchJournalTab(tabName) {
|
||
|
|
// Update tab buttons
|
||
|
|
document.querySelectorAll('swp-journal-tab[data-tab]').forEach(tab => {
|
||
|
|
tab.classList.toggle('active', tab.dataset.tab === tabName);
|
||
|
|
});
|
||
|
|
// Update tab content
|
||
|
|
document.getElementById('tabNoter').classList.toggle('active', tabName === 'noter');
|
||
|
|
document.getElementById('tabFarveformler').classList.toggle('active', tabName === 'farveformler');
|
||
|
|
document.getElementById('tabAnalyse').classList.toggle('active', tabName === 'analyse');
|
||
|
|
// Close any open panels
|
||
|
|
closeAddNote();
|
||
|
|
closeFarveformel();
|
||
|
|
closeAnalyse();
|
||
|
|
}
|
||
|
|
|
||
|
|
function openAddNote() {
|
||
|
|
document.getElementById('addNotePanel').classList.add('open');
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeAddNote() {
|
||
|
|
document.getElementById('addNotePanel').classList.remove('open');
|
||
|
|
hidePreview();
|
||
|
|
resetAddNoteForm();
|
||
|
|
}
|
||
|
|
|
||
|
|
function toggleJournalProfile() {
|
||
|
|
const toggle = document.querySelector('swp-journal-profile-toggle');
|
||
|
|
const boxes = document.getElementById('journalProfileBoxes');
|
||
|
|
toggle.classList.toggle('collapsed');
|
||
|
|
boxes.classList.toggle('collapsed');
|
||
|
|
}
|
||
|
|
|
||
|
|
function openCustomerPanel() {
|
||
|
|
const panel = document.getElementById('customerPanel');
|
||
|
|
const link = document.getElementById('customerDetailsLink');
|
||
|
|
const isOpen = panel.classList.contains('open');
|
||
|
|
|
||
|
|
if (isOpen) {
|
||
|
|
panel.classList.remove('open');
|
||
|
|
link.classList.remove('panel-open');
|
||
|
|
} else {
|
||
|
|
panel.classList.add('open');
|
||
|
|
link.classList.add('panel-open');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeCustomerPanel() {
|
||
|
|
document.getElementById('customerPanel').classList.remove('open');
|
||
|
|
document.getElementById('customerDetailsLink').classList.remove('panel-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();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add note tags: multi-select (toggle) + update preview
|
||
|
|
document.querySelectorAll('swp-add-note-tag-option').forEach(tag => {
|
||
|
|
tag.onclick = () => {
|
||
|
|
tag.classList.toggle('selected');
|
||
|
|
updatePreviewTags();
|
||
|
|
};
|
||
|
|
});
|
||
|
|
|
||
|
|
// Live Preview Logic
|
||
|
|
const addNoteTextarea = document.querySelector('swp-add-note-content textarea');
|
||
|
|
const previewEntry = document.getElementById('previewEntry');
|
||
|
|
const previewText = document.getElementById('previewText');
|
||
|
|
const previewTags = document.getElementById('previewTags');
|
||
|
|
const previewVisibility = document.getElementById('previewVisibility');
|
||
|
|
const previewMarking = document.getElementById('previewMarking');
|
||
|
|
const visibilitySelect = document.querySelector('swp-add-note-dropdown-group:nth-child(1) select');
|
||
|
|
const markingSelect = document.querySelector('swp-add-note-dropdown-group:nth-child(2) select');
|
||
|
|
|
||
|
|
// Show preview on textarea focus
|
||
|
|
addNoteTextarea.addEventListener('focus', showPreview);
|
||
|
|
|
||
|
|
// Update visibility in preview
|
||
|
|
visibilitySelect.addEventListener('change', updatePreviewVisibility);
|
||
|
|
|
||
|
|
// Update marking in preview
|
||
|
|
markingSelect.addEventListener('change', updatePreviewMarking);
|
||
|
|
|
||
|
|
// Update preview text in real-time
|
||
|
|
addNoteTextarea.addEventListener('input', () => {
|
||
|
|
previewText.textContent = addNoteTextarea.value || '(Tom note)';
|
||
|
|
});
|
||
|
|
|
||
|
|
function showPreview() {
|
||
|
|
previewEntry.classList.remove('hidden');
|
||
|
|
updatePreviewTags();
|
||
|
|
}
|
||
|
|
|
||
|
|
function hidePreview() {
|
||
|
|
previewEntry.classList.add('hidden');
|
||
|
|
}
|
||
|
|
|
||
|
|
function updatePreviewTags() {
|
||
|
|
const selectedTags = document.querySelectorAll('swp-add-note-tag-option.selected');
|
||
|
|
previewTags.innerHTML = '';
|
||
|
|
selectedTags.forEach(tag => {
|
||
|
|
const tagEl = document.createElement('swp-journal-tag');
|
||
|
|
tagEl.textContent = tag.textContent;
|
||
|
|
tagEl.classList.add('tag-' + tag.dataset.tag);
|
||
|
|
previewTags.appendChild(tagEl);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function updatePreviewVisibility() {
|
||
|
|
const value = visibilitySelect.value;
|
||
|
|
const text = value === 'Kun mig' ? 'Kun dig' : 'Alle';
|
||
|
|
previewVisibility.querySelector('span').textContent = text;
|
||
|
|
}
|
||
|
|
|
||
|
|
function updatePreviewMarking() {
|
||
|
|
const value = markingSelect.value;
|
||
|
|
previewMarking.className = '';
|
||
|
|
|
||
|
|
if (value === 'Ingen') {
|
||
|
|
previewMarking.classList.add('hidden');
|
||
|
|
previewMarking.innerHTML = '';
|
||
|
|
} else if (value === 'Vigtigt') {
|
||
|
|
previewMarking.classList.add('important');
|
||
|
|
previewMarking.innerHTML = '<img src="icons/exclamation.svg" class="entry-icon" alt=""><span>Vigtigt</span>';
|
||
|
|
} else if (value === 'Advarsel') {
|
||
|
|
previewMarking.classList.add('warning');
|
||
|
|
previewMarking.innerHTML = '<img src="icons/warning.svg" class="entry-icon" alt=""><span>Advarsel</span>';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function resetAddNoteForm() {
|
||
|
|
addNoteTextarea.value = '';
|
||
|
|
previewText.textContent = '(Tom note)';
|
||
|
|
document.querySelectorAll('swp-add-note-tag-option').forEach(tag => {
|
||
|
|
if (tag.textContent === 'Fri note') {
|
||
|
|
tag.classList.add('selected');
|
||
|
|
} else {
|
||
|
|
tag.classList.remove('selected');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
visibilitySelect.value = 'Hele salonen';
|
||
|
|
markingSelect.value = 'Ingen';
|
||
|
|
updatePreviewTags();
|
||
|
|
updatePreviewVisibility();
|
||
|
|
updatePreviewMarking();
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==========================================
|
||
|
|
// FARVEFORMEL PANEL
|
||
|
|
// ==========================================
|
||
|
|
let activePanel = null; // 'note' or 'farveformel'
|
||
|
|
|
||
|
|
// Farveformel elements
|
||
|
|
const ffMaalTone = document.getElementById('ffMaalTone');
|
||
|
|
const ffOxidant = document.getElementById('ffOxidant');
|
||
|
|
const ffFormel = document.getElementById('ffFormel');
|
||
|
|
const ffBlandingsforhold = document.getElementById('ffBlandingsforhold');
|
||
|
|
const ffVirketid = document.getElementById('ffVirketid');
|
||
|
|
const ffPlacering = document.getElementById('ffPlacering');
|
||
|
|
const ffResultat = document.getElementById('ffResultat');
|
||
|
|
const previewType = document.querySelector('#previewEntry swp-journal-entry-type');
|
||
|
|
|
||
|
|
// Farveformel preview elements (in farveformler tab)
|
||
|
|
const previewEntryFarveformel = document.getElementById('previewEntryFarveformel');
|
||
|
|
const previewTextFarveformel = document.getElementById('previewTextFarveformel');
|
||
|
|
|
||
|
|
function openFarveformel() {
|
||
|
|
document.getElementById('farveformelPanel').classList.add('open');
|
||
|
|
activePanel = 'farveformel';
|
||
|
|
showFarveformelPreview();
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeFarveformel() {
|
||
|
|
document.getElementById('farveformelPanel').classList.remove('open');
|
||
|
|
hideFarveformelPreview();
|
||
|
|
resetFarveformelForm();
|
||
|
|
activePanel = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function showFarveformelPreview() {
|
||
|
|
previewEntryFarveformel.classList.remove('hidden');
|
||
|
|
updateFarveformelPreview();
|
||
|
|
}
|
||
|
|
|
||
|
|
function hideFarveformelPreview() {
|
||
|
|
previewEntryFarveformel.classList.add('hidden');
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateFarveformelPreview() {
|
||
|
|
const lines = [];
|
||
|
|
|
||
|
|
if (ffMaalTone.value) {
|
||
|
|
lines.push(`• Mål/tone: ${ffMaalTone.value}`);
|
||
|
|
}
|
||
|
|
if (ffOxidant.value) {
|
||
|
|
lines.push(`• Oxidant: <span class="mono">${ffOxidant.value}</span>`);
|
||
|
|
}
|
||
|
|
if (ffFormel.value) {
|
||
|
|
lines.push(`• Formel: <span class="mono">${ffFormel.value}</span>`);
|
||
|
|
} else {
|
||
|
|
lines.push(`• Formel: <span class="mono">(ikke angivet)</span>`);
|
||
|
|
}
|
||
|
|
if (ffBlandingsforhold.value) {
|
||
|
|
lines.push(`• Blanding: <span class="mono">${ffBlandingsforhold.value}</span>`);
|
||
|
|
}
|
||
|
|
if (ffVirketid.value) {
|
||
|
|
lines.push(`• Virketid: <span class="mono">${ffVirketid.value}</span>`);
|
||
|
|
}
|
||
|
|
if (ffPlacering.value) {
|
||
|
|
lines.push(`• Placering: ${ffPlacering.value}`);
|
||
|
|
}
|
||
|
|
if (ffResultat.value) {
|
||
|
|
lines.push(`<br>${ffResultat.value}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
previewTextFarveformel.innerHTML = lines.length > 0 ? lines.join('<br>') : '(Udfyld felter...)';
|
||
|
|
}
|
||
|
|
|
||
|
|
function resetFarveformelForm() {
|
||
|
|
ffMaalTone.value = '';
|
||
|
|
ffOxidant.value = '';
|
||
|
|
ffFormel.value = '';
|
||
|
|
ffBlandingsforhold.value = '';
|
||
|
|
ffVirketid.value = '';
|
||
|
|
ffPlacering.value = '';
|
||
|
|
ffResultat.value = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function saveFarveformel() {
|
||
|
|
// In a real app, this would save to backend
|
||
|
|
alert('Farveformel gemt!');
|
||
|
|
closeFarveformel();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add event listeners for farveformel fields
|
||
|
|
[ffMaalTone, ffOxidant, ffFormel, ffBlandingsforhold, ffVirketid, ffPlacering, ffResultat].forEach(el => {
|
||
|
|
el.addEventListener('input', () => {
|
||
|
|
if (activePanel === 'farveformel') {
|
||
|
|
updateFarveformelPreview();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
el.addEventListener('change', () => {
|
||
|
|
if (activePanel === 'farveformel') {
|
||
|
|
updateFarveformelPreview();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Update original openAddNote to track active panel
|
||
|
|
const originalOpenAddNote = openAddNote;
|
||
|
|
openAddNote = function() {
|
||
|
|
originalOpenAddNote();
|
||
|
|
activePanel = 'note';
|
||
|
|
};
|
||
|
|
|
||
|
|
// Update original closeAddNote to clear active panel
|
||
|
|
const originalCloseAddNote = closeAddNote;
|
||
|
|
closeAddNote = function() {
|
||
|
|
originalCloseAddNote();
|
||
|
|
activePanel = null;
|
||
|
|
};
|
||
|
|
|
||
|
|
// ==========================================
|
||
|
|
// ANALYSE PANEL
|
||
|
|
// ==========================================
|
||
|
|
|
||
|
|
// Analyse form elements
|
||
|
|
const anHovedbund = document.getElementById('anHovedbund');
|
||
|
|
const anIrritation = document.getElementById('anIrritation');
|
||
|
|
const anHaarTykkelse = document.getElementById('anHaarTykkelse');
|
||
|
|
const anHaarStruktur = document.getElementById('anHaarStruktur');
|
||
|
|
const anPorositet = document.getElementById('anPorositet');
|
||
|
|
const anKemisk = document.getElementById('anKemisk');
|
||
|
|
const anShampoo = document.getElementById('anShampoo');
|
||
|
|
const anHjemmepleje = document.getElementById('anHjemmepleje');
|
||
|
|
const anBemaerkning = document.getElementById('anBemaerkning');
|
||
|
|
const anAdvarsel = document.getElementById('anAdvarsel');
|
||
|
|
|
||
|
|
// Analyse preview elements
|
||
|
|
const previewEntryAnalyse = document.getElementById('previewEntryAnalyse');
|
||
|
|
const previewTextAnalyse = document.getElementById('previewTextAnalyse');
|
||
|
|
const previewTagsAnalyse = document.getElementById('previewTagsAnalyse');
|
||
|
|
|
||
|
|
function openAnalyse() {
|
||
|
|
document.getElementById('analysePanel').classList.add('open');
|
||
|
|
activePanel = 'analyse';
|
||
|
|
showAnalysePreview();
|
||
|
|
}
|
||
|
|
|
||
|
|
function closeAnalyse() {
|
||
|
|
document.getElementById('analysePanel').classList.remove('open');
|
||
|
|
hideAnalysePreview();
|
||
|
|
resetAnalyseForm();
|
||
|
|
activePanel = null;
|
||
|
|
}
|
||
|
|
|
||
|
|
function showAnalysePreview() {
|
||
|
|
previewEntryAnalyse.classList.remove('hidden');
|
||
|
|
updateAnalysePreview();
|
||
|
|
updateAnalysePreviewTags();
|
||
|
|
}
|
||
|
|
|
||
|
|
function hideAnalysePreview() {
|
||
|
|
previewEntryAnalyse.classList.add('hidden');
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateAnalysePreview() {
|
||
|
|
const lines = [];
|
||
|
|
|
||
|
|
if (anHovedbund.value) {
|
||
|
|
lines.push(`• Hovedbund: ${anHovedbund.value}`);
|
||
|
|
}
|
||
|
|
if (anIrritation.value) {
|
||
|
|
lines.push(`• Irritation: ${anIrritation.value}`);
|
||
|
|
}
|
||
|
|
if (anHaarTykkelse.value || anHaarStruktur.value) {
|
||
|
|
const haarParts = [];
|
||
|
|
if (anHaarTykkelse.value) haarParts.push(anHaarTykkelse.value);
|
||
|
|
if (anHaarStruktur.value) haarParts.push(anHaarStruktur.value);
|
||
|
|
lines.push(`• Hår: <span class="mono">${haarParts.join(' · ')}</span>`);
|
||
|
|
}
|
||
|
|
if (anPorositet.value) {
|
||
|
|
lines.push(`• Porøsitet: <span class="mono">${anPorositet.value}</span>`);
|
||
|
|
}
|
||
|
|
if (anKemisk.value) {
|
||
|
|
lines.push(`• Kemisk beh.: ${anKemisk.value}`);
|
||
|
|
}
|
||
|
|
if (anShampoo.value) {
|
||
|
|
lines.push(`• Shampoo: ${anShampoo.value}`);
|
||
|
|
}
|
||
|
|
if (anHjemmepleje.value) {
|
||
|
|
lines.push(`• Hjemmepleje: ${anHjemmepleje.value}`);
|
||
|
|
}
|
||
|
|
if (anBemaerkning.value) {
|
||
|
|
lines.push(`<br>${anBemaerkning.value}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
previewTextAnalyse.innerHTML = lines.length > 0 ? lines.join('<br>') : '(Udfyld felter...)';
|
||
|
|
}
|
||
|
|
|
||
|
|
function updateAnalysePreviewTags() {
|
||
|
|
const analysePanelTags = document.querySelectorAll('#analysePanel swp-add-note-tag-option.selected');
|
||
|
|
previewTagsAnalyse.innerHTML = '';
|
||
|
|
analysePanelTags.forEach(tag => {
|
||
|
|
const tagEl = document.createElement('swp-journal-tag');
|
||
|
|
tagEl.textContent = tag.textContent;
|
||
|
|
tagEl.classList.add('tag-' + tag.dataset.tag);
|
||
|
|
previewTagsAnalyse.appendChild(tagEl);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function resetAnalyseForm() {
|
||
|
|
anHovedbund.value = '';
|
||
|
|
anIrritation.value = '';
|
||
|
|
anHaarTykkelse.value = '';
|
||
|
|
anHaarStruktur.value = '';
|
||
|
|
anPorositet.value = '';
|
||
|
|
anKemisk.value = '';
|
||
|
|
anShampoo.value = '';
|
||
|
|
anHjemmepleje.value = '';
|
||
|
|
anBemaerkning.value = '';
|
||
|
|
anAdvarsel.value = 'Nej';
|
||
|
|
|
||
|
|
// Reset tags - only "Analyse" selected by default
|
||
|
|
document.querySelectorAll('#analysePanel swp-add-note-tag-option').forEach(tag => {
|
||
|
|
if (tag.dataset.tag === 'analyse') {
|
||
|
|
tag.classList.add('selected');
|
||
|
|
} else {
|
||
|
|
tag.classList.remove('selected');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
function saveAnalyse() {
|
||
|
|
// In a real app, this would save to backend
|
||
|
|
alert('Analyse gemt!');
|
||
|
|
closeAnalyse();
|
||
|
|
}
|
||
|
|
|
||
|
|
// Add event listeners for analyse form fields
|
||
|
|
[anHovedbund, anIrritation, anHaarTykkelse, anHaarStruktur, anPorositet, anKemisk, anShampoo, anHjemmepleje, anBemaerkning, anAdvarsel].forEach(el => {
|
||
|
|
el.addEventListener('input', () => {
|
||
|
|
if (activePanel === 'analyse') {
|
||
|
|
updateAnalysePreview();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
el.addEventListener('change', () => {
|
||
|
|
if (activePanel === 'analyse') {
|
||
|
|
updateAnalysePreview();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
});
|
||
|
|
|
||
|
|
// Add tag toggle listeners for analyse panel
|
||
|
|
document.querySelectorAll('#analysePanel swp-add-note-tag-option').forEach(tag => {
|
||
|
|
tag.onclick = () => {
|
||
|
|
tag.classList.toggle('selected');
|
||
|
|
updateAnalysePreviewTags();
|
||
|
|
};
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<!-- Chart initialization -->
|
||
|
|
<script type="module">
|
||
|
|
import { createChart } from 'https://unpkg.com/@sevenweirdpeople/swp-charting@latest/dist/index.js';
|
||
|
|
|
||
|
|
// Initialize chart when customer panel opens
|
||
|
|
let chartInitialized = false;
|
||
|
|
|
||
|
|
const originalOpenCustomerPanel = window.openCustomerPanel;
|
||
|
|
window.openCustomerPanel = function() {
|
||
|
|
originalOpenCustomerPanel();
|
||
|
|
|
||
|
|
if (!chartInitialized) {
|
||
|
|
setTimeout(() => {
|
||
|
|
createChart(document.getElementById('customerRevenueChart'), {
|
||
|
|
width: 620,
|
||
|
|
height: 215,
|
||
|
|
xAxis: {
|
||
|
|
categories: ['Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec']
|
||
|
|
},
|
||
|
|
series: [
|
||
|
|
{
|
||
|
|
name: 'Services',
|
||
|
|
color: '#00897b',
|
||
|
|
data: [
|
||
|
|
{ x: 'Jul', y: 1200 },
|
||
|
|
{ x: 'Sep', y: 1500 },
|
||
|
|
{ x: 'Okt', y: 2800 },
|
||
|
|
{ x: 'Dec', y: 1800 }
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'Produkter',
|
||
|
|
color: '#1e88e5',
|
||
|
|
data: [
|
||
|
|
{ x: 'Aug', y: 800 },
|
||
|
|
{ x: 'Okt', y: 900 },
|
||
|
|
{ x: 'Nov', y: 700 },
|
||
|
|
{ x: 'Dec', y: 950 }
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
legend: true
|
||
|
|
});
|
||
|
|
chartInitialized = true;
|
||
|
|
}, 100);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|