PlanTempusApp/.workbench/POC/poc-service-detail.html
2026-02-03 19:12:45 +01:00

2521 lines
78 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="da">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Service Detaljer - Klip & Farve</title>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* ==========================================
FONT FACE (Poppins)
========================================== */
@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;
}
/* ==========================================
CSS VARIABLES (Design System)
========================================== */
:root {
/* Colors */
--color-surface: #fff;
--color-background: #f5f5f5;
--color-background-hover: #f0f0f0;
--color-background-alt: #fafafa;
--color-border: #e0e0e0;
--color-text: #333;
--color-text-secondary: #666;
--color-teal: #00897b;
--color-blue: #1976d2;
--color-red: #e53935;
--color-amber: #ffb300;
--color-purple: #8b5cf6;
--color-green: #43a047;
/* Calendar colors */
--b-color-red: #e53935;
--b-color-pink: #d81b60;
--b-color-magenta: #c2185b;
--b-color-purple: #8e24aa;
--b-color-violet: #7b1fa2;
--b-color-deep-purple: #5e35b1;
--b-color-indigo: #3949ab;
--b-color-blue: #1e88e5;
--b-color-light-blue: #039be5;
--b-color-cyan: #00acc1;
--b-color-teal: #00897b;
--b-color-green: #43a047;
--b-color-light-green: #7cb342;
--b-color-lime: #c0ca33;
--b-color-yellow: #fdd835;
--b-color-amber: #ffb300;
--b-color-orange: #fb8c00;
--b-color-deep-orange: #f4511e;
/* Typography */
--font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-mono: 'JetBrains Mono', monospace;
}
/* ==========================================
RESET & BASE
========================================== */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font-family);
font-size: 14px;
color: var(--color-text);
background: var(--color-background);
line-height: 1.5;
}
/* ==========================================
TOPBAR
========================================== */
swp-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 24px;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 100;
}
swp-topbar-left {
display: flex;
align-items: center;
gap: 16px;
}
swp-back-link {
display: flex;
align-items: center;
gap: 6px;
color: var(--color-text-secondary);
text-decoration: none;
font-size: 13px;
cursor: pointer;
transition: color 150ms ease;
}
swp-back-link:hover {
color: var(--color-teal);
}
swp-back-link svg {
width: 16px;
height: 16px;
fill: currentColor;
}
swp-topbar-title {
font-size: 16px;
font-weight: 600;
color: var(--color-text);
}
swp-topbar-actions {
display: flex;
align-items: center;
gap: 12px;
}
swp-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
font-size: 13px;
font-weight: 500;
border-radius: 6px;
border: none;
cursor: pointer;
transition: all 150ms ease;
}
swp-btn.primary {
background: var(--color-teal);
color: white;
}
swp-btn.primary:hover {
background: #00796b;
}
swp-btn.secondary {
background: var(--color-surface);
color: var(--color-text);
border: 1px solid var(--color-border);
}
swp-btn.secondary:hover {
background: var(--color-background);
}
/* ==========================================
SERVICE HEADER
========================================== */
swp-service-header {
display: flex;
gap: 24px;
padding: 24px;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 49px;
z-index: 90;
}
swp-service-info {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
}
swp-service-name-row {
display: flex;
align-items: center;
gap: 16px;
}
swp-service-name {
font-size: 24px;
font-weight: 600;
color: var(--color-text);
}
/* Tags */
swp-tags-editor {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
swp-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.3px;
border-radius: 4px;
background: var(--color-background);
color: var(--color-text-secondary);
}
swp-tag.active {
background: color-mix(in srgb, var(--color-green) 20%, white);
color: var(--color-green);
}
swp-tag.popular {
background: color-mix(in srgb, var(--color-amber) 20%, white);
color: #b8860b;
}
swp-tag.combo {
background: color-mix(in srgb, var(--color-teal) 15%, white);
color: var(--color-teal);
}
swp-tag.color {
background: color-mix(in srgb, var(--color-purple) 15%, white);
color: var(--color-purple);
}
swp-tag .remove {
cursor: pointer;
opacity: 0.6;
margin-left: 2px;
}
swp-tag .remove:hover {
opacity: 1;
}
swp-tag-add {
display: inline-flex;
align-items: center;
padding: 4px 10px;
font-size: 11px;
font-weight: 500;
color: var(--color-text-secondary);
border: 1px dashed var(--color-border);
border-radius: 4px;
cursor: pointer;
transition: all 150ms ease;
}
swp-tag-add:hover {
border-color: var(--color-teal);
color: var(--color-teal);
}
/* Service Status Toggle (like booking exclusion) */
swp-service-status {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
font-size: 12px;
font-weight: 500;
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
margin-left: auto;
}
swp-service-status[data-active="true"] {
background: color-mix(in srgb, var(--color-green) 15%, white);
color: var(--color-green);
border: 1px solid color-mix(in srgb, var(--color-green) 30%, white);
}
swp-service-status[data-active="false"] {
background: color-mix(in srgb, var(--color-red) 12%, white);
color: var(--color-red);
border: 1px solid color-mix(in srgb, var(--color-red) 30%, white);
}
swp-service-status .icon {
font-size: 14px;
}
/* Fact Boxes Inline (same as customer detail) */
swp-fact-boxes-inline {
display: flex;
gap: 24px;
margin-top: 4px;
}
swp-fact-inline {
display: flex;
align-items: baseline;
gap: 6px;
}
swp-fact-inline-value {
font-size: 18px;
font-weight: 600;
font-family: var(--font-mono);
color: var(--color-text);
}
swp-fact-inline-label {
font-size: 12px;
color: var(--color-text-secondary);
}
/* ==========================================
TAB BAR
========================================== */
swp-tab-bar {
display: flex;
gap: 0;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
padding: 0 24px;
position: sticky;
top: 178px;
z-index: 80;
}
swp-tab {
padding: 14px 24px;
font-size: 14px;
font-weight: 500;
color: var(--color-text-secondary);
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: all 150ms ease;
}
swp-tab:hover {
color: var(--color-text);
background: var(--color-background-alt);
}
swp-tab.active {
color: var(--color-teal);
border-bottom-color: var(--color-teal);
}
/* ==========================================
TAB CONTENT
========================================== */
swp-tab-content {
display: none;
padding: 24px;
max-width: 1200px;
margin: 0 auto;
}
swp-tab-content.active {
display: block;
}
/* ==========================================
LAYOUT GRID
========================================== */
.grid-2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
}
.grid-4 {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
}
@media (max-width: 900px) {
.grid-2 {
grid-template-columns: 1fr;
}
.grid-4 {
grid-template-columns: repeat(2, 1fr);
}
}
/* ==========================================
CARDS
========================================== */
swp-card {
display: block;
background: var(--color-surface);
border-radius: 8px;
padding: 20px;
border: 1px solid var(--color-border);
margin-bottom: 16px;
}
swp-card:last-child {
margin-bottom: 0;
}
/* Section Label */
swp-section-label {
display: block;
font-size: 11px;
font-weight: 600;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 16px;
}
/* ==========================================
STAT CARDS
========================================== */
swp-stat-card {
background: var(--color-surface);
border-radius: 8px;
padding: 20px;
text-align: center;
border: 1px solid var(--color-border);
}
swp-stat-value {
display: block;
font-size: 28px;
font-weight: 600;
font-family: var(--font-mono);
color: var(--color-text);
}
swp-stat-label {
display: block;
font-size: 12px;
color: var(--color-text-secondary);
margin-top: 4px;
}
swp-stat-card.highlight swp-stat-value {
color: var(--color-teal);
}
/* ==========================================
EDIT SECTION
========================================== */
swp-edit-section {
display: flex;
flex-direction: column;
gap: 12px;
}
swp-edit-row {
display: grid;
grid-template-columns: 140px 1fr;
align-items: center;
gap: 12px;
}
swp-edit-label {
font-size: 13px;
color: var(--color-text-secondary);
}
swp-edit-value {
font-size: 14px;
padding: 8px 12px;
border-radius: 4px;
background: var(--color-background-alt);
border: 1px solid transparent;
transition: all 150ms ease;
cursor: text;
}
swp-edit-value:hover {
background: var(--color-background);
}
swp-edit-value:focus {
outline: none;
background: var(--color-surface);
border-color: var(--color-teal);
}
swp-edit-value[contenteditable="true"] {
cursor: text;
}
/* Select dropdown styling */
swp-edit-select {
display: block;
}
swp-edit-select select {
width: 100%;
font-size: 14px;
font-family: inherit;
padding: 8px 12px;
border-radius: 4px;
background: var(--color-background-alt);
border: 1px solid transparent;
cursor: pointer;
transition: all 150ms ease;
}
swp-edit-select select:hover {
background: var(--color-background);
}
swp-edit-select select:focus {
outline: none;
background: var(--color-surface);
border-color: var(--color-teal);
}
/* Textarea styling */
swp-edit-textarea {
display: block;
width: 100%;
min-height: 80px;
font-size: 14px;
font-family: inherit;
padding: 12px;
border-radius: 4px;
background: var(--color-background-alt);
border: 1px solid transparent;
resize: vertical;
transition: all 150ms ease;
}
swp-edit-textarea:hover {
background: var(--color-background);
}
swp-edit-textarea:focus {
outline: none;
background: var(--color-surface);
border-color: var(--color-teal);
}
/* ==========================================
TOGGLE SLIDER (Ja/Nej)
========================================== */
swp-toggle-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px 0;
border-bottom: 1px solid var(--color-border);
}
swp-toggle-row:last-child {
border-bottom: none;
}
swp-toggle-label {
font-size: 14px;
color: var(--color-text);
}
swp-toggle-description {
display: block;
font-size: 12px;
color: var(--color-text-secondary);
margin-top: 2px;
}
swp-toggle-slider {
display: inline-flex;
width: fit-content;
background: var(--color-background);
border-radius: 6px;
border: 1px solid var(--color-border);
overflow: hidden;
position: relative;
}
swp-toggle-slider::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
width: calc(50% - 4px);
height: calc(100% - 4px);
background: color-mix(in srgb, var(--color-green) 18%, white);
border-radius: 4px;
transition: transform 200ms ease, background 200ms ease;
}
swp-toggle-slider[data-value="no"]::before {
transform: translateX(100%);
background: color-mix(in srgb, var(--color-red) 18%, white);
}
swp-toggle-option {
position: relative;
z-index: 1;
padding: 5px 16px;
font-size: 12px;
font-weight: 500;
color: var(--color-text-secondary);
cursor: pointer;
transition: color 150ms ease;
user-select: none;
}
swp-toggle-slider[data-value="yes"] swp-toggle-option:first-child {
color: var(--color-green);
font-weight: 600;
}
swp-toggle-slider[data-value="no"] swp-toggle-option:last-child {
color: var(--color-red);
font-weight: 600;
}
/* ==========================================
PRICE MATRIX
========================================== */
swp-price-matrix {
display: block;
overflow-x: auto;
margin-top: 16px;
}
swp-price-matrix table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
swp-price-matrix th,
swp-price-matrix td {
padding: 12px 16px;
text-align: center;
border: 1px solid var(--color-border);
}
swp-price-matrix th {
background: var(--color-background);
font-weight: 600;
color: var(--color-text-secondary);
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.3px;
}
swp-price-matrix th:first-child,
swp-price-matrix td:first-child {
text-align: left;
}
swp-price-matrix td:first-child {
font-weight: 500;
background: var(--color-background-alt);
}
swp-price-matrix td span {
font-family: var(--font-mono);
}
swp-price-matrix td span[contenteditable="true"] {
display: inline-block;
min-width: 60px;
padding: 4px 8px;
border-radius: 4px;
background: var(--color-surface);
border: 1px solid var(--color-border);
cursor: text;
}
swp-price-matrix td span[contenteditable="true"]:focus {
outline: none;
border-color: var(--color-teal);
}
/* Price mode toggle */
swp-price-mode {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
swp-price-mode-btn {
padding: 8px 16px;
font-size: 13px;
font-weight: 500;
border-radius: 6px;
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-text-secondary);
cursor: pointer;
transition: all 150ms ease;
}
swp-price-mode-btn.active {
background: var(--color-teal);
color: white;
border-color: var(--color-teal);
}
swp-price-mode-btn:hover:not(.active) {
background: var(--color-background);
}
/* Simple price view */
swp-price-simple {
display: block;
margin-top: 16px;
}
/* ==========================================
DURATION LIST
========================================== */
swp-duration-list {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-duration-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: var(--color-background-alt);
border-radius: 6px;
border: 1px solid var(--color-border);
}
swp-duration-name {
flex: 1;
font-weight: 500;
}
swp-duration-value {
display: flex;
align-items: center;
gap: 6px;
}
swp-duration-value span {
font-family: var(--font-mono);
min-width: 40px;
padding: 4px 8px;
border-radius: 4px;
background: var(--color-surface);
border: 1px solid var(--color-border);
text-align: right;
}
swp-duration-value span[contenteditable="true"]:focus {
outline: none;
border-color: var(--color-teal);
}
swp-duration-unit {
font-size: 13px;
color: var(--color-text-secondary);
}
swp-duration-delete {
padding: 4px 8px;
color: var(--color-text-secondary);
cursor: pointer;
border-radius: 4px;
transition: all 150ms ease;
}
swp-duration-delete:hover {
color: var(--color-red);
background: color-mix(in srgb, var(--color-red) 10%, white);
}
/* ==========================================
EMPLOYEE LIST
========================================== */
swp-employee-list {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-employee-item {
display: flex;
align-items: center;
gap: 16px;
padding: 16px;
background: var(--color-background-alt);
border-radius: 6px;
border: 1px solid var(--color-border);
cursor: pointer;
transition: border-color 0.15s ease;
}
swp-employee-item:hover {
border-color: var(--color-teal);
}
swp-employee-item.selected {
border-color: var(--color-teal);
background: color-mix(in srgb, var(--color-teal) 5%, var(--color-background-alt));
}
swp-employee-item.disabled {
opacity: 0.5;
pointer-events: none;
}
swp-employee-checkbox {
width: 20px;
height: 20px;
border: 2px solid var(--color-border);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.15s ease;
}
swp-employee-item.selected swp-employee-checkbox {
background: var(--color-teal);
border-color: var(--color-teal);
color: white;
}
swp-employee-checkbox svg {
width: 14px;
height: 14px;
fill: currentColor;
opacity: 0;
}
swp-employee-item.selected swp-employee-checkbox svg {
opacity: 1;
}
swp-employee-avatar {
width: 44px;
height: 44px;
border-radius: 50%;
background: linear-gradient(135deg, var(--color-teal) 0%, #00695c 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 600;
font-size: 14px;
flex-shrink: 0;
}
swp-employee-info {
flex: 1;
min-width: 0;
}
swp-employee-name {
font-weight: 500;
color: var(--color-text);
}
swp-employee-info {
display: flex;
flex-direction: column;
align-items: flex-start;
}
swp-employee-level {
display: inline-flex;
font-size: 11px;
font-weight: 500;
padding: 3px 8px;
border-radius: 4px;
background: var(--color-background);
color: var(--color-text-secondary);
margin-top: 4px;
}
swp-employee-overrides {
display: flex;
gap: 16px;
font-size: 13px;
color: var(--color-text-secondary);
}
swp-employee-override-value {
color: var(--color-text);
font-weight: 500;
}
swp-employee-warning {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 10px;
font-weight: 500;
color: #b8860b;
background: color-mix(in srgb, var(--color-amber) 20%, white);
padding: 3px 8px;
border-radius: 10px;
margin-left: 8px;
}
/* ==========================================
ADDON LIST
========================================== */
swp-addon-list {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-addon-item {
display: flex;
align-items: center;
gap: 12px;
padding: 16px;
background: var(--color-background-alt);
border-radius: 6px;
border: 1px solid var(--color-border);
cursor: pointer;
transition: all 150ms ease;
}
swp-addon-item:hover {
background: var(--color-background);
}
swp-addon-item.selected {
border-color: var(--color-teal);
background: color-mix(in srgb, var(--color-teal) 5%, white);
}
swp-addon-checkbox {
width: 20px;
height: 20px;
border: 2px solid var(--color-border);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 150ms ease;
}
swp-addon-item.selected swp-addon-checkbox {
background: var(--color-teal);
border-color: var(--color-teal);
color: white;
}
swp-addon-checkbox svg {
width: 14px;
height: 14px;
fill: currentColor;
opacity: 0;
}
swp-addon-item.selected swp-addon-checkbox svg {
opacity: 1;
}
swp-addon-info {
flex: 1;
}
swp-addon-name {
font-weight: 500;
color: var(--color-text);
}
swp-addon-meta {
display: flex;
gap: 12px;
font-size: 13px;
color: var(--color-text-secondary);
margin-top: 4px;
}
swp-addon-price {
color: var(--color-teal);
font-weight: 500;
font-family: var(--font-mono);
}
swp-addon-type {
display: inline-block;
padding: 2px 8px;
background: color-mix(in srgb, var(--color-blue) 12%, white);
color: var(--color-blue);
border-radius: 10px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
}
swp-addon-type.required {
background: color-mix(in srgb, var(--color-amber) 15%, white);
color: #b8860b;
}
/* ==========================================
AVAILABILITY LIST
========================================== */
swp-availability-list {
display: flex;
flex-direction: column;
}
swp-availability-row {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px 16px;
padding: 12px 0;
border-bottom: 1px solid var(--color-border);
}
swp-availability-row:last-child {
border-bottom: none;
}
swp-availability-row[data-enabled="false"] {
opacity: 0.5;
}
swp-availability-day {
width: 100%;
font-size: 14px;
font-weight: 500;
color: var(--color-text);
}
swp-availability-time {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
swp-time-range {
display: flex;
align-items: center;
gap: 12px;
}
swp-time-range-slider {
position: relative;
flex: 1;
height: 20px;
display: flex;
align-items: center;
}
swp-time-range-track {
position: absolute;
width: 100%;
height: 4px;
background: var(--color-border);
border-radius: 2px;
}
swp-time-range-fill {
position: absolute;
height: 4px;
background: var(--color-teal);
border-radius: 2px;
cursor: grab;
}
swp-time-range-fill:active {
cursor: grabbing;
}
swp-time-range-fill.disabled {
pointer-events: none;
cursor: default;
}
swp-time-range-slider input[type="range"] {
position: absolute;
width: 100%;
height: 4px;
-webkit-appearance: none;
appearance: none;
background: transparent;
pointer-events: none;
margin: 0;
}
swp-time-range-slider input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
background: var(--color-teal);
border: 2px solid white;
border-radius: 50%;
cursor: pointer;
pointer-events: auto;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
swp-time-range-slider input[type="range"]::-moz-range-thumb {
width: 14px;
height: 14px;
background: var(--color-teal);
border: 2px solid white;
border-radius: 50%;
cursor: pointer;
pointer-events: auto;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
}
swp-time-range-label {
font-size: 12px;
font-family: var(--font-mono);
color: var(--color-text);
min-width: 90px;
text-align: center;
background: var(--color-background-alt);
padding: 3px 8px;
border-radius: 4px;
}
swp-availability-row[data-enabled="false"] swp-time-range-slider input[type="range"]::-webkit-slider-thumb {
background: var(--color-text-secondary);
}
swp-availability-row[data-enabled="false"] swp-time-range-fill {
background: var(--color-text-secondary);
}
swp-availability-row[data-enabled="false"] swp-time-range-label {
opacity: 0.5;
}
/* ==========================================
COLOR DROPDOWN (Popover)
========================================== */
swp-color-dropdown {
position: relative;
}
swp-color-dropdown button {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
font-size: 14px;
font-family: inherit;
border-radius: 4px;
background: var(--color-background-alt);
border: 1px solid transparent;
cursor: pointer;
transition: all 150ms ease;
min-width: 160px;
anchor-name: --color-trigger;
}
swp-color-dropdown button:hover {
background: var(--color-background);
}
swp-color-dropdown button .color-name {
flex: 1;
text-align: left;
}
swp-color-dropdown button .chevron {
opacity: 0.5;
}
swp-color-dropdown [popover] {
position: absolute;
position-anchor: --color-trigger;
top: anchor(bottom);
left: anchor(left);
margin: 4px 0 0 0;
padding: 6px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
min-width: 180px;
max-height: 280px;
overflow-y: auto;
}
swp-color-dropdown [popover]:popover-open {
display: flex;
flex-direction: column;
gap: 2px;
}
swp-color-option {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
transition: background 150ms ease;
font-size: 13px;
}
swp-color-option:hover {
background: var(--color-background);
}
swp-color-option.selected {
background: color-mix(in srgb, var(--color-teal) 12%, white);
font-weight: 500;
}
swp-color-dot {
width: 18px;
height: 12px;
border-radius: 3px;
flex-shrink: 0;
}
/* ==========================================
CUSTOM DROPDOWN (Popover)
========================================== */
swp-custom-dropdown {
position: relative;
}
swp-custom-dropdown button {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 12px;
font-size: 14px;
font-family: inherit;
border-radius: 4px;
background: var(--color-background-alt);
border: 1px solid transparent;
cursor: pointer;
transition: all 150ms ease;
min-width: 180px;
text-align: left;
anchor-name: --dropdown-trigger;
}
swp-custom-dropdown button:hover {
background: var(--color-background);
}
swp-custom-dropdown button .dropdown-value {
flex: 1;
}
swp-custom-dropdown button .chevron {
opacity: 0.5;
}
swp-custom-dropdown [popover] {
position: absolute;
position-anchor: --dropdown-trigger;
top: anchor(bottom);
left: anchor(left);
margin: 4px 0 0 0;
padding: 6px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 8px;
box-shadow: 0 4px 16px rgba(0,0,0,0.12);
min-width: 180px;
max-height: 280px;
overflow-y: auto;
}
swp-custom-dropdown [popover]:popover-open {
display: flex;
flex-direction: column;
gap: 2px;
}
swp-dropdown-option {
display: flex;
align-items: center;
padding: 8px 12px;
border-radius: 4px;
cursor: pointer;
transition: background 150ms ease;
font-size: 13px;
}
swp-dropdown-option:hover {
background: var(--color-background);
}
swp-dropdown-option.selected {
background: color-mix(in srgb, var(--color-teal) 12%, white);
font-weight: 500;
color: var(--color-teal);
}
/* Color classes */
swp-color-dot.is-red { background: var(--b-color-red); }
swp-color-dot.is-pink { background: var(--b-color-pink); }
swp-color-dot.is-magenta { background: var(--b-color-magenta); }
swp-color-dot.is-purple { background: var(--b-color-purple); }
swp-color-dot.is-violet { background: var(--b-color-violet); }
swp-color-dot.is-deep-purple { background: var(--b-color-deep-purple); }
swp-color-dot.is-indigo { background: var(--b-color-indigo); }
swp-color-dot.is-blue { background: var(--b-color-blue); }
swp-color-dot.is-light-blue { background: var(--b-color-light-blue); }
swp-color-dot.is-cyan { background: var(--b-color-cyan); }
swp-color-dot.is-teal { background: var(--b-color-teal); }
swp-color-dot.is-green { background: var(--b-color-green); }
swp-color-dot.is-light-green { background: var(--b-color-light-green); }
swp-color-dot.is-lime { background: var(--b-color-lime); }
swp-color-dot.is-yellow { background: var(--b-color-yellow); }
swp-color-dot.is-amber { background: var(--b-color-amber); }
swp-color-dot.is-orange { background: var(--b-color-orange); }
swp-color-dot.is-deep-orange { background: var(--b-color-deep-orange); }
/* ==========================================
ADD BUTTON
========================================== */
swp-add-button {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px;
border: 2px dashed var(--color-border);
border-radius: 6px;
color: var(--color-text-secondary);
font-size: 13px;
cursor: pointer;
transition: all 150ms ease;
margin-top: 12px;
}
swp-add-button:hover {
border-color: var(--color-teal);
color: var(--color-teal);
background: color-mix(in srgb, var(--color-teal) 5%, white);
}
/* ==========================================
SEE ALL LINK
========================================== */
swp-see-all {
display: block;
text-align: center;
padding: 12px;
font-size: 13px;
color: var(--color-teal);
cursor: pointer;
margin-top: 12px;
border-top: 1px solid var(--color-border);
}
swp-see-all:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<!-- Topbar -->
<swp-topbar>
<swp-topbar-left>
<swp-back-link>
<svg viewBox="0 0 24 24"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>
Tilbage til services
</swp-back-link>
<swp-topbar-title>Service detaljer</swp-topbar-title>
</swp-topbar-left>
<swp-topbar-actions>
<swp-btn class="secondary">Duplikér</swp-btn>
<swp-btn class="primary">Gem ændringer</swp-btn>
</swp-topbar-actions>
</swp-topbar>
<!-- Service Header -->
<swp-service-header>
<swp-service-info>
<swp-service-name-row>
<swp-service-name contenteditable="true">Klip & Farve</swp-service-name>
<swp-tags-editor>
<swp-tag class="popular">Populær</swp-tag>
<swp-tag class="combo">Kombi</swp-tag>
<swp-tag class="color">Farve</swp-tag>
<swp-tag-add>+ Tilføj tag</swp-tag-add>
</swp-tags-editor>
<swp-service-status data-active="true" id="serviceStatus">
<span class="icon"></span>
<span class="text">Aktiv</span>
</swp-service-status>
</swp-service-name-row>
<swp-fact-boxes-inline>
<swp-fact-inline>
<swp-fact-inline-value>60-120</swp-fact-inline-value>
<swp-fact-inline-label>min varighed</swp-fact-inline-label>
</swp-fact-inline>
<swp-fact-inline>
<swp-fact-inline-value>795 kr</swp-fact-inline-value>
<swp-fact-inline-label>fra pris</swp-fact-inline-label>
</swp-fact-inline>
<swp-fact-inline>
<swp-fact-inline-value>4</swp-fact-inline-value>
<swp-fact-inline-label>medarbejdere</swp-fact-inline-label>
</swp-fact-inline>
<swp-fact-inline>
<swp-fact-inline-value>156</swp-fact-inline-value>
<swp-fact-inline-label>bookinger i år</swp-fact-inline-label>
</swp-fact-inline>
</swp-fact-boxes-inline>
</swp-service-info>
</swp-service-header>
<!-- Tab Bar -->
<swp-tab-bar>
<swp-tab class="active" data-tab="general">Generelt</swp-tab>
<swp-tab data-tab="prices">Priser</swp-tab>
<swp-tab data-tab="duration">Varighed</swp-tab>
<swp-tab data-tab="employees">Medarbejdere</swp-tab>
<swp-tab data-tab="addons">Tilvalg</swp-tab>
<swp-tab data-tab="rules">Regler</swp-tab>
</swp-tab-bar>
<!-- ==========================================
GENERELT TAB
========================================== -->
<swp-tab-content class="active" data-tab="general">
<div class="grid-2">
<div>
<swp-card>
<swp-section-label>Grundlæggende</swp-section-label>
<swp-edit-section>
<swp-edit-row>
<swp-edit-label>Servicenavn</swp-edit-label>
<swp-edit-value contenteditable="true">Klip & Farve</swp-edit-value>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Kategori</swp-edit-label>
<swp-custom-dropdown>
<button type="button" popovertarget="categoryPopover" id="categoryTrigger">
<span class="dropdown-value">Kombi-behandlinger</span>
<svg class="chevron" viewBox="0 0 24 24" width="16" height="16"><path d="M7 10l5 5 5-5z" fill="currentColor"/></svg>
</button>
<div popover id="categoryPopover">
<swp-dropdown-option class="selected" data-value="kombi">Kombi-behandlinger</swp-dropdown-option>
<swp-dropdown-option data-value="klip">Klip</swp-dropdown-option>
<swp-dropdown-option data-value="farve">Farve</swp-dropdown-option>
<swp-dropdown-option data-value="behandlinger">Behandlinger</swp-dropdown-option>
<swp-dropdown-option data-value="styling">Styling</swp-dropdown-option>
</div>
</swp-custom-dropdown>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Farve i kalenderen</swp-edit-label>
<swp-color-dropdown>
<button type="button" popovertarget="colorPopover" id="colorTrigger">
<swp-color-dot class="is-deep-orange"></swp-color-dot>
<span class="color-name">Orange</span>
<svg class="chevron" viewBox="0 0 24 24" width="16" height="16"><path d="M7 10l5 5 5-5z" fill="currentColor"/></svg>
</button>
<div popover id="colorPopover">
<swp-color-option data-value="red" data-label="Rød"><swp-color-dot class="is-red"></swp-color-dot><span>Rød</span></swp-color-option>
<swp-color-option data-value="pink" data-label="Pink"><swp-color-dot class="is-pink"></swp-color-dot><span>Pink</span></swp-color-option>
<swp-color-option data-value="magenta" data-label="Magenta"><swp-color-dot class="is-magenta"></swp-color-dot><span>Magenta</span></swp-color-option>
<swp-color-option data-value="purple" data-label="Lilla"><swp-color-dot class="is-purple"></swp-color-dot><span>Lilla</span></swp-color-option>
<swp-color-option data-value="violet" data-label="Violet"><swp-color-dot class="is-violet"></swp-color-dot><span>Violet</span></swp-color-option>
<swp-color-option data-value="deep-purple" data-label="Mørk lilla"><swp-color-dot class="is-deep-purple"></swp-color-dot><span>Mørk lilla</span></swp-color-option>
<swp-color-option data-value="indigo" data-label="Indigo"><swp-color-dot class="is-indigo"></swp-color-dot><span>Indigo</span></swp-color-option>
<swp-color-option data-value="blue" data-label="Blå"><swp-color-dot class="is-blue"></swp-color-dot><span>Blå</span></swp-color-option>
<swp-color-option data-value="light-blue" data-label="Lyseblå"><swp-color-dot class="is-light-blue"></swp-color-dot><span>Lyseblå</span></swp-color-option>
<swp-color-option data-value="cyan" data-label="Cyan"><swp-color-dot class="is-cyan"></swp-color-dot><span>Cyan</span></swp-color-option>
<swp-color-option data-value="teal" data-label="Teal" class="selected"><swp-color-dot class="is-teal"></swp-color-dot><span>Teal</span></swp-color-option>
<swp-color-option data-value="green" data-label="Grøn"><swp-color-dot class="is-green"></swp-color-dot><span>Grøn</span></swp-color-option>
<swp-color-option data-value="light-green" data-label="Lysegrøn"><swp-color-dot class="is-light-green"></swp-color-dot><span>Lysegrøn</span></swp-color-option>
<swp-color-option data-value="lime" data-label="Lime"><swp-color-dot class="is-lime"></swp-color-dot><span>Lime</span></swp-color-option>
<swp-color-option data-value="yellow" data-label="Gul"><swp-color-dot class="is-yellow"></swp-color-dot><span>Gul</span></swp-color-option>
<swp-color-option data-value="amber" data-label="Amber"><swp-color-dot class="is-amber"></swp-color-dot><span>Amber</span></swp-color-option>
<swp-color-option data-value="orange" data-label="Orange"><swp-color-dot class="is-orange"></swp-color-dot><span>Orange</span></swp-color-option>
<swp-color-option data-value="deep-orange" data-label="Mørk orange"><swp-color-dot class="is-deep-orange"></swp-color-dot><span>Mørk orange</span></swp-color-option>
</div>
</swp-color-dropdown>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Service aktiv</swp-edit-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-edit-row>
</swp-edit-section>
<swp-section-label style="margin-top: 20px;">Interne noter</swp-section-label>
<swp-edit-textarea contenteditable="true">Komplet farvebehandling med klip. Husk konsultation ved første besøg. Anbefal Olaplex til kemisk behandlet hår.</swp-edit-textarea>
</swp-card>
<swp-card>
<swp-section-label>Bookingtype</swp-section-label>
<swp-toggle-row>
<div>
<swp-toggle-label>Kan bookes som hovedservice</swp-toggle-label>
<swp-toggle-description>Vises i servicelisten og kan bookes selvstændigt</swp-toggle-description>
</div>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<div>
<swp-toggle-label>Kan bookes som tilvalg</swp-toggle-label>
<swp-toggle-description>Kan tilføjes som ekstra ydelse til andre services</swp-toggle-description>
</div>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
</swp-card>
</div>
<div>
<swp-card>
<swp-section-label>Online booking</swp-section-label>
<swp-toggle-row>
<div>
<swp-toggle-label>Vis i online booking</swp-toggle-label>
<swp-toggle-description>Synlig for kunder i online booking</swp-toggle-description>
</div>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<div>
<swp-toggle-label>Fremhævet service</swp-toggle-label>
<swp-toggle-description>Vises øverst med fremhævet styling</swp-toggle-description>
</div>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-section-label style="margin-top: 20px;">Beskrivelse</swp-section-label>
<swp-edit-textarea contenteditable="true">Forkæl dig selv med en komplet forvandling! Vores Klip & Farve behandling inkluderer professionel farverådgivning, farvning tilpasset din hudtone, præcisionsklip og styling. Perfekt til dig der ønsker et helt nyt look.</swp-edit-textarea>
<swp-section-label style="margin-top: 20px;">Billede</swp-section-label>
<swp-add-button>+ Upload billede</swp-add-button>
</swp-card>
</div>
</div>
</swp-tab-content>
<!-- ==========================================
PRISER TAB
========================================== -->
<swp-tab-content data-tab="prices">
<swp-card>
<swp-section-label>Prisstruktur</swp-section-label>
<swp-price-mode>
<swp-price-mode-btn data-mode="simple">Simpel pris</swp-price-mode-btn>
<swp-price-mode-btn data-mode="matrix" class="active">Matrix-pris</swp-price-mode-btn>
</swp-price-mode>
<!-- Simpel pris visning -->
<swp-price-simple style="display: none;">
<swp-edit-section>
<swp-edit-row>
<swp-edit-label>Pris</swp-edit-label>
<swp-edit-value contenteditable="true">995 kr</swp-edit-value>
</swp-edit-row>
</swp-edit-section>
</swp-price-simple>
<!-- Matrix pris visning -->
<swp-price-matrix>
<table>
<thead>
<tr>
<th>Niveau</th>
<th>Kort hår</th>
<th>Mellem hår</th>
<th>Langt hår</th>
<th>Ekstra langt</th>
</tr>
</thead>
<tbody>
<tr>
<td>Junior</td>
<td><span contenteditable="true">795</span> kr</td>
<td><span contenteditable="true">895</span> kr</td>
<td><span contenteditable="true">995</span> kr</td>
<td><span contenteditable="true">1.095</span> kr</td>
</tr>
<tr>
<td>Senior</td>
<td><span contenteditable="true">895</span> kr</td>
<td><span contenteditable="true">995</span> kr</td>
<td><span contenteditable="true">1.095</span> kr</td>
<td><span contenteditable="true">1.195</span> kr</td>
</tr>
<tr>
<td>Master</td>
<td><span contenteditable="true">995</span> kr</td>
<td><span contenteditable="true">1.095</span> kr</td>
<td><span contenteditable="true">1.195</span> kr</td>
<td><span contenteditable="true">1.295</span> kr</td>
</tr>
</tbody>
</table>
<swp-add-button>+ Tilføj niveau eller hårlængde</swp-add-button>
</swp-price-matrix>
</swp-card>
<div class="grid-2">
<swp-card>
<swp-section-label>Økonomi</swp-section-label>
<swp-edit-section>
<swp-edit-row>
<swp-edit-label>Momssats</swp-edit-label>
<swp-edit-select>
<select>
<option selected>25% (standard)</option>
<option>0% (momsfri)</option>
</select>
</swp-edit-select>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Produktomkostning</swp-edit-label>
<swp-edit-value contenteditable="true">85 kr</swp-edit-value>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Provision</swp-edit-label>
<swp-edit-select>
<select>
<option selected>Standard (fra lønsats)</option>
<option>Fast beløb</option>
<option>Procent af pris</option>
</select>
</swp-edit-select>
</swp-edit-row>
</swp-edit-section>
</swp-card>
<swp-card>
<swp-section-label>Rabatter & Loyalitet</swp-section-label>
<swp-toggle-row>
<swp-toggle-label>Medlemsrabat (10%)</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<swp-toggle-label>Kan betales med gavekort</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<swp-toggle-label>Optjen loyalitetspoint</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
</swp-card>
</div>
</swp-tab-content>
<!-- ==========================================
VARIGHED TAB
========================================== -->
<swp-tab-content data-tab="duration">
<div class="grid-2">
<swp-card>
<swp-section-label>Varighedsvarianter</swp-section-label>
<swp-duration-list>
<swp-duration-item>
<swp-duration-name>Kort hår</swp-duration-name>
<swp-duration-value>
<span contenteditable="true">60</span>
<swp-duration-unit>min</swp-duration-unit>
</swp-duration-value>
<swp-duration-delete></swp-duration-delete>
</swp-duration-item>
<swp-duration-item>
<swp-duration-name>Mellem hår</swp-duration-name>
<swp-duration-value>
<span contenteditable="true">90</span>
<swp-duration-unit>min</swp-duration-unit>
</swp-duration-value>
<swp-duration-delete></swp-duration-delete>
</swp-duration-item>
<swp-duration-item>
<swp-duration-name>Langt hår</swp-duration-name>
<swp-duration-value>
<span contenteditable="true">120</span>
<swp-duration-unit>min</swp-duration-unit>
</swp-duration-value>
<swp-duration-delete></swp-duration-delete>
</swp-duration-item>
<swp-duration-item>
<swp-duration-name>Ekstra langt hår</swp-duration-name>
<swp-duration-value>
<span contenteditable="true">150</span>
<swp-duration-unit>min</swp-duration-unit>
</swp-duration-value>
<swp-duration-delete></swp-duration-delete>
</swp-duration-item>
</swp-duration-list>
<swp-add-button>+ Tilføj variant</swp-add-button>
</swp-card>
<swp-card>
<swp-section-label>Buffer-tider</swp-section-label>
<swp-edit-section>
<swp-edit-row>
<swp-edit-label>Buffer før aftale</swp-edit-label>
<swp-edit-select>
<select>
<option>Ingen</option>
<option>5 minutter</option>
<option>10 minutter</option>
<option selected>15 minutter</option>
<option>30 minutter</option>
</select>
</swp-edit-select>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Buffer efter aftale</swp-edit-label>
<swp-edit-select>
<select>
<option>Ingen</option>
<option>5 minutter</option>
<option selected>10 minutter</option>
<option>15 minutter</option>
<option>30 minutter</option>
</select>
</swp-edit-select>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Oprydningstid</swp-edit-label>
<swp-edit-select>
<select>
<option>Ingen</option>
<option selected>5 minutter</option>
<option>10 minutter</option>
<option>15 minutter</option>
</select>
</swp-edit-select>
</swp-edit-row>
</swp-edit-section>
</swp-card>
</div>
</swp-tab-content>
<!-- ==========================================
MEDARBEJDERE TAB
========================================== -->
<swp-tab-content data-tab="employees">
<div class="grid-2">
<div>
<swp-card>
<swp-section-label>Medarbejdere der udfører denne service</swp-section-label>
<swp-employee-list>
<swp-employee-item class="selected">
<swp-employee-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-employee-checkbox>
<swp-employee-avatar>AS</swp-employee-avatar>
<swp-employee-info>
<swp-employee-name>Anna Sørensen</swp-employee-name>
<swp-employee-level data-level="master">Master Stylist</swp-employee-level>
</swp-employee-info>
<swp-employee-overrides>
<span>Varighed: <swp-employee-override-value>Standard</swp-employee-override-value></span>
</swp-employee-overrides>
</swp-employee-item>
<swp-employee-item class="selected">
<swp-employee-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-employee-checkbox>
<swp-employee-avatar>MJ</swp-employee-avatar>
<swp-employee-info>
<swp-employee-name>Mette Jensen</swp-employee-name>
<swp-employee-level data-level="senior">Senior Stylist</swp-employee-level>
</swp-employee-info>
<swp-employee-overrides>
<span>Varighed: <swp-employee-override-value>+15 min</swp-employee-override-value></span>
</swp-employee-overrides>
</swp-employee-item>
<swp-employee-item class="selected">
<swp-employee-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-employee-checkbox>
<swp-employee-avatar>LN</swp-employee-avatar>
<swp-employee-info>
<swp-employee-name>Louise Nielsen</swp-employee-name>
<swp-employee-level data-level="senior">Senior Stylist</swp-employee-level>
</swp-employee-info>
<swp-employee-overrides>
<span>Varighed: <swp-employee-override-value>Standard</swp-employee-override-value></span>
</swp-employee-overrides>
</swp-employee-item>
<swp-employee-item class="selected">
<swp-employee-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-employee-checkbox>
<swp-employee-avatar>KP</swp-employee-avatar>
<swp-employee-info>
<swp-employee-name>Katrine Pedersen</swp-employee-name>
<swp-employee-level data-level="stylist">Stylist</swp-employee-level>
</swp-employee-info>
<swp-employee-overrides>
<span>Varighed: <swp-employee-override-value>+15 min</swp-employee-override-value></span>
</swp-employee-overrides>
</swp-employee-item>
<swp-employee-item class="disabled">
<swp-employee-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-employee-checkbox>
<swp-employee-avatar>SA</swp-employee-avatar>
<swp-employee-info>
<swp-employee-name>Sofie Andersen<swp-employee-warning>⚠ Ikke certificeret</swp-employee-warning></swp-employee-name>
<swp-employee-level data-level="junior">Junior Stylist</swp-employee-level>
</swp-employee-info>
<swp-employee-overrides>
<span>Varighed: <swp-employee-override-value></swp-employee-override-value></span>
</swp-employee-overrides>
</swp-employee-item>
</swp-employee-list>
<swp-see-all>Vælg alle / Fravælg alle</swp-see-all>
</swp-card>
</div>
<div>
<swp-card>
<swp-section-label>Tilgængelighed</swp-section-label>
<swp-availability-list>
<swp-availability-row data-enabled="true">
<swp-availability-day>Mandag</swp-availability-day>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
</swp-time-range-slider>
<swp-time-range-label>08:00 18:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
<swp-availability-row data-enabled="true">
<swp-availability-day>Tirsdag</swp-availability-day>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
</swp-time-range-slider>
<swp-time-range-label>08:00 18:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
<swp-availability-row data-enabled="true">
<swp-availability-day>Onsdag</swp-availability-day>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
</swp-time-range-slider>
<swp-time-range-label>08:00 18:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
<swp-availability-row data-enabled="true">
<swp-availability-day>Torsdag</swp-availability-day>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
<input type="range" class="range-end" min="0" max="60" value="24" step="1">
</swp-time-range-slider>
<swp-time-range-label>08:00 12:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
<swp-availability-row data-enabled="true">
<swp-availability-day>Fredag</swp-availability-day>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
</swp-time-range-slider>
<swp-time-range-label>08:00 18:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
<swp-availability-row data-enabled="false">
<swp-availability-day>Lørdag</swp-availability-day>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1" disabled>
<input type="range" class="range-end" min="0" max="60" value="48" step="1" disabled>
</swp-time-range-slider>
<swp-time-range-label>08:00 18:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
<swp-availability-row data-enabled="false">
<swp-availability-day>Søndag</swp-availability-day>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
<swp-availability-time>
<swp-time-range>
<swp-time-range-slider>
<swp-time-range-track></swp-time-range-track>
<swp-time-range-fill></swp-time-range-fill>
<input type="range" class="range-start" min="0" max="60" value="8" step="1" disabled>
<input type="range" class="range-end" min="0" max="60" value="48" step="1" disabled>
</swp-time-range-slider>
<swp-time-range-label>08:00 18:00</swp-time-range-label>
</swp-time-range>
</swp-availability-time>
</swp-availability-row>
</swp-availability-list>
</swp-card>
</div>
</div>
</swp-tab-content>
<!-- ==========================================
TILVALG TAB
========================================== -->
<swp-tab-content data-tab="addons">
<swp-card>
<swp-section-label>Tilvalg til denne service</swp-section-label>
<swp-addon-list>
<swp-addon-item class="selected">
<swp-addon-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-addon-checkbox>
<swp-addon-info>
<swp-addon-name>Olaplex Behandling</swp-addon-name>
<swp-addon-meta>
<swp-addon-price>+250 kr</swp-addon-price>
<span>+15 min</span>
<swp-addon-type>Valgfri</swp-addon-type>
</swp-addon-meta>
</swp-addon-info>
</swp-addon-item>
<swp-addon-item class="selected">
<swp-addon-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-addon-checkbox>
<swp-addon-info>
<swp-addon-name>Kerastase Hårkur</swp-addon-name>
<swp-addon-meta>
<swp-addon-price>+195 kr</swp-addon-price>
<span>+10 min</span>
<swp-addon-type>Valgfri</swp-addon-type>
</swp-addon-meta>
</swp-addon-info>
</swp-addon-item>
<swp-addon-item class="selected">
<swp-addon-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-addon-checkbox>
<swp-addon-info>
<swp-addon-name>Styling / Curls</swp-addon-name>
<swp-addon-meta>
<swp-addon-price>+150 kr</swp-addon-price>
<span>+20 min</span>
<swp-addon-type>Valgfri</swp-addon-type>
</swp-addon-meta>
</swp-addon-info>
</swp-addon-item>
<swp-addon-item class="selected">
<swp-addon-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-addon-checkbox>
<swp-addon-info>
<swp-addon-name>Hovedbundsmassage</swp-addon-name>
<swp-addon-meta>
<swp-addon-price>+75 kr</swp-addon-price>
<span>+5 min</span>
<swp-addon-type>Valgfri</swp-addon-type>
</swp-addon-meta>
</swp-addon-info>
</swp-addon-item>
<swp-addon-item>
<swp-addon-checkbox>
<svg viewBox="0 0 24 24"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/></svg>
</swp-addon-checkbox>
<swp-addon-info>
<swp-addon-name>Patch Test</swp-addon-name>
<swp-addon-meta>
<swp-addon-price>Gratis</swp-addon-price>
<span>48t før</span>
<swp-addon-type class="required">Påkrævet (nye)</swp-addon-type>
</swp-addon-meta>
</swp-addon-info>
</swp-addon-item>
</swp-addon-list>
<swp-add-button>+ Tilføj eksisterende tilvalg</swp-add-button>
</swp-card>
</swp-tab-content>
<!-- ==========================================
REGLER TAB
========================================== -->
<swp-tab-content data-tab="rules">
<div class="grid-2">
<swp-card>
<swp-section-label>Booking-regler</swp-section-label>
<swp-edit-section>
<swp-edit-row>
<swp-edit-label>Minimum varsel</swp-edit-label>
<swp-edit-select>
<select>
<option>Ingen</option>
<option>2 timer</option>
<option>4 timer</option>
<option selected>24 timer</option>
<option>48 timer</option>
<option>1 uge</option>
</select>
</swp-edit-select>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Maks. forudbooking</swp-edit-label>
<swp-edit-select>
<select>
<option>1 måned</option>
<option>2 måneder</option>
<option selected>3 måneder</option>
<option>6 måneder</option>
<option>1 år</option>
</select>
</swp-edit-select>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>Afbestillingsfrist</swp-edit-label>
<swp-edit-select>
<select>
<option>Ingen</option>
<option>2 timer</option>
<option>4 timer</option>
<option selected>24 timer</option>
<option>48 timer</option>
</select>
</swp-edit-select>
</swp-edit-row>
<swp-edit-row>
<swp-edit-label>No-show gebyr</swp-edit-label>
<swp-edit-select>
<select>
<option>Intet</option>
<option>25% af pris</option>
<option selected>50% af pris</option>
<option>Fuld pris</option>
<option>Fast beløb</option>
</select>
</swp-edit-select>
</swp-edit-row>
</swp-edit-section>
</swp-card>
<swp-card>
<swp-section-label>Krav & Forberedelse</swp-section-label>
<swp-toggle-row>
<div>
<swp-toggle-label>Konsultation påkrævet</swp-toggle-label>
<swp-toggle-description>Kunde skal have konsultation før første booking</swp-toggle-description>
</div>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<div>
<swp-toggle-label>Patch test påkrævet</swp-toggle-label>
<swp-toggle-description>Allergitest 48 timer før farvebehandling (nye kunder)</swp-toggle-description>
</div>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<div>
<swp-toggle-label>Aldersbegrænsning</swp-toggle-label>
<swp-toggle-description>Minimum alder for booking af denne service</swp-toggle-description>
</div>
<swp-toggle-slider data-value="no">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
</swp-card>
</div>
<swp-card>
<swp-section-label>Online booking indstillinger</swp-section-label>
<swp-toggle-row>
<swp-toggle-label>Vis i online booking</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<swp-toggle-label>Tillad valg af medarbejder</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<swp-toggle-label>Vis pris</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
<swp-toggle-row>
<swp-toggle-label>Vis varighed</swp-toggle-label>
<swp-toggle-slider data-value="yes">
<swp-toggle-option>Ja</swp-toggle-option>
<swp-toggle-option>Nej</swp-toggle-option>
</swp-toggle-slider>
</swp-toggle-row>
</swp-card>
</swp-tab-content>
<script>
// ==========================================
// TAB SWITCHING
// ==========================================
document.querySelectorAll('swp-tab').forEach(tab => {
tab.addEventListener('click', () => {
const tabName = tab.dataset.tab;
// Update tab active state
document.querySelectorAll('swp-tab').forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// Update content visibility
document.querySelectorAll('swp-tab-content').forEach(content => {
content.classList.remove('active');
if (content.dataset.tab === tabName) {
content.classList.add('active');
}
});
});
});
// ==========================================
// TIME RANGE SLIDERS
// ==========================================
function valueToTime(value) {
// value 0-60 represents 06:00-21:00 in 15-min intervals
const totalMinutes = (value * 15) + (6 * 60); // Add 6 hour offset
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
}
const TIME_RANGE_MAX = 60; // 15 hours (06:00-21:00) * 4 intervals
function updateTimeRange(slider) {
const startInput = slider.querySelector('.range-start');
const endInput = slider.querySelector('.range-end');
const fill = slider.querySelector('swp-time-range-fill');
const label = slider.closest('swp-time-range').querySelector('swp-time-range-label');
let startVal = parseInt(startInput.value);
let endVal = parseInt(endInput.value);
// Ensure start doesn't exceed end
if (startVal > endVal) {
if (startInput === document.activeElement) {
startInput.value = endVal;
startVal = endVal;
} else {
endInput.value = startVal;
endVal = startVal;
}
}
// Update fill bar position
const startPercent = (startVal / TIME_RANGE_MAX) * 100;
const endPercent = (endVal / TIME_RANGE_MAX) * 100;
fill.style.left = startPercent + '%';
fill.style.width = (endPercent - startPercent) + '%';
// Update label
label.textContent = valueToTime(startVal) + ' ' + valueToTime(endVal);
}
document.querySelectorAll('swp-time-range-slider').forEach(slider => {
const startInput = slider.querySelector('.range-start');
const endInput = slider.querySelector('.range-end');
const fill = slider.querySelector('swp-time-range-fill');
const track = slider.querySelector('swp-time-range-track');
// Initialize
updateTimeRange(slider);
startInput.addEventListener('input', () => updateTimeRange(slider));
endInput.addEventListener('input', () => updateTimeRange(slider));
// Drag fill bar to move entire range
let isDragging = false;
let dragStartX = 0;
let dragStartValues = { start: 0, end: 0 };
fill.addEventListener('mousedown', (e) => {
if (startInput.disabled) return;
isDragging = true;
dragStartX = e.clientX;
dragStartValues.start = parseInt(startInput.value);
dragStartValues.end = parseInt(endInput.value);
e.preventDefault();
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
const sliderWidth = track.offsetWidth;
const deltaX = e.clientX - dragStartX;
const deltaValue = Math.round((deltaX / sliderWidth) * TIME_RANGE_MAX);
const duration = dragStartValues.end - dragStartValues.start;
let newStart = dragStartValues.start + deltaValue;
let newEnd = dragStartValues.end + deltaValue;
// Clamp to bounds
if (newStart < 0) {
newStart = 0;
newEnd = duration;
}
if (newEnd > TIME_RANGE_MAX) {
newEnd = TIME_RANGE_MAX;
newStart = TIME_RANGE_MAX - duration;
}
startInput.value = newStart;
endInput.value = newEnd;
updateTimeRange(slider);
});
document.addEventListener('mouseup', () => {
isDragging = false;
});
});
// ==========================================
// TOGGLE SLIDERS (Ja/Nej)
// ==========================================
document.querySelectorAll('swp-toggle-slider').forEach(slider => {
const options = slider.querySelectorAll('swp-toggle-option');
options.forEach((option, index) => {
option.addEventListener('click', () => {
const newValue = index === 0 ? 'yes' : 'no';
slider.dataset.value = newValue;
// Handle availability row toggle
const availabilityRow = slider.closest('swp-availability-row');
if (availabilityRow) {
const isEnabled = newValue === 'yes';
availabilityRow.dataset.enabled = isEnabled;
const rangeInputs = availabilityRow.querySelectorAll('input[type="range"]');
rangeInputs.forEach(input => {
input.disabled = !isEnabled;
});
const fill = availabilityRow.querySelector('swp-time-range-fill');
if (fill) {
fill.classList.toggle('disabled', !isEnabled);
}
}
});
});
});
// ==========================================
// ADDON ITEMS
// ==========================================
document.querySelectorAll('swp-addon-item').forEach(item => {
item.addEventListener('click', () => {
item.classList.toggle('selected');
});
});
// ==========================================
// EMPLOYEE ITEMS
// ==========================================
document.querySelectorAll('swp-employee-item:not(.disabled)').forEach(item => {
item.addEventListener('click', () => {
item.classList.toggle('selected');
});
});
// ==========================================
// COLOR DROPDOWN
// ==========================================
const colorPopover = document.getElementById('colorPopover');
const colorTrigger = document.getElementById('colorTrigger');
if (colorPopover) {
colorPopover.querySelectorAll('swp-color-option').forEach(option => {
option.addEventListener('click', () => {
const value = option.dataset.value;
const label = option.dataset.label;
// Update selected state
colorPopover.querySelectorAll('swp-color-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
// Update trigger button
const triggerDot = colorTrigger.querySelector('swp-color-dot');
const triggerName = colorTrigger.querySelector('.color-name');
triggerDot.className = `is-${value}`;
triggerName.textContent = label;
// Close popover
colorPopover.hidePopover();
});
});
}
// ==========================================
// CATEGORY DROPDOWN
// ==========================================
const categoryPopover = document.getElementById('categoryPopover');
const categoryTrigger = document.getElementById('categoryTrigger');
if (categoryPopover) {
categoryPopover.querySelectorAll('swp-dropdown-option').forEach(option => {
option.addEventListener('click', () => {
const label = option.textContent;
// Update selected state
categoryPopover.querySelectorAll('swp-dropdown-option').forEach(o => o.classList.remove('selected'));
option.classList.add('selected');
// Update trigger button
categoryTrigger.querySelector('.dropdown-value').textContent = label;
// Close popover
categoryPopover.hidePopover();
});
});
}
// ==========================================
// PRICE MODE TOGGLE
// ==========================================
document.querySelectorAll('swp-price-mode-btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('swp-price-mode-btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
const mode = btn.dataset.mode;
const simpleView = document.querySelector('swp-price-simple');
const matrixView = document.querySelector('swp-price-matrix');
if (mode === 'simple') {
simpleView.style.display = 'block';
matrixView.style.display = 'none';
} else {
simpleView.style.display = 'none';
matrixView.style.display = 'block';
}
});
});
// ==========================================
// DURATION DELETE
// ==========================================
document.querySelectorAll('swp-duration-delete').forEach(btn => {
btn.addEventListener('click', () => {
const item = btn.closest('swp-duration-item');
if (item) {
item.style.opacity = '0';
item.style.transform = 'translateX(20px)';
setTimeout(() => item.remove(), 200);
}
});
});
// ==========================================
// TAG REMOVE
// ==========================================
document.querySelectorAll('swp-tag .remove').forEach(btn => {
btn.addEventListener('click', (e) => {
e.stopPropagation();
const tag = btn.closest('swp-tag');
if (tag) tag.remove();
});
});
// ==========================================
// SERVICE STATUS TOGGLE
// ==========================================
const serviceStatus = document.getElementById('serviceStatus');
if (serviceStatus) {
serviceStatus.addEventListener('click', () => {
const isActive = serviceStatus.dataset.active === 'true';
serviceStatus.dataset.active = isActive ? 'false' : 'true';
serviceStatus.querySelector('.icon').textContent = isActive ? '○' : '●';
serviceStatus.querySelector('.text').textContent = isActive ? 'Inaktiv' : 'Aktiv';
});
}
</script>
</body>
</html>