Moves POC-files into PlanTempus
1066
.workbench/POC/calendar-poc-single-file.html
Normal file
1157
.workbench/POC/css/dashboard.css
Normal file
576
.workbench/POC/css/indstillinger.css
Normal file
|
|
@ -0,0 +1,576 @@
|
||||||
|
/* ==========================================
|
||||||
|
INDSTILLINGER (SETTINGS) STYLES
|
||||||
|
========================================== */
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PAGE LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 900px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title h1 {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
SETTINGS SECTIONS
|
||||||
|
========================================== */
|
||||||
|
swp-settings-section {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20px 24px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-title i {
|
||||||
|
font-size: 22px;
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-title h2 {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-content {
|
||||||
|
display: block;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 16px 24px;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FORM ELEMENTS
|
||||||
|
========================================== */
|
||||||
|
swp-form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-grid.single-column {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-row.full-width {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-label span.optional {
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-input {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-background);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-teal) 15%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-input::placeholder {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-input[type="time"] {
|
||||||
|
padding: 8px 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-textarea {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-background);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 80px;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-teal) 15%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-select {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 14px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
color: var(--color-text);
|
||||||
|
background: var(--color-background);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M213.66 101.66l-80 80a8 8 0 0 1-11.32 0l-80-80A8 8 0 0 1 48 88h160a8 8 0 0 1 5.66 13.66z'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
padding-right: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-teal) 15%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-hint {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TOGGLE SWITCH
|
||||||
|
========================================== */
|
||||||
|
swp-toggle-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle {
|
||||||
|
position: relative;
|
||||||
|
width: 44px;
|
||||||
|
height: 24px;
|
||||||
|
background: var(--color-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 200ms ease;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle.active {
|
||||||
|
background: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle-knob {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||||
|
transition: transform 200ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-toggle.active swp-toggle-knob {
|
||||||
|
transform: translateX(20px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
OPENING HOURS TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-hours-table {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 100px 80px 1fr 1fr auto;
|
||||||
|
gap: 16px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-day {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, transparent);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-badge.closed {
|
||||||
|
background: var(--color-background);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-time {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-time span {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-time swp-form-input {
|
||||||
|
width: 100px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
LOGO UPLOAD
|
||||||
|
========================================== */
|
||||||
|
swp-logo-upload {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-logo-preview {
|
||||||
|
width: 80px;
|
||||||
|
height: 80px;
|
||||||
|
background: var(--color-background);
|
||||||
|
border: 2px dashed var(--color-border);
|
||||||
|
border-radius: 8px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-logo-preview.has-logo {
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-logo-preview img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-logo-preview i {
|
||||||
|
font-size: 32px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-logo-actions {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-logo-actions swp-btn {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
URL FIELD WITH COPY
|
||||||
|
========================================== */
|
||||||
|
swp-url-field {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: var(--color-background);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-url-field swp-form-input {
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-url-field swp-form-input:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-url-copy {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 14px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-left: 1px solid var(--color-border);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-url-copy:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-url-copy i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
BUTTONS
|
||||||
|
========================================== */
|
||||||
|
swp-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary {
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:hover {
|
||||||
|
background: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.small {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.small i {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.danger {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.danger:hover {
|
||||||
|
background: color-mix(in srgb, var(--color-red) 10%, transparent);
|
||||||
|
border-color: var(--color-red);
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ICON BUTTON
|
||||||
|
========================================== */
|
||||||
|
swp-icon-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-icon-btn:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-icon-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
INFO BOX
|
||||||
|
========================================== */
|
||||||
|
swp-info-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 14px 16px;
|
||||||
|
background: color-mix(in srgb, var(--color-blue) 8%, transparent);
|
||||||
|
border: 1px solid color-mix(in srgb, var(--color-blue) 20%, transparent);
|
||||||
|
border-radius: 6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-info-box i {
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--color-blue);
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-info-box p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
RESPONSIVE
|
||||||
|
========================================== */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
swp-page-container {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-row {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-hours-time {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-header {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
684
.workbench/POC/css/konto.css
Normal file
|
|
@ -0,0 +1,684 @@
|
||||||
|
/* ==========================================
|
||||||
|
KONTO & ABONNEMENT STYLES
|
||||||
|
========================================== */
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PAGE LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title h1 {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title p {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
SECTIONS
|
||||||
|
========================================== */
|
||||||
|
swp-section {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-title {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-section-title i {
|
||||||
|
font-size: 22px;
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PLAN CARDS
|
||||||
|
========================================== */
|
||||||
|
swp-plan-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 2px solid var(--color-border);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
transition: all 200ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-card.current {
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-teal) 15%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-card.enterprise {
|
||||||
|
background: linear-gradient(135deg, var(--color-surface) 0%, color-mix(in srgb, var(--color-purple) 5%, var(--color-surface)) 100%);
|
||||||
|
border-color: var(--color-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
border-radius: 20px;
|
||||||
|
width: fit-content;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-badge.current {
|
||||||
|
background: color-mix(in srgb, var(--color-teal) 15%, transparent);
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-badge.popular {
|
||||||
|
background: color-mix(in srgb, var(--color-amber) 15%, transparent);
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-name {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-users {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-price {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 4px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-price-amount {
|
||||||
|
font-size: 36px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-price-period {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-features {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-feature {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-feature i {
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-action {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-action swp-btn {
|
||||||
|
width: 100%;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-plan-card.current swp-btn.secondary {
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
USERS TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-users-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-users-count {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-users-count strong {
|
||||||
|
color: var(--color-text);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-users-progress {
|
||||||
|
width: 100px;
|
||||||
|
height: 6px;
|
||||||
|
background: var(--color-border);
|
||||||
|
border-radius: 3px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-users-progress-bar {
|
||||||
|
height: 100%;
|
||||||
|
background: var(--color-teal);
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: width 300ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-users-progress-bar.warning {
|
||||||
|
background: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-users-progress-bar.full {
|
||||||
|
background: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-card {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header {
|
||||||
|
display: table-header-group;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-body {
|
||||||
|
display: table-row-group;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row {
|
||||||
|
display: table-row;
|
||||||
|
transition: background 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-body swp-table-row:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-cell {
|
||||||
|
display: table-cell;
|
||||||
|
padding: 14px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header swp-table-cell {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-cell:first-child {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-cell:last-child {
|
||||||
|
padding-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* User row specific */
|
||||||
|
swp-user-info {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-user-avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-user-avatar.purple { background: var(--color-purple); }
|
||||||
|
swp-user-avatar.blue { background: var(--color-blue); }
|
||||||
|
swp-user-avatar.amber { background: var(--color-amber); }
|
||||||
|
|
||||||
|
swp-user-details {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-user-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-user-email {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-role-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--color-background);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-role-badge.admin {
|
||||||
|
background: color-mix(in srgb, var(--color-purple) 15%, transparent);
|
||||||
|
color: var(--color-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-role-badge.owner {
|
||||||
|
background: color-mix(in srgb, var(--color-teal) 15%, transparent);
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.active {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, transparent);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.invited {
|
||||||
|
background: color-mix(in srgb, var(--color-amber) 15%, transparent);
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.inactive {
|
||||||
|
background: var(--color-background);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-dot {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-actions {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-icon-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-icon-btn:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-icon-btn.danger:hover {
|
||||||
|
background: color-mix(in srgb, var(--color-red) 15%, transparent);
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-icon-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
BILLING GRID
|
||||||
|
========================================== */
|
||||||
|
swp-billing-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 380px 1fr;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PAYMENT CARD
|
||||||
|
========================================== */
|
||||||
|
swp-payment-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-method {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 32px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-icon i {
|
||||||
|
font-size: 24px;
|
||||||
|
color: var(--color-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-info {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-type {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-number {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-detail {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-detail:last-of-type {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-value {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-payment-value.highlight {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
INVOICES
|
||||||
|
========================================== */
|
||||||
|
swp-invoices-card {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-invoices-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-invoices-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-invoice-status {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-invoice-status.paid {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, transparent);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-invoice-status.pending {
|
||||||
|
background: color-mix(in srgb, var(--color-amber) 15%, transparent);
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-invoice-status.overdue {
|
||||||
|
background: color-mix(in srgb, var(--color-red) 15%, transparent);
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-download-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-teal);
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-teal);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-download-btn:hover {
|
||||||
|
background: color-mix(in srgb, var(--color-teal) 10%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-download-btn i {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
BUTTONS
|
||||||
|
========================================== */
|
||||||
|
swp-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary {
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:hover {
|
||||||
|
background: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.outline {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--color-teal);
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.outline:hover {
|
||||||
|
background: color-mix(in srgb, var(--color-teal) 10%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
EMPTY STATE
|
||||||
|
========================================== */
|
||||||
|
swp-empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 48px 24px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-empty-state i {
|
||||||
|
font-size: 48px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-empty-state p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
RESPONSIVE
|
||||||
|
========================================== */
|
||||||
|
@media (max-width: 1024px) {
|
||||||
|
swp-plan-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-billing-grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
swp-page-container {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-card {
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table {
|
||||||
|
min-width: 600px;
|
||||||
|
}
|
||||||
|
}
|
||||||
88
.workbench/POC/data/calendar-config.json
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
{
|
||||||
|
"gridSettings": {
|
||||||
|
"hourHeight": 80,
|
||||||
|
"dayStartHour": 6,
|
||||||
|
"dayEndHour": 22,
|
||||||
|
"workStartHour": 8,
|
||||||
|
"workEndHour": 17,
|
||||||
|
"snapInterval": 15,
|
||||||
|
"gridStartThresholdMinutes": 30,
|
||||||
|
"showCurrentTime": true,
|
||||||
|
"showWorkHours": true,
|
||||||
|
"fitToWidth": false,
|
||||||
|
"scrollToHour": 8
|
||||||
|
},
|
||||||
|
"dateViewSettings": {
|
||||||
|
"period": "week",
|
||||||
|
"weekDays": 7,
|
||||||
|
"firstDayOfWeek": 1,
|
||||||
|
"showAllDay": true
|
||||||
|
},
|
||||||
|
"timeFormatConfig": {
|
||||||
|
"timezone": "Europe/Copenhagen",
|
||||||
|
"use24HourFormat": true,
|
||||||
|
"locale": "da-DK",
|
||||||
|
"dateFormat": "technical",
|
||||||
|
"showSeconds": false
|
||||||
|
},
|
||||||
|
"workWeekPresets": {
|
||||||
|
"standard": {
|
||||||
|
"id": "standard",
|
||||||
|
"workDays": [1, 2, 3, 4, 5],
|
||||||
|
"totalDays": 5,
|
||||||
|
"firstWorkDay": 1
|
||||||
|
},
|
||||||
|
"compressed": {
|
||||||
|
"id": "compressed",
|
||||||
|
"workDays": [1, 2, 3, 4],
|
||||||
|
"totalDays": 4,
|
||||||
|
"firstWorkDay": 1
|
||||||
|
},
|
||||||
|
"midweek": {
|
||||||
|
"id": "midweek",
|
||||||
|
"workDays": [3, 4, 5],
|
||||||
|
"totalDays": 3,
|
||||||
|
"firstWorkDay": 3
|
||||||
|
},
|
||||||
|
"weekend": {
|
||||||
|
"id": "weekend",
|
||||||
|
"workDays": [6, 7],
|
||||||
|
"totalDays": 2,
|
||||||
|
"firstWorkDay": 6
|
||||||
|
},
|
||||||
|
"fullweek": {
|
||||||
|
"id": "fullweek",
|
||||||
|
"workDays": [1, 2, 3, 4, 5, 6, 7],
|
||||||
|
"totalDays": 7,
|
||||||
|
"firstWorkDay": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"currentWorkWeek": "standard",
|
||||||
|
"currentView": "week",
|
||||||
|
"scrollbar": {
|
||||||
|
"width": 16,
|
||||||
|
"color": "#666",
|
||||||
|
"trackColor": "#f0f0f0",
|
||||||
|
"hoverColor": "#b53f7aff",
|
||||||
|
"borderRadius": 6
|
||||||
|
},
|
||||||
|
"interaction": {
|
||||||
|
"allowDrag": true,
|
||||||
|
"allowResize": true,
|
||||||
|
"allowCreate": true
|
||||||
|
},
|
||||||
|
"api": {
|
||||||
|
"endpoint": "/api/events",
|
||||||
|
"dateFormat": "YYYY-MM-DD",
|
||||||
|
"timeFormat": "HH:mm"
|
||||||
|
},
|
||||||
|
"features": {
|
||||||
|
"enableSearch": true,
|
||||||
|
"enableTouch": true
|
||||||
|
},
|
||||||
|
"eventDefaults": {
|
||||||
|
"defaultEventDuration": 60,
|
||||||
|
"minEventDuration": 15,
|
||||||
|
"maxEventDuration": 480
|
||||||
|
}
|
||||||
|
}
|
||||||
67
.workbench/POC/data/employee-revenue-utilization.json
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
{
|
||||||
|
"categories": ["Uge 40", "Uge 41", "Uge 42", "Uge 43", "Uge 44", "Uge 45", "Uge 46", "Uge 47", "Uge 48", "Uge 49", "Uge 50", "Uge 51", "Uge 52", "Uge 1", "Uge 2", "Uge 3", "Uge 4", "Uge 5", "Uge 6", "Uge 7", "Uge 8", "Uge 9", "Uge 10", "Uge 11", "Uge 12"],
|
||||||
|
"nowCategory": "Uge 52",
|
||||||
|
"forecastStartCategory": "Uge 1",
|
||||||
|
"actual": {
|
||||||
|
"revenue": [
|
||||||
|
{ "x": "Uge 40", "y": 38500 },
|
||||||
|
{ "x": "Uge 41", "y": 42000 },
|
||||||
|
{ "x": "Uge 42", "y": 35200 },
|
||||||
|
{ "x": "Uge 43", "y": 44800 },
|
||||||
|
{ "x": "Uge 44", "y": 41500 },
|
||||||
|
{ "x": "Uge 45", "y": 39200 },
|
||||||
|
{ "x": "Uge 46", "y": 46100 },
|
||||||
|
{ "x": "Uge 47", "y": 43800 },
|
||||||
|
{ "x": "Uge 48", "y": 40500 },
|
||||||
|
{ "x": "Uge 49", "y": 45200 },
|
||||||
|
{ "x": "Uge 50", "y": 42800 },
|
||||||
|
{ "x": "Uge 51", "y": 44500 },
|
||||||
|
{ "x": "Uge 52", "y": 28450 }
|
||||||
|
],
|
||||||
|
"utilization": [
|
||||||
|
{ "x": "Uge 40", "y": 82 },
|
||||||
|
{ "x": "Uge 41", "y": 88 },
|
||||||
|
{ "x": "Uge 42", "y": 75 },
|
||||||
|
{ "x": "Uge 43", "y": 91 },
|
||||||
|
{ "x": "Uge 44", "y": 85 },
|
||||||
|
{ "x": "Uge 45", "y": 80 },
|
||||||
|
{ "x": "Uge 46", "y": 94 },
|
||||||
|
{ "x": "Uge 47", "y": 89 },
|
||||||
|
{ "x": "Uge 48", "y": 83 },
|
||||||
|
{ "x": "Uge 49", "y": 92 },
|
||||||
|
{ "x": "Uge 50", "y": 87 },
|
||||||
|
{ "x": "Uge 51", "y": 90 },
|
||||||
|
{ "x": "Uge 52", "y": 84 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"forecast": {
|
||||||
|
"revenue": [
|
||||||
|
{ "x": "Uge 1", "y": 0 },
|
||||||
|
{ "x": "Uge 2", "y": 32500 },
|
||||||
|
{ "x": "Uge 3", "y": 28800 },
|
||||||
|
{ "x": "Uge 4", "y": 22400 },
|
||||||
|
{ "x": "Uge 5", "y": 15200 },
|
||||||
|
{ "x": "Uge 6", "y": 9800 },
|
||||||
|
{ "x": "Uge 7", "y": 6500 },
|
||||||
|
{ "x": "Uge 8", "y": 4200 },
|
||||||
|
{ "x": "Uge 9", "y": 2800 },
|
||||||
|
{ "x": "Uge 10", "y": 1500 },
|
||||||
|
{ "x": "Uge 11", "y": 800 },
|
||||||
|
{ "x": "Uge 12", "y": 0 }
|
||||||
|
],
|
||||||
|
"utilization": [
|
||||||
|
{ "x": "Uge 1", "y": 0 },
|
||||||
|
{ "x": "Uge 2", "y": 74 },
|
||||||
|
{ "x": "Uge 3", "y": 58 },
|
||||||
|
{ "x": "Uge 4", "y": 39 },
|
||||||
|
{ "x": "Uge 5", "y": 21 },
|
||||||
|
{ "x": "Uge 6", "y": 11 },
|
||||||
|
{ "x": "Uge 7", "y": 8 },
|
||||||
|
{ "x": "Uge 8", "y": 5 },
|
||||||
|
{ "x": "Uge 9", "y": 3 },
|
||||||
|
{ "x": "Uge 10", "y": 2 },
|
||||||
|
{ "x": "Uge 11", "y": 1 },
|
||||||
|
{ "x": "Uge 12", "y": 0 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
125
.workbench/POC/data/kk-services.json
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
{
|
||||||
|
"Klip dame, herre og børn": [
|
||||||
|
{ "name": "Dameklip", "duration": 60, "price": 725 },
|
||||||
|
{ "name": "Dameklip uden snak", "duration": 60, "price": 725 },
|
||||||
|
{ "name": "Dameklip spidser mellemlangt og langt hår", "duration": 40, "price": 575 },
|
||||||
|
{ "name": "Dameklip Luksus ekstra glans og pleje", "duration": 75, "price": 925 },
|
||||||
|
{ "name": "Herreklip", "duration": 60, "price": 645 },
|
||||||
|
{ "name": "Herreklip uden snak", "duration": 60, "price": 645 },
|
||||||
|
{ "name": "Skin fade", "duration": 60, "price": 645 },
|
||||||
|
{ "name": "Klip med maskine (herre klip)", "duration": 30, "price": 475 },
|
||||||
|
{ "name": "Børneklip 0-4 år", "duration": 45, "price": 475 },
|
||||||
|
{ "name": "Børneklip 4-8 år", "duration": 45, "price": 525 },
|
||||||
|
{ "name": "Touch up Dame", "duration": 10, "price": 0 },
|
||||||
|
{ "name": "Touch up Herre", "duration": 10, "price": 0 },
|
||||||
|
{ "name": "Pandehår helt nyt", "duration": 20, "price": 325 },
|
||||||
|
{ "name": "Konsultation uden behandling", "duration": 10, "price": 0 },
|
||||||
|
{ "name": "Herreklip", "duration": 60, "price": 550 },
|
||||||
|
{ "name": "Klip med maskine (herre klip)", "duration": 45, "price": 525 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Farvebehandlinger": [
|
||||||
|
{ "name": "Bundfarve almindelig udgroning maks 3 cm", "duration": 90, "price": 785 },
|
||||||
|
{ "name": "Helfarve kort hår", "duration": 105, "price": 950 },
|
||||||
|
{ "name": "Helfarve mellemlangt hår", "duration": 120, "price": 1450 },
|
||||||
|
{ "name": "Helfarve langt hår", "duration": 120, "price": 1550 },
|
||||||
|
{ "name": "Bundfarve/ Lysning", "duration": 105, "price": 975 },
|
||||||
|
{ "name": "Afblegning kort hår + gloss", "duration": 150, "price": 1895 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Striber/ Refleksbehandling": [
|
||||||
|
{ "name": "Striber kort hår", "duration": 120, "price": 1465 },
|
||||||
|
{ "name": "Striber mellemlangt hår", "duration": 150, "price": 1665 },
|
||||||
|
{ "name": "Striber langt hår", "duration": 180, "price": 1865 },
|
||||||
|
{ "name": "Striber på toppen/ overhår", "duration": 90, "price": 1065 },
|
||||||
|
{ "name": "Striber babylights tæt lysning mellemlangt hår", "duration": 180, "price": 2650 },
|
||||||
|
{ "name": "Striber babylights tæt lysning langt hår", "duration": 180, "price": 2850 },
|
||||||
|
{ "name": "Striber babylights tæt lysning på toppen", "duration": 120, "price": 1650 },
|
||||||
|
{ "name": "AirTouch skulderlangt hår", "duration": 210, "price": 3250 },
|
||||||
|
{ "name": "AirTouch langt hår", "duration": 240, "price": 3850 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Hårvask med styling eller uden styling": [
|
||||||
|
{ "name": "Hårvask uden styling", "duration": 30, "price": 265 },
|
||||||
|
{ "name": "Hårvask med styling (kun føn)", "duration": 40, "price": 450 },
|
||||||
|
{ "name": "Vask + Styling med varme glatning/krøller (mellemlangt/langt)", "duration": 60, "price": 650 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Henna naturlig hårfarver": [
|
||||||
|
{ "name": "Henna kort hår", "duration": 90, "price": 965 },
|
||||||
|
{ "name": "Henna mellemlangt/langt hår", "duration": 90, "price": 1265 },
|
||||||
|
{ "name": "Henna bundfarve", "duration": 90, "price": 750 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Kurbehandling": [
|
||||||
|
{ "name": "Olaplex Stand alone", "duration": 60, "price": 550 },
|
||||||
|
{ "name": "Kurbehandling fugt/protein", "duration": 40, "price": 365 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Bryn og vipper": [
|
||||||
|
{ "name": "Farvning vipper & bryn", "duration": 30, "price": 345 },
|
||||||
|
{ "name": "Farvning vipper", "duration": 20, "price": 185 },
|
||||||
|
{ "name": "Farvning og retning af bryn", "duration": 20, "price": 185 },
|
||||||
|
{ "name": "Retning af bryn", "duration": 10, "price": 100 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Balayage": [
|
||||||
|
{ "name": "Balayage maks til skulderen", "duration": 150, "price": 1850 },
|
||||||
|
{ "name": "Balayage maks skulder + gloss/toning", "duration": 180, "price": 2250 },
|
||||||
|
{ "name": "Balayage langt hår", "duration": 150, "price": 2150 },
|
||||||
|
{ "name": "Balayage langt hår + gloss/toning", "duration": 180, "price": 2550 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Skæg": [
|
||||||
|
{ "name": "Skægtrim", "duration": 20, "price": 300 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Gloss": [
|
||||||
|
{ "name": "Gloss ekstra langt/tykt hår", "duration": 75, "price": 900 },
|
||||||
|
{ "name": "Glossing kort hår", "duration": 60, "price": 685 },
|
||||||
|
{ "name": "Glossing mellemlangt/ langt hår", "duration": 60, "price": 745 },
|
||||||
|
{ "name": "Glossing mænd", "duration": 40, "price": 350 },
|
||||||
|
{ "name": "Gloss ifb. anden farvebehandling", "duration": 20, "price": 450 },
|
||||||
|
{ "name": "Gloss ifb. anden farvebehandling", "duration": 30, "price": 450 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Håropsætning": [
|
||||||
|
{ "name": "Håropsætning kort hår", "duration": 60, "price": 850 },
|
||||||
|
{ "name": "Håropsætning langt hår", "duration": 60, "price": 1450 },
|
||||||
|
{ "name": "Håropsætning Brud/brudepiger/Galla/Oscar", "duration": 90, "price": 1599 },
|
||||||
|
{ "name": "Make-up Special Brud/Galla mm", "duration": 90, "price": 3000 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Modeller": [
|
||||||
|
{ "name": "Dameklip Model", "duration": 60, "price": 0 },
|
||||||
|
{ "name": "Herreklip Model", "duration": 60, "price": 0 },
|
||||||
|
{ "name": "Balayage Model", "duration": 240, "price": 0 },
|
||||||
|
{ "name": "Striber Model", "duration": 180, "price": 0 },
|
||||||
|
{ "name": "Bryn & Vippe Model", "duration": 40, "price": 0 },
|
||||||
|
{ "name": "Bundfarve Model", "duration": 120, "price": 0 },
|
||||||
|
{ "name": "Gloss", "duration": 30, "price": 0 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Tristan farve modeller": [
|
||||||
|
{ "name": "Bundfarve med HP/HPF", "duration": 90, "price": 325 },
|
||||||
|
{ "name": "Striber Model", "duration": 240, "price": 400 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Uden kategori": [
|
||||||
|
{ "name": "P-afgift", "duration": 0, "price": -25 },
|
||||||
|
{ "name": "Børneklip 9-12 år", "duration": 60, "price": 450 }
|
||||||
|
],
|
||||||
|
|
||||||
|
"Tilvalg services": [
|
||||||
|
{ "name": "Touch up kur", "duration": 15, "price": 175 },
|
||||||
|
{ "name": "Root shading", "duration": 30, "price": 425 },
|
||||||
|
{ "name": "Styling med varme (efter behandling)", "duration": 60, "price": 475 },
|
||||||
|
{ "name": "Styling kort hår (efter farve)", "duration": 20, "price": 175 },
|
||||||
|
{ "name": "Olaplex efter afblegning", "duration": 10, "price": 325 },
|
||||||
|
{ "name": "Let afrensning af gloss/klor/kemi", "duration": 20, "price": 220 },
|
||||||
|
{ "name": "Forpigmentering", "duration": 20, "price": 300 },
|
||||||
|
{ "name": "Knække bund ifb. farvebehandling", "duration": 20, "price": 400 },
|
||||||
|
{ "name": "Olaplex i farve", "duration": 10, "price": 230 },
|
||||||
|
{ "name": "Metal DX intens kur redken gloss", "duration": 20, "price": 225 }
|
||||||
|
]
|
||||||
|
}
|
||||||
514
.workbench/POC/data/mock-bookings.json
Normal file
|
|
@ -0,0 +1,514 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "BOOK001",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-08-05T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV001",
|
||||||
|
"serviceName": "Klipning og styling",
|
||||||
|
"baseDuration": 60,
|
||||||
|
"basePrice": 500,
|
||||||
|
"customPrice": 500,
|
||||||
|
"resourceId": "EMP001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 500,
|
||||||
|
"notes": "Kunde ønsker lidt kortere"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK002",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"status": "paid",
|
||||||
|
"createdAt": "2025-08-05T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV002",
|
||||||
|
"serviceName": "Hårvask",
|
||||||
|
"baseDuration": 30,
|
||||||
|
"basePrice": 100,
|
||||||
|
"customPrice": 100,
|
||||||
|
"resourceId": "STUDENT001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serviceId": "SRV003",
|
||||||
|
"serviceName": "Bundfarve",
|
||||||
|
"baseDuration": 90,
|
||||||
|
"basePrice": 800,
|
||||||
|
"customPrice": 800,
|
||||||
|
"resourceId": "EMP001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 900,
|
||||||
|
"notes": "Split booking: Elev laver hårvask, master laver farve"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK003",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-08-05T07:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV004A",
|
||||||
|
"serviceName": "Bryllupsfrisure - Del 1",
|
||||||
|
"baseDuration": 60,
|
||||||
|
"basePrice": 750,
|
||||||
|
"customPrice": 750,
|
||||||
|
"resourceId": "EMP001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serviceId": "SRV004B",
|
||||||
|
"serviceName": "Bryllupsfrisure - Del 2",
|
||||||
|
"baseDuration": 60,
|
||||||
|
"basePrice": 750,
|
||||||
|
"customPrice": 750,
|
||||||
|
"resourceId": "EMP002"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 1500,
|
||||||
|
"notes": "Equal-split: To master stylister arbejder sammen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK004",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-08-05T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV005",
|
||||||
|
"serviceName": "Herreklipning",
|
||||||
|
"baseDuration": 30,
|
||||||
|
"basePrice": 350,
|
||||||
|
"customPrice": 350,
|
||||||
|
"resourceId": "EMP003"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 350
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK005",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"status": "paid",
|
||||||
|
"createdAt": "2025-08-05T11:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV006",
|
||||||
|
"serviceName": "Balayage langt hår",
|
||||||
|
"baseDuration": 120,
|
||||||
|
"basePrice": 1200,
|
||||||
|
"customPrice": 1200,
|
||||||
|
"resourceId": "EMP002"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 1200,
|
||||||
|
"notes": "Kunde ønsker naturlig blond tone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK006",
|
||||||
|
"customerId": "CUST006",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-08-06T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV007",
|
||||||
|
"serviceName": "Permanent",
|
||||||
|
"baseDuration": 90,
|
||||||
|
"basePrice": 900,
|
||||||
|
"customPrice": 900,
|
||||||
|
"resourceId": "EMP004"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK007",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-08-06T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV008",
|
||||||
|
"serviceName": "Highlights",
|
||||||
|
"baseDuration": 90,
|
||||||
|
"basePrice": 850,
|
||||||
|
"customPrice": 850,
|
||||||
|
"resourceId": "EMP001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serviceId": "SRV009",
|
||||||
|
"serviceName": "Styling",
|
||||||
|
"baseDuration": 30,
|
||||||
|
"basePrice": 200,
|
||||||
|
"customPrice": 200,
|
||||||
|
"resourceId": "EMP001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 1050,
|
||||||
|
"notes": "Highlights + styling samme stylist"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK008",
|
||||||
|
"customerId": "CUST008",
|
||||||
|
"status": "paid",
|
||||||
|
"createdAt": "2025-08-06T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV010",
|
||||||
|
"serviceName": "Klipning",
|
||||||
|
"baseDuration": 45,
|
||||||
|
"basePrice": 450,
|
||||||
|
"customPrice": 450,
|
||||||
|
"resourceId": "EMP004"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK009",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-08-07T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV011",
|
||||||
|
"serviceName": "Farve behandling",
|
||||||
|
"baseDuration": 120,
|
||||||
|
"basePrice": 950,
|
||||||
|
"customPrice": 950,
|
||||||
|
"resourceId": "EMP002"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 950
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK010",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-08-07T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV012",
|
||||||
|
"serviceName": "Skæg trimning",
|
||||||
|
"baseDuration": 20,
|
||||||
|
"basePrice": 200,
|
||||||
|
"customPrice": 200,
|
||||||
|
"resourceId": "EMP003"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK011",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"status": "paid",
|
||||||
|
"createdAt": "2025-08-07T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV002",
|
||||||
|
"serviceName": "Hårvask",
|
||||||
|
"baseDuration": 30,
|
||||||
|
"basePrice": 100,
|
||||||
|
"customPrice": 100,
|
||||||
|
"resourceId": "STUDENT002"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serviceId": "SRV013",
|
||||||
|
"serviceName": "Ombré",
|
||||||
|
"baseDuration": 100,
|
||||||
|
"basePrice": 1100,
|
||||||
|
"customPrice": 1100,
|
||||||
|
"resourceId": "EMP002"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 1200,
|
||||||
|
"notes": "Split booking: Student hårvask, master ombré"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK012",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-08-08T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV014",
|
||||||
|
"serviceName": "Føntørring",
|
||||||
|
"baseDuration": 30,
|
||||||
|
"basePrice": 250,
|
||||||
|
"customPrice": 250,
|
||||||
|
"resourceId": "STUDENT001"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 250
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK013",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-08-08T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV015",
|
||||||
|
"serviceName": "Opsætning",
|
||||||
|
"baseDuration": 60,
|
||||||
|
"basePrice": 700,
|
||||||
|
"customPrice": 700,
|
||||||
|
"resourceId": "EMP004"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 700,
|
||||||
|
"notes": "Fest opsætning"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK014",
|
||||||
|
"customerId": "CUST006",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-08-09T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV016A",
|
||||||
|
"serviceName": "Ekstensions - Del 1",
|
||||||
|
"baseDuration": 90,
|
||||||
|
"basePrice": 1250,
|
||||||
|
"customPrice": 1250,
|
||||||
|
"resourceId": "EMP001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"serviceId": "SRV016B",
|
||||||
|
"serviceName": "Ekstensions - Del 2",
|
||||||
|
"baseDuration": 90,
|
||||||
|
"basePrice": 1250,
|
||||||
|
"customPrice": 1250,
|
||||||
|
"resourceId": "EMP004"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 2500,
|
||||||
|
"notes": "Equal-split: To stylister arbejder sammen om extensions"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK015",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"status": "noshow",
|
||||||
|
"createdAt": "2025-08-09T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"serviceId": "SRV001",
|
||||||
|
"serviceName": "Klipning og styling",
|
||||||
|
"baseDuration": 60,
|
||||||
|
"basePrice": 500,
|
||||||
|
"customPrice": 500,
|
||||||
|
"resourceId": "EMP002"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"totalPrice": 500,
|
||||||
|
"notes": "Kunde mødte ikke op"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV22-001",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-11-20T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-WASH", "serviceName": "Hårvask", "baseDuration": 30, "basePrice": 100, "resourceId": "STUDENT001" },
|
||||||
|
{ "serviceId": "SRV-BAL", "serviceName": "Balayage", "baseDuration": 90, "basePrice": 1200, "resourceId": "EMP001" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1300,
|
||||||
|
"notes": "Split: Elev vasker, Camilla farver"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV22-002",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-11-20T11:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-HERREKLIP", "serviceName": "Herreklipning", "baseDuration": 30, "basePrice": 350, "resourceId": "EMP003" }
|
||||||
|
],
|
||||||
|
"totalPrice": 350
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV22-003",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-20T12:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-FARVE", "serviceName": "Farvning", "baseDuration": 120, "basePrice": 900, "resourceId": "EMP002" }
|
||||||
|
],
|
||||||
|
"totalPrice": 900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV22-004",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"status": "arrived",
|
||||||
|
"createdAt": "2025-11-20T13:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-KLIP", "serviceName": "Dameklipning", "baseDuration": 60, "basePrice": 450, "resourceId": "EMP004" }
|
||||||
|
],
|
||||||
|
"totalPrice": 450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV22-005",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-20T14:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-STYLE", "serviceName": "Styling", "baseDuration": 60, "basePrice": 400, "resourceId": "EMP001" }
|
||||||
|
],
|
||||||
|
"totalPrice": 400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV23-001",
|
||||||
|
"customerId": "CUST006",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-21T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-PERM", "serviceName": "Permanent", "baseDuration": 150, "basePrice": 1100, "resourceId": "EMP002" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV23-002",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-21T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-SKAEG", "serviceName": "Skæg trimning", "baseDuration": 30, "basePrice": 200, "resourceId": "EMP003" }
|
||||||
|
],
|
||||||
|
"totalPrice": 200
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV23-003",
|
||||||
|
"customerId": "CUST008",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-21T11:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-WASH", "serviceName": "Hårvask", "baseDuration": 30, "basePrice": 100, "resourceId": "STUDENT002" },
|
||||||
|
{ "serviceId": "SRV-HIGH", "serviceName": "Highlights", "baseDuration": 120, "basePrice": 1000, "resourceId": "EMP001" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1100,
|
||||||
|
"notes": "Split: Elev vasker, Camilla laver highlights"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV24-001",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-22T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-BRYLLUP1", "serviceName": "Bryllupsfrisure Del 1", "baseDuration": 60, "basePrice": 750, "resourceId": "EMP001" },
|
||||||
|
{ "serviceId": "SRV-BRYLLUP2", "serviceName": "Bryllupsfrisure Del 2", "baseDuration": 60, "basePrice": 750, "resourceId": "EMP002" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1500,
|
||||||
|
"notes": "Equal split: Camilla og Isabella arbejder sammen"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV24-002",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-22T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-FADE", "serviceName": "Fade klipning", "baseDuration": 45, "basePrice": 400, "resourceId": "EMP003" }
|
||||||
|
],
|
||||||
|
"totalPrice": 400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV24-003",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-22T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-KLIPVASK", "serviceName": "Klipning og vask", "baseDuration": 60, "basePrice": 500, "resourceId": "EMP004" }
|
||||||
|
],
|
||||||
|
"totalPrice": 500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV25-001",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-23T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-BALKORT", "serviceName": "Balayage kort hår", "baseDuration": 90, "basePrice": 900, "resourceId": "EMP001" }
|
||||||
|
],
|
||||||
|
"totalPrice": 900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV25-002",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-23T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-EXT", "serviceName": "Extensions", "baseDuration": 180, "basePrice": 2500, "resourceId": "EMP002" }
|
||||||
|
],
|
||||||
|
"totalPrice": 2500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV25-003",
|
||||||
|
"customerId": "CUST006",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-23T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-HERRESKAEG", "serviceName": "Herreklipning + skæg", "baseDuration": 60, "basePrice": 500, "resourceId": "EMP003" }
|
||||||
|
],
|
||||||
|
"totalPrice": 500
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV26-001",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-24T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-FARVKOR", "serviceName": "Farvekorrektion", "baseDuration": 180, "basePrice": 1800, "resourceId": "EMP001" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1800
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV26-002",
|
||||||
|
"customerId": "CUST008",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-24T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-KERATIN", "serviceName": "Keratinbehandling", "baseDuration": 150, "basePrice": 1400, "resourceId": "EMP002" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1400
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV26-003",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-24T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-SKINFADE", "serviceName": "Skin fade", "baseDuration": 45, "basePrice": 450, "resourceId": "EMP003" }
|
||||||
|
],
|
||||||
|
"totalPrice": 450
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV27-001",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-25T08:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-FULLCOLOR", "serviceName": "Full color", "baseDuration": 120, "basePrice": 1000, "resourceId": "EMP001" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1000
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV27-002",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-25T09:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-WASH", "serviceName": "Hårvask", "baseDuration": 30, "basePrice": 100, "resourceId": "STUDENT001" },
|
||||||
|
{ "serviceId": "SRV-BABY", "serviceName": "Babylights", "baseDuration": 180, "basePrice": 1500, "resourceId": "EMP002" }
|
||||||
|
],
|
||||||
|
"totalPrice": 1600,
|
||||||
|
"notes": "Split: Elev vasker, Isabella laver babylights"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "BOOK-NOV27-003",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"status": "created",
|
||||||
|
"createdAt": "2025-11-25T10:00:00Z",
|
||||||
|
"services": [
|
||||||
|
{ "serviceId": "SRV-KLASSISK", "serviceName": "Klassisk herreklip", "baseDuration": 30, "basePrice": 300, "resourceId": "EMP003" }
|
||||||
|
],
|
||||||
|
"totalPrice": 300
|
||||||
|
}
|
||||||
|
]
|
||||||
49
.workbench/POC/data/mock-customers.json
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "CUST001",
|
||||||
|
"name": "Sofie Nielsen",
|
||||||
|
"phone": "+45 23 45 67 89",
|
||||||
|
"email": "sofie.nielsen@email.dk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST002",
|
||||||
|
"name": "Emma Andersen",
|
||||||
|
"phone": "+45 31 24 56 78",
|
||||||
|
"email": "emma.andersen@email.dk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST003",
|
||||||
|
"name": "Freja Christensen",
|
||||||
|
"phone": "+45 42 67 89 12",
|
||||||
|
"email": "freja.christensen@email.dk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST004",
|
||||||
|
"name": "Laura Pedersen",
|
||||||
|
"phone": "+45 51 98 76 54"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST005",
|
||||||
|
"name": "Ida Larsen",
|
||||||
|
"phone": "+45 29 87 65 43",
|
||||||
|
"email": "ida.larsen@email.dk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST006",
|
||||||
|
"name": "Caroline Jensen",
|
||||||
|
"phone": "+45 38 76 54 32",
|
||||||
|
"email": "caroline.jensen@email.dk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST007",
|
||||||
|
"name": "Mathilde Hansen",
|
||||||
|
"phone": "+45 47 65 43 21",
|
||||||
|
"email": "mathilde.hansen@email.dk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "CUST008",
|
||||||
|
"name": "Olivia Sørensen",
|
||||||
|
"phone": "+45 56 54 32 10",
|
||||||
|
"email": "olivia.sorensen@email.dk"
|
||||||
|
}
|
||||||
|
]
|
||||||
14
.workbench/POC/data/mock-departments.json
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "dept-styling",
|
||||||
|
"name": "Styling",
|
||||||
|
"resourceIds": ["EMP001", "EMP002", "EMP003"],
|
||||||
|
"syncStatus": "synced"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "dept-training",
|
||||||
|
"name": "Training",
|
||||||
|
"resourceIds": ["EMP004", "STUDENT001", "STUDENT002"],
|
||||||
|
"syncStatus": "synced"
|
||||||
|
}
|
||||||
|
]
|
||||||
669
.workbench/POC/data/mock-events.json
Normal file
|
|
@ -0,0 +1,669 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV24-001",
|
||||||
|
"title": "Herreklipning",
|
||||||
|
"start": "2025-11-24T09:00:00",
|
||||||
|
"end": "2025-11-24T09:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N01",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "blue" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV24-002",
|
||||||
|
"title": "Balayage",
|
||||||
|
"start": "2025-11-24T10:00:00",
|
||||||
|
"end": "2025-11-24T12:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N02",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV24-003",
|
||||||
|
"title": "Klipning dame",
|
||||||
|
"start": "2025-11-24T14:00:00",
|
||||||
|
"end": "2025-11-24T15:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N03",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "teal" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV25-001",
|
||||||
|
"title": "Farve behandling",
|
||||||
|
"start": "2025-11-25T09:00:00",
|
||||||
|
"end": "2025-11-25T11:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N04",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "orange" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV25-002",
|
||||||
|
"title": "Permanent",
|
||||||
|
"start": "2025-11-25T12:00:00",
|
||||||
|
"end": "2025-11-25T14:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N05",
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "indigo" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV26-001",
|
||||||
|
"title": "Highlights",
|
||||||
|
"start": "2025-11-26T10:00:00",
|
||||||
|
"end": "2025-11-26T12:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N06",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST006",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "lime" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV26-002",
|
||||||
|
"title": "Børneklip",
|
||||||
|
"start": "2025-11-26T14:00:00",
|
||||||
|
"end": "2025-11-26T14:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N07",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "cyan" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV27-001",
|
||||||
|
"title": "Olaplex behandling",
|
||||||
|
"start": "2025-11-27T09:00:00",
|
||||||
|
"end": "2025-11-27T10:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N08",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST008",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "pink" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV27-002",
|
||||||
|
"title": "Skæg trim",
|
||||||
|
"start": "2025-11-27T11:00:00",
|
||||||
|
"end": "2025-11-27T11:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N09",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST009",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "teal" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-NOV28-001",
|
||||||
|
"title": "Extensions",
|
||||||
|
"start": "2025-11-28T09:00:00",
|
||||||
|
"end": "2025-11-28T12:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N10",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST010",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "deep-purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC01-001",
|
||||||
|
"title": "Klipning og føn",
|
||||||
|
"start": "2025-12-01T10:00:00",
|
||||||
|
"end": "2025-12-01T11:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N11",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST011",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "blue" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC01-002",
|
||||||
|
"title": "Farve korrektion",
|
||||||
|
"start": "2025-12-01T13:00:00",
|
||||||
|
"end": "2025-12-01T16:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N12",
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"customerId": "CUST012",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "magenta" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC02-001",
|
||||||
|
"title": "Bryllupsfrisure prøve",
|
||||||
|
"start": "2025-12-02T09:00:00",
|
||||||
|
"end": "2025-12-02T11:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N13",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST013",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "green" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC02-002",
|
||||||
|
"title": "Herreklip express",
|
||||||
|
"start": "2025-12-02T14:00:00",
|
||||||
|
"end": "2025-12-02T14:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N14",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST014",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "amber" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC03-001",
|
||||||
|
"title": "Keratin behandling",
|
||||||
|
"start": "2025-12-03T10:00:00",
|
||||||
|
"end": "2025-12-03T13:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N15",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "violet" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC03-002",
|
||||||
|
"title": "Vask og styling",
|
||||||
|
"start": "2025-12-03T15:00:00",
|
||||||
|
"end": "2025-12-03T15:45:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N16",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "light-green" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC04-001",
|
||||||
|
"title": "Balayage kort hår",
|
||||||
|
"start": "2025-12-04T09:00:00",
|
||||||
|
"end": "2025-12-04T10:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N17",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC04-002",
|
||||||
|
"title": "Ferie",
|
||||||
|
"start": "2025-12-04T00:00:00",
|
||||||
|
"end": "2025-12-05T23:59:59",
|
||||||
|
"type": "vacation",
|
||||||
|
"allDay": true,
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "red" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC05-001",
|
||||||
|
"title": "Dameklip langt hår",
|
||||||
|
"start": "2025-12-05T11:00:00",
|
||||||
|
"end": "2025-12-05T12:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N18",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "pink" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC05-002",
|
||||||
|
"title": "Highlights delvis",
|
||||||
|
"start": "2025-12-05T14:00:00",
|
||||||
|
"end": "2025-12-05T15:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-N19",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "lime" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC08-001",
|
||||||
|
"title": "Balayage langt hår",
|
||||||
|
"description": "Fuld balayage behandling",
|
||||||
|
"start": "2025-12-08T10:00:00",
|
||||||
|
"end": "2025-12-08T11:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-001",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC08-002",
|
||||||
|
"title": "Klipning og styling",
|
||||||
|
"description": "Dameklipning med føn",
|
||||||
|
"start": "2025-12-08T14:00:00",
|
||||||
|
"end": "2025-12-08T15:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-002",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "pink" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC08-003",
|
||||||
|
"title": "Permanent",
|
||||||
|
"description": "Permanent med curler",
|
||||||
|
"start": "2025-12-08T09:00:00",
|
||||||
|
"end": "2025-12-08T11:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-003",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "indigo" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC08-004",
|
||||||
|
"title": "Farve behandling",
|
||||||
|
"description": "Farve og pleje",
|
||||||
|
"start": "2025-12-08T13:00:00",
|
||||||
|
"end": "2025-12-08T15:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-004",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "orange" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC09-001",
|
||||||
|
"title": "Herreklipning",
|
||||||
|
"description": "Klassisk herreklip",
|
||||||
|
"start": "2025-12-09T11:00:00",
|
||||||
|
"end": "2025-12-09T11:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-005",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "teal" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC09-002",
|
||||||
|
"title": "Kursus",
|
||||||
|
"description": "Ekstern kursusdag",
|
||||||
|
"start": "2025-12-09T00:00:00",
|
||||||
|
"end": "2025-12-10T23:59:59",
|
||||||
|
"type": "blocked",
|
||||||
|
"allDay": true,
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "cyan" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC09-003",
|
||||||
|
"title": "Bryllupsfrisure",
|
||||||
|
"description": "Bryllupsfrisure med prøve",
|
||||||
|
"start": "2025-12-09T08:00:00",
|
||||||
|
"end": "2025-12-09T10:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-007",
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "green" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC10-001",
|
||||||
|
"title": "Highlights",
|
||||||
|
"description": "Highlights med folie",
|
||||||
|
"start": "2025-12-10T12:00:00",
|
||||||
|
"end": "2025-12-10T14:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-008",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST008",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "lime" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC10-002",
|
||||||
|
"title": "Styling konsultation",
|
||||||
|
"description": "Rådgivning om ny stil",
|
||||||
|
"start": "2025-12-10T15:00:00",
|
||||||
|
"end": "2025-12-10T15:30:00",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "amber" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC10-003",
|
||||||
|
"title": "Olaplex behandling",
|
||||||
|
"description": "Fuld Olaplex kur",
|
||||||
|
"start": "2025-12-10T09:00:00",
|
||||||
|
"end": "2025-12-10T10:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-009",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST009",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "blue" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC11-001",
|
||||||
|
"title": "Extensions",
|
||||||
|
"description": "Hair extensions påsætning",
|
||||||
|
"start": "2025-12-11T09:00:00",
|
||||||
|
"end": "2025-12-11T12:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-010",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST010",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "deep-purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC11-002",
|
||||||
|
"title": "Børneklip",
|
||||||
|
"description": "Klipning af barn",
|
||||||
|
"start": "2025-12-11T14:00:00",
|
||||||
|
"end": "2025-12-11T14:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-011",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST011",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "light-blue" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC11-003",
|
||||||
|
"title": "Team møde",
|
||||||
|
"description": "Morgen briefing",
|
||||||
|
"start": "2025-12-11T08:00:00",
|
||||||
|
"end": "2025-12-11T08:30:00",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "red" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC12-001",
|
||||||
|
"title": "Keratin behandling",
|
||||||
|
"description": "Brasiliansk keratin",
|
||||||
|
"start": "2025-12-12T10:00:00",
|
||||||
|
"end": "2025-12-12T13:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-012",
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"customerId": "CUST012",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "violet" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC12-002",
|
||||||
|
"title": "Vask og føn",
|
||||||
|
"description": "Express service",
|
||||||
|
"start": "2025-12-12T15:00:00",
|
||||||
|
"end": "2025-12-12T15:45:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-013",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST013",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "light-green" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC12-003",
|
||||||
|
"title": "Farvekorrektion",
|
||||||
|
"description": "Korrektion af tidligere farve",
|
||||||
|
"start": "2025-12-12T09:00:00",
|
||||||
|
"end": "2025-12-12T12:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-014",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST014",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "magenta" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC15-001",
|
||||||
|
"title": "Juleklipning",
|
||||||
|
"start": "2025-12-15T09:00:00",
|
||||||
|
"end": "2025-12-15T10:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F01",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST001",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "red" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC15-002",
|
||||||
|
"title": "Balayage jul",
|
||||||
|
"start": "2025-12-15T11:00:00",
|
||||||
|
"end": "2025-12-15T13:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F02",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST002",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC15-003",
|
||||||
|
"title": "Herreklip",
|
||||||
|
"start": "2025-12-15T14:00:00",
|
||||||
|
"end": "2025-12-15T14:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F03",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST003",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "blue" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC16-001",
|
||||||
|
"title": "Farve og klip",
|
||||||
|
"start": "2025-12-16T10:00:00",
|
||||||
|
"end": "2025-12-16T12:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F04",
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"customerId": "CUST004",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "orange" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC16-002",
|
||||||
|
"title": "Permanent",
|
||||||
|
"start": "2025-12-16T13:00:00",
|
||||||
|
"end": "2025-12-16T15:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F05",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST005",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "indigo" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC17-001",
|
||||||
|
"title": "Julefrokost",
|
||||||
|
"start": "2025-12-17T12:00:00",
|
||||||
|
"end": "2025-12-17T14:00:00",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "green" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC17-002",
|
||||||
|
"title": "Extensions fjernelse",
|
||||||
|
"start": "2025-12-17T09:00:00",
|
||||||
|
"end": "2025-12-17T11:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F06",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST006",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "deep-purple" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC18-001",
|
||||||
|
"title": "Highlights jul",
|
||||||
|
"start": "2025-12-18T10:00:00",
|
||||||
|
"end": "2025-12-18T12:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F07",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST007",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "lime" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC18-002",
|
||||||
|
"title": "Børneklip jul",
|
||||||
|
"start": "2025-12-18T14:00:00",
|
||||||
|
"end": "2025-12-18T14:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F08",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST008",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "cyan" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC19-001",
|
||||||
|
"title": "Festfrisure",
|
||||||
|
"start": "2025-12-19T09:00:00",
|
||||||
|
"end": "2025-12-19T10:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F09",
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"customerId": "CUST009",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "pink" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC19-002",
|
||||||
|
"title": "Julestyling",
|
||||||
|
"start": "2025-12-19T11:00:00",
|
||||||
|
"end": "2025-12-19T12:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F10",
|
||||||
|
"resourceId": "EMP005",
|
||||||
|
"customerId": "CUST010",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "amber" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC19-003",
|
||||||
|
"title": "Klipning og farve",
|
||||||
|
"start": "2025-12-19T14:00:00",
|
||||||
|
"end": "2025-12-19T16:30:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F11",
|
||||||
|
"resourceId": "EMP001",
|
||||||
|
"customerId": "CUST011",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "violet" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC22-001",
|
||||||
|
"title": "Sidste jul klip",
|
||||||
|
"start": "2025-12-22T09:00:00",
|
||||||
|
"end": "2025-12-22T10:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F12",
|
||||||
|
"resourceId": "EMP002",
|
||||||
|
"customerId": "CUST012",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "red" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC22-002",
|
||||||
|
"title": "Juleaften forberedelse",
|
||||||
|
"start": "2025-12-22T11:00:00",
|
||||||
|
"end": "2025-12-22T13:00:00",
|
||||||
|
"type": "customer",
|
||||||
|
"allDay": false,
|
||||||
|
"bookingId": "BOOK-F13",
|
||||||
|
"resourceId": "EMP003",
|
||||||
|
"customerId": "CUST013",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "green" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EVT-DEC22-003",
|
||||||
|
"title": "Juleferie start",
|
||||||
|
"start": "2025-12-22T00:00:00",
|
||||||
|
"end": "2025-12-27T23:59:59",
|
||||||
|
"type": "vacation",
|
||||||
|
"allDay": true,
|
||||||
|
"resourceId": "EMP004",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "color": "light-blue" }
|
||||||
|
}
|
||||||
|
]
|
||||||
135
.workbench/POC/data/mock-resource-events.json
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
{
|
||||||
|
"date": "2025-08-05",
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"name": "karina.knudsen",
|
||||||
|
"displayName": "Karina Knudsen",
|
||||||
|
"avatarUrl": "/avatars/karina.jpg",
|
||||||
|
"employeeId": "EMP001",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"title": "Balayage langt hår",
|
||||||
|
"start": "2025-08-05T10:00:00",
|
||||||
|
"end": "2025-08-05T11:00:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 60, "color": "#9c27b0" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "2",
|
||||||
|
"title": "Klipning og styling",
|
||||||
|
"start": "2025-08-05T14:00:00",
|
||||||
|
"end": "2025-08-05T15:30:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 90, "color": "#e91e63" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "maria.hansen",
|
||||||
|
"displayName": "Maria Hansen",
|
||||||
|
"avatarUrl": "/avatars/maria.jpg",
|
||||||
|
"employeeId": "EMP002",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"id": "3",
|
||||||
|
"title": "Permanent",
|
||||||
|
"start": "2025-08-05T09:00:00",
|
||||||
|
"end": "2025-08-05T11:00:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 120, "color": "#3f51b5" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "4",
|
||||||
|
"title": "Farve behandling",
|
||||||
|
"start": "2025-08-05T13:00:00",
|
||||||
|
"end": "2025-08-05T15:00:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 120, "color": "#ff9800" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lars.nielsen",
|
||||||
|
"displayName": "Lars Nielsen",
|
||||||
|
"avatarUrl": "/avatars/lars.jpg",
|
||||||
|
"employeeId": "EMP003",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"id": "5",
|
||||||
|
"title": "Herreklipning",
|
||||||
|
"start": "2025-08-05T11:00:00",
|
||||||
|
"end": "2025-08-05T11:30:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 30, "color": "#795548" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "6",
|
||||||
|
"title": "Skæg trimning",
|
||||||
|
"start": "2025-08-05T16:00:00",
|
||||||
|
"end": "2025-08-05T16:30:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 30, "color": "#607d8b" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "anna.petersen",
|
||||||
|
"displayName": "Anna Petersen",
|
||||||
|
"avatarUrl": "/avatars/anna.jpg",
|
||||||
|
"employeeId": "EMP004",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"id": "7",
|
||||||
|
"title": "Bryllupsfrisure",
|
||||||
|
"start": "2025-08-05T08:00:00",
|
||||||
|
"end": "2025-08-05T10:00:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 120, "color": "#009688" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "thomas.olsen",
|
||||||
|
"displayName": "Thomas Olsen",
|
||||||
|
"avatarUrl": "/avatars/thomas.jpg",
|
||||||
|
"employeeId": "EMP005",
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"id": "8",
|
||||||
|
"title": "Highlights",
|
||||||
|
"start": "2025-08-05T12:00:00",
|
||||||
|
"end": "2025-08-05T14:00:00",
|
||||||
|
"type": "work",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 120, "color": "#8bc34a" }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9",
|
||||||
|
"title": "Styling konsultation",
|
||||||
|
"start": "2025-08-05T15:00:00",
|
||||||
|
"end": "2025-08-05T15:30:00",
|
||||||
|
"type": "meeting",
|
||||||
|
"allDay": false,
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"metadata": { "duration": 30, "color": "#cddc39" }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
134
.workbench/POC/data/mock-resources.json
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "EMP001",
|
||||||
|
"name": "camilla.jensen",
|
||||||
|
"displayName": "Camilla Jensen",
|
||||||
|
"type": "person",
|
||||||
|
"avatarUrl": "/avatars/camilla.jpg",
|
||||||
|
"color": "#9c27b0",
|
||||||
|
"isActive": true,
|
||||||
|
"defaultSchedule": {
|
||||||
|
"1": { "start": "09:00", "end": "17:00" },
|
||||||
|
"2": { "start": "09:00", "end": "17:00" },
|
||||||
|
"3": { "start": "09:00", "end": "15:00" },
|
||||||
|
"4": { "start": "09:00", "end": "17:00" },
|
||||||
|
"5": { "start": "09:00", "end": "14:00" },
|
||||||
|
"6": null,
|
||||||
|
"7": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"role": "master stylist",
|
||||||
|
"specialties": ["balayage", "color", "bridal"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EMP002",
|
||||||
|
"name": "isabella.hansen",
|
||||||
|
"displayName": "Isabella Hansen",
|
||||||
|
"type": "person",
|
||||||
|
"avatarUrl": "/avatars/isabella.jpg",
|
||||||
|
"color": "#e91e63",
|
||||||
|
"isActive": true,
|
||||||
|
"defaultSchedule": {
|
||||||
|
"1": { "start": "10:00", "end": "18:00" },
|
||||||
|
"2": { "start": "10:00", "end": "18:00" },
|
||||||
|
"3": { "start": "10:00", "end": "18:00" },
|
||||||
|
"4": { "start": "10:00", "end": "18:00" },
|
||||||
|
"5": { "start": "10:00", "end": "16:00" },
|
||||||
|
"6": null,
|
||||||
|
"7": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"role": "master stylist",
|
||||||
|
"specialties": ["highlights", "ombre", "styling"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EMP003",
|
||||||
|
"name": "alexander.nielsen",
|
||||||
|
"displayName": "Alexander Nielsen",
|
||||||
|
"type": "person",
|
||||||
|
"avatarUrl": "/avatars/alexander.jpg",
|
||||||
|
"color": "#3f51b5",
|
||||||
|
"isActive": true,
|
||||||
|
"defaultSchedule": {
|
||||||
|
"1": { "start": "08:00", "end": "16:00" },
|
||||||
|
"2": { "start": "08:00", "end": "16:00" },
|
||||||
|
"3": { "start": "08:00", "end": "16:00" },
|
||||||
|
"4": { "start": "08:00", "end": "16:00" },
|
||||||
|
"5": { "start": "08:00", "end": "14:00" },
|
||||||
|
"6": null,
|
||||||
|
"7": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"role": "master stylist",
|
||||||
|
"specialties": ["men's cuts", "beard", "fade"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "EMP004",
|
||||||
|
"name": "viktor.andersen",
|
||||||
|
"displayName": "Viktor Andersen",
|
||||||
|
"type": "person",
|
||||||
|
"avatarUrl": "/avatars/viktor.jpg",
|
||||||
|
"color": "#009688",
|
||||||
|
"isActive": true,
|
||||||
|
"defaultSchedule": {
|
||||||
|
"1": { "start": "09:00", "end": "17:00" },
|
||||||
|
"2": null,
|
||||||
|
"3": { "start": "09:00", "end": "17:00" },
|
||||||
|
"4": { "start": "09:00", "end": "17:00" },
|
||||||
|
"5": { "start": "09:00", "end": "17:00" },
|
||||||
|
"6": { "start": "10:00", "end": "14:00" },
|
||||||
|
"7": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"role": "stylist",
|
||||||
|
"specialties": ["cuts", "styling", "perms"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "STUDENT001",
|
||||||
|
"name": "line.pedersen",
|
||||||
|
"displayName": "Line Pedersen (Elev)",
|
||||||
|
"type": "person",
|
||||||
|
"avatarUrl": "/avatars/line.jpg",
|
||||||
|
"color": "#8bc34a",
|
||||||
|
"isActive": true,
|
||||||
|
"defaultSchedule": {
|
||||||
|
"1": { "start": "09:00", "end": "15:00" },
|
||||||
|
"2": { "start": "09:00", "end": "15:00" },
|
||||||
|
"3": { "start": "09:00", "end": "15:00" },
|
||||||
|
"4": null,
|
||||||
|
"5": { "start": "09:00", "end": "15:00" },
|
||||||
|
"6": null,
|
||||||
|
"7": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"role": "student",
|
||||||
|
"specialties": ["wash", "blow-dry", "basic cuts"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "STUDENT002",
|
||||||
|
"name": "mads.larsen",
|
||||||
|
"displayName": "Mads Larsen (Elev)",
|
||||||
|
"type": "person",
|
||||||
|
"avatarUrl": "/avatars/mads.jpg",
|
||||||
|
"color": "#ff9800",
|
||||||
|
"isActive": true,
|
||||||
|
"defaultSchedule": {
|
||||||
|
"1": null,
|
||||||
|
"2": { "start": "10:00", "end": "16:00" },
|
||||||
|
"3": { "start": "10:00", "end": "16:00" },
|
||||||
|
"4": { "start": "10:00", "end": "16:00" },
|
||||||
|
"5": null,
|
||||||
|
"6": null,
|
||||||
|
"7": null
|
||||||
|
},
|
||||||
|
"metadata": {
|
||||||
|
"role": "student",
|
||||||
|
"specialties": ["wash", "styling assistance"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
14
.workbench/POC/data/mock-teams.json
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "team1",
|
||||||
|
"name": "Team Alpha",
|
||||||
|
"resourceIds": ["EMP001", "EMP002"],
|
||||||
|
"syncStatus": "synced"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "team2",
|
||||||
|
"name": "Team Beta",
|
||||||
|
"resourceIds": ["EMP003", "EMP004"],
|
||||||
|
"syncStatus": "synced"
|
||||||
|
}
|
||||||
|
]
|
||||||
69
.workbench/POC/data/tenant-settings.json
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "workweek",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"presets": {
|
||||||
|
"standard": {
|
||||||
|
"id": "standard",
|
||||||
|
"workDays": [1, 2, 3, 4, 5],
|
||||||
|
"label": "Man-Fre",
|
||||||
|
"periodDays": 7
|
||||||
|
},
|
||||||
|
"compressed": {
|
||||||
|
"id": "compressed",
|
||||||
|
"workDays": [1, 2, 3],
|
||||||
|
"label": "Man-Ons",
|
||||||
|
"periodDays": 7
|
||||||
|
},
|
||||||
|
"midweek": {
|
||||||
|
"id": "midweek",
|
||||||
|
"workDays": [4, 5],
|
||||||
|
"label": "Tors-Fre",
|
||||||
|
"periodDays": 7
|
||||||
|
},
|
||||||
|
"weekend": {
|
||||||
|
"id": "weekend",
|
||||||
|
"workDays": [6, 7],
|
||||||
|
"label": "Weekend",
|
||||||
|
"periodDays": 7
|
||||||
|
},
|
||||||
|
"fullweek": {
|
||||||
|
"id": "fullweek",
|
||||||
|
"workDays": [1, 2, 3, 4, 5, 6, 7],
|
||||||
|
"label": "Alle dage",
|
||||||
|
"periodDays": 7
|
||||||
|
},
|
||||||
|
"day": {
|
||||||
|
"id": "day",
|
||||||
|
"workDays": [1],
|
||||||
|
"label": "Dag",
|
||||||
|
"periodDays": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"defaultPreset": "standard",
|
||||||
|
"firstDayOfWeek": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "grid",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"dayStartHour": 6,
|
||||||
|
"dayEndHour": 22,
|
||||||
|
"workStartHour": 8,
|
||||||
|
"workEndHour": 17,
|
||||||
|
"hourHeight": 80,
|
||||||
|
"snapInterval": 15
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "timeFormat",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"timezone": "Europe/Copenhagen",
|
||||||
|
"locale": "da-DK",
|
||||||
|
"use24HourFormat": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "views",
|
||||||
|
"syncStatus": "synced",
|
||||||
|
"availableViews": ["simple", "resource", "team", "department"],
|
||||||
|
"defaultView": "simple"
|
||||||
|
}
|
||||||
|
]
|
||||||
45
.workbench/POC/data/viewconfigs.json
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "day",
|
||||||
|
"groupings": [
|
||||||
|
{ "type": "resource", "values": ["EMP001", "EMP002"], "idProperty": "resourceId" },
|
||||||
|
{ "type": "date", "values": [], "idProperty": "date", "derivedFrom": "start", "hideHeader": true }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "simple",
|
||||||
|
"groupings": [
|
||||||
|
{ "type": "date", "values": [], "idProperty": "date", "derivedFrom": "start" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "resource",
|
||||||
|
"groupings": [
|
||||||
|
{ "type": "resource", "values": ["EMP001", "EMP002"], "idProperty": "resourceId" },
|
||||||
|
{ "type": "date", "values": [], "idProperty": "date", "derivedFrom": "start" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "team",
|
||||||
|
"groupings": [
|
||||||
|
{ "type": "team", "values": ["team1", "team2"] },
|
||||||
|
{ "type": "resource", "values": ["EMP001", "EMP002", "EMP003", "EMP004"], "idProperty": "resourceId", "belongsTo": "team.resourceIds" },
|
||||||
|
{ "type": "date", "values": [], "idProperty": "date", "derivedFrom": "start" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "department",
|
||||||
|
"groupings": [
|
||||||
|
{ "type": "department", "values": ["dept-styling", "dept-training"] },
|
||||||
|
{ "type": "resource", "values": ["EMP001", "EMP002", "EMP003", "EMP004", "STUDENT001", "STUDENT002"], "idProperty": "resourceId", "belongsTo": "department.resourceIds" },
|
||||||
|
{ "type": "date", "values": [], "idProperty": "date", "derivedFrom": "start" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "picker",
|
||||||
|
"groupings": [
|
||||||
|
{ "type": "resource", "values": ["EMP001", "EMP002", "EMP003", "EMP004"], "idProperty": "resourceId" },
|
||||||
|
{ "type": "date", "values": [], "idProperty": "date", "derivedFrom": "start" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
255
.workbench/POC/docs/ai-booking-optimering.md
Normal file
|
|
@ -0,0 +1,255 @@
|
||||||
|
# AI Booking Optimering
|
||||||
|
|
||||||
|
## Produktoversigt
|
||||||
|
|
||||||
|
AI Booking Optimering er et intelligent tillægsmodul der hjælper saloner med at maksimere deres kalenderudnyttelse og reducere tabt omsætning fra tomme tidsslots.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
### Feature 1: Smart Tidsforslag (Real-time)
|
||||||
|
|
||||||
|
Når kunder booker online, analyserer AI'en eksisterende bookinger og foreslår de mest optimale tidspunkter.
|
||||||
|
|
||||||
|
**Hvordan det virker:**
|
||||||
|
1. Kunden vælger ydelse (f.eks. Dameklip, 60 min)
|
||||||
|
2. AI'en analyserer dagens/ugens bookinger for den valgte medarbejder
|
||||||
|
3. Hvert ledigt tidsslot får en score baseret på:
|
||||||
|
- Minimering af huller
|
||||||
|
- Optimal udnyttelse af åbningstiden
|
||||||
|
- Kontinuitet i bookinger
|
||||||
|
4. Top 2-3 bedste slots markeres med "Anbefalet" badge
|
||||||
|
|
||||||
|
**Scoring-algoritme:**
|
||||||
|
|
||||||
|
| Kriterium | Score |
|
||||||
|
|-----------|-------|
|
||||||
|
| Starter ved åbningstid | +3 |
|
||||||
|
| Slutter præcis på næste booking | +3 |
|
||||||
|
| Starter lige efter en booking | +2 |
|
||||||
|
| Slutter ved lukketid | +1 |
|
||||||
|
| Skaber hul < 30 min | -2 |
|
||||||
|
|
||||||
|
**UX-principper:**
|
||||||
|
- Blød anbefaling - kunden kan stadig vælge alle ledige tider
|
||||||
|
- Grøn badge med AI-ikon på anbefalede tider
|
||||||
|
- Info-tekst forklarer fordelen
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Feature 2: Kalender-optimering Dashboard
|
||||||
|
|
||||||
|
Salonejere får et dashboard der identificerer huller og foreslår handlinger.
|
||||||
|
|
||||||
|
**Dashboard-komponenter:**
|
||||||
|
|
||||||
|
1. **Statistik-kort**
|
||||||
|
- Huller i dag
|
||||||
|
- Tabt omsætning (estimeret)
|
||||||
|
- Huller denne uge
|
||||||
|
- Potentiel besparelse
|
||||||
|
|
||||||
|
2. **Mini-kalender**
|
||||||
|
- Visuel oversigt over ugen
|
||||||
|
- Farvekodede dage (grøn = optimalt, gul = huller, rød = kritisk)
|
||||||
|
|
||||||
|
3. **Hul-liste**
|
||||||
|
- Detaljeret visning af hvert identificeret hul
|
||||||
|
- Medarbejder og tidspunkt
|
||||||
|
- Estimeret tabt omsætning
|
||||||
|
- AI-forslag til at fylde hullet
|
||||||
|
|
||||||
|
4. **AI-forslag typer:**
|
||||||
|
- **Flyt booking**: Foreslå at flytte en eksisterende kundes tid
|
||||||
|
- **Venteliste**: Kontakt kunde fra ventelisten
|
||||||
|
- **Rabattilbud**: Send SMS med rabat for at fylde hullet
|
||||||
|
|
||||||
|
5. **SMS-historik**
|
||||||
|
- Track sendte tilbud
|
||||||
|
- Accept/afvisning statistik
|
||||||
|
- Pending tilbud
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Teknisk Implementation
|
||||||
|
|
||||||
|
### POC 1: poc-booking-v2.html
|
||||||
|
|
||||||
|
**Tilføjede komponenter:**
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
// Mock data for eksisterende bookinger
|
||||||
|
const existingBookings = {
|
||||||
|
'EMP001': {
|
||||||
|
'2026-01-06': [
|
||||||
|
{ start: '10:00', end: '11:00', service: 'Dameklip' },
|
||||||
|
{ start: '13:30', end: '14:30', service: 'Herreklip' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Scoring-algoritme
|
||||||
|
function calculateOptimalSlots(serviceDuration, date, employeeId) {
|
||||||
|
// 1. Hent bookinger for dato/medarbejder
|
||||||
|
// 2. Generer alle mulige slots (30 min intervaller)
|
||||||
|
// 3. Tjek overlap med eksisterende bookinger
|
||||||
|
// 4. Beregn score for hvert ledigt slot
|
||||||
|
// 5. Marker top 3 med positiv score som "recommended"
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**CSS-styling:**
|
||||||
|
- `.time-slot.recommended` - Grøn border og baggrund
|
||||||
|
- `.ai-badge` - Absolut positioneret badge med sparkle-ikon
|
||||||
|
- `.ai-info` - Info-boks over tidsgrid
|
||||||
|
|
||||||
|
### POC 2: poc-ai-booking-optimizer.html
|
||||||
|
|
||||||
|
**Struktur:**
|
||||||
|
- Topbar med AI-badge
|
||||||
|
- Stats-grid med 4 KPI-kort
|
||||||
|
- Main-grid med kalender og hul-liste
|
||||||
|
- Sidebar med optimeringsscore og SMS-historik
|
||||||
|
|
||||||
|
**Mock data:**
|
||||||
|
- `gaps[]` - Identificerede huller med forslag
|
||||||
|
- `weekDays[]` - Ugevisning med gap-status
|
||||||
|
- `smsHistory[]` - Historik over sendte tilbud
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Forretningsværdi
|
||||||
|
|
||||||
|
### ROI-beregning
|
||||||
|
|
||||||
|
```
|
||||||
|
Typisk salon:
|
||||||
|
- 4 medarbejdere
|
||||||
|
- 40 timer/uge pr. medarbejder
|
||||||
|
- 15% tomme slots = 24 timer/uge tabt
|
||||||
|
- Gennemsnitlig timepris: 500 kr.
|
||||||
|
- Tabt omsætning: 12.000 kr./uge = 624.000 kr./år
|
||||||
|
|
||||||
|
AI-optimering fylder 50% af huller:
|
||||||
|
- Ekstra omsætning: 312.000 kr./år
|
||||||
|
|
||||||
|
Pris for AI-modul: 499 kr./md = 5.988 kr./år
|
||||||
|
ROI: 52x investering
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nøgletal at tracke
|
||||||
|
|
||||||
|
| Metrik | Beskrivelse |
|
||||||
|
|--------|-------------|
|
||||||
|
| Kalenderudnyttelse | % af tilgængelige timer der er booket |
|
||||||
|
| Gennemsnitligt hul | Minutter tabt pr. dag i gaps |
|
||||||
|
| Accept-rate | % af kunder der accepterer flyttetilbud |
|
||||||
|
| Tabt omsætning | Estimeret kr. i tomme slots |
|
||||||
|
| Optimeringsscore | Samlet effektivitet (mål: 90%+) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Fremtidig AI-udvidelse
|
||||||
|
|
||||||
|
### Niveau 1: Regelbaseret (Nuværende POC)
|
||||||
|
- Statiske scoring-regler
|
||||||
|
- Ingen læring
|
||||||
|
- Fungerer for alle saloner ens
|
||||||
|
|
||||||
|
### Niveau 2: Machine Learning
|
||||||
|
- Lærer fra salonens historik
|
||||||
|
- Personlige kundeprofilenr
|
||||||
|
- Forudsigelse af no-shows
|
||||||
|
- Dynamisk prisjustering
|
||||||
|
|
||||||
|
### ML-features (fremtidig):
|
||||||
|
|
||||||
|
1. **Historisk mønstergenkendelse**
|
||||||
|
- Populære vs. døde tider
|
||||||
|
- Sæsonvariation
|
||||||
|
- Service-specifikke mønstre
|
||||||
|
|
||||||
|
2. **Kundesegmentering**
|
||||||
|
- Fleksible vs. fastlåste kunder
|
||||||
|
- Pris-sensitive kunder
|
||||||
|
- No-show risiko-profiler
|
||||||
|
|
||||||
|
3. **Intelligent rabat-beregning**
|
||||||
|
- Dynamisk rabat baseret på:
|
||||||
|
- Hullets "værdi"
|
||||||
|
- Kundens prissensitivitet
|
||||||
|
- Sandsynlighed for naturlig booking
|
||||||
|
|
||||||
|
4. **Proaktiv optimering**
|
||||||
|
- Forudsig huller før de opstår
|
||||||
|
- Automatisk udsend tilbud
|
||||||
|
- Venteliste-matching
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Integration med eksisterende system
|
||||||
|
|
||||||
|
### Data-flow
|
||||||
|
|
||||||
|
```
|
||||||
|
Booking system
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐
|
||||||
|
│ AI Optimizer │
|
||||||
|
│ - Analyse │
|
||||||
|
│ - Scoring │
|
||||||
|
│ - Anbefalinger │
|
||||||
|
└─────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────┐ ┌─────────────────┐
|
||||||
|
│ Booking Widget │ │ Dashboard │
|
||||||
|
│ (kundevisning) │ │ (ejervisning) │
|
||||||
|
└─────────────────┘ └─────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
### API-endpoints (fremtidig)
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/ai/optimal-slots?date=X&employee=Y&duration=Z
|
||||||
|
POST /api/ai/send-offer
|
||||||
|
GET /api/ai/gaps?week=X
|
||||||
|
GET /api/ai/stats
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
### Indstillinger pr. salon
|
||||||
|
|
||||||
|
| Indstilling | Beskrivelse | Default |
|
||||||
|
|-------------|-------------|---------|
|
||||||
|
| `minGapMinutes` | Mindste hul der tæller som tabt | 30 min |
|
||||||
|
| `recommendedSlots` | Antal anbefalede slots | 3 |
|
||||||
|
| `defaultDiscount` | Standard rabat ved flytning | 5% |
|
||||||
|
| `autoSendOffers` | Automatisk udsend tilbud | Fra |
|
||||||
|
| `smsEnabled` | Aktiver SMS-udsendelse | Til |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Filer
|
||||||
|
|
||||||
|
| Fil | Beskrivelse |
|
||||||
|
|-----|-------------|
|
||||||
|
| `poc-booking-v2.html` | Kundens booking-widget med AI-anbefalinger |
|
||||||
|
| `poc-ai-booking-optimizer.html` | Dashboard til salonejere |
|
||||||
|
| `docs/ai-booking-optimering.md` | Denne dokumentation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### Version 1.0 (Januar 2026)
|
||||||
|
- Initial POC implementation
|
||||||
|
- Regelbaseret scoring-algoritme
|
||||||
|
- Dashboard med hul-identifikation
|
||||||
|
- SMS-historik tracking
|
||||||
BIN
.workbench/POC/fonts/Poppins-Black.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-BlackItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-Bold.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-BoldItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-ExtraBold.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-ExtraBoldItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-ExtraLight.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-ExtraLightItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-Italic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-Light.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-LightItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-Medium.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-MediumItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-Regular.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-SemiBold.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-SemiBoldItalic.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-Thin.woff
Normal file
BIN
.workbench/POC/fonts/Poppins-ThinItalic.woff
Normal file
2
.workbench/POC/icons/angle-small-left.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="512" height="512"><g id="_01_align_center" data-name="01 align center"><path d="M13.775,18.707,8.482,13.414a2,2,0,0,1,0-2.828l5.293-5.293,1.414,1.414L9.9,12l5.293,5.293Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 289 B |
2
.workbench/POC/icons/angle-small-right.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="512" height="512"><g id="_01_align_center" data-name="01 align center"><path d="M10.811,18.707,9.4,17.293,14.689,12,9.4,6.707l1.415-1.414L16.1,10.586a2,2,0,0,1,0,2.828Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 288 B |
1
.workbench/POC/icons/bank.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg id="Layer_1" height="512" viewBox="0 0 24 24" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><path d="m24 23a1 1 0 0 1 -1 1h-22a1 1 0 0 1 0-2h22a1 1 0 0 1 1 1zm-23.709-14.448a2.443 2.443 0 0 1 .153-2.566 4.716 4.716 0 0 1 1.668-1.5l7.501-3.904a5.174 5.174 0 0 1 4.774 0l7.5 3.907a4.716 4.716 0 0 1 1.668 1.5 2.443 2.443 0 0 1 .153 2.566 2.713 2.713 0 0 1 -2.416 1.445h-.292v8h1a1 1 0 0 1 0 2h-20a1 1 0 0 1 0-2h1v-8h-.292a2.713 2.713 0 0 1 -2.417-1.448zm4.709 9.448h3v-8h-3zm5-8v8h4v-8zm9 0h-3v8h3zm-16.937-2.375a.717.717 0 0 0 .645.375h18.584a.717.717 0 0 0 .645-.375.452.452 0 0 0 -.024-.5 2.7 2.7 0 0 0 -.949-.864l-7.5-3.907a3.176 3.176 0 0 0 -2.926 0l-7.5 3.907a2.712 2.712 0 0 0 -.949.865.452.452 0 0 0 -.026.499z"/></svg>
|
||||||
|
After Width: | Height: | Size: 751 B |
4
.workbench/POC/icons/booking.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24">
|
||||||
|
<path d="m3.866,18.965c-.186.32-.521.5-.867.5-.17,0-.342-.043-.5-.134-1.542-.892-2.5-2.551-2.5-4.331V7C0,4.243,2.243,2,5,2v-1c0-.552.448-1,1-1s1,.448,1,1v1h7v-1c0-.552.447-1,1-1s1,.448,1,1v1c2.757,0,5,2.243,5,5v8c0,.552-.447,1-1,1s-1-.448-1-1v-6h-1c-.553,0-1-.448-1-1s.447-1,1-1h1c0-1.654-1.346-3-3-3H5c-1.654,0-3,1.346-3,3h8c.552,0,1,.448,1,1s-.448,1-1,1H2v6c0,1.068.575,2.064,1.5,2.599.478.276.642.888.365,1.366Zm16.892-.385l-3.749-1.401v-5.045c0-1.516-1.076-2.834-2.503-3.066-.881-.143-1.768.102-2.439.673-.672.571-1.058,1.405-1.058,2.286v7.563l-1.015-.808c-.007-.006-.016-.006-.023-.012-1.211-1.053-3.049-.975-4.153.207-1.13,1.208-1.066,3.11.13,4.23l.558.538c.186.18.435.28.694.28.9,0,1.342-1.095.694-1.72l-.568-.548c-.403-.378-.424-1.013-.046-1.416.375-.402,1.008-.421,1.41-.048.01.009,2.697,2.151,2.697,2.151.301.24.713.285,1.057.119.346-.167.566-.517.566-.901v-9.638c0-.294.129-.572.353-.763.228-.193.518-.273.822-.223.463.076.825.556.825,1.093v5.739c0,.417.259.791.65.937l4.399,1.644c1.104.412,1.866,1.438,1.943,2.612.035.529.475.935.997.935.022,0,.044,0,.066-.002.551-.037.969-.513.933-1.063-.129-1.958-1.4-3.668-3.24-4.354Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
4
.workbench/POC/icons/check-in-calendar.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24">
|
||||||
|
<path d="m24,7.5v11c0,3.033-2.467,5.5-5.5,5.5H5.5c-2.511,0-4.701-1.697-5.327-4.126-.207-.802.276-1.62,1.079-1.827.804-.208,1.62.277,1.827,1.079.284,1.104,1.28,1.874,2.421,1.874h13c1.378,0,2.5-1.122,2.5-2.5v-9.5H3v.5c0,.829-.671,1.5-1.5,1.5s-1.5-.671-1.5-1.5v-2C0,4.467,2.467,2,5.5,2h.5v-.5c0-.829.671-1.5,1.5-1.5s1.5.671,1.5,1.5v.5h6v-.5c0-.829.671-1.5,1.5-1.5s1.5.671,1.5,1.5v.5h.5c3.033,0,5.5,2.467,5.5,5.5Zm-15.346,10.748l3.063-3.063c.378-.378.378-.991,0-1.369l-3.063-3.063c-.61-.61-1.653-.178-1.653.685v1.563H1.5c-.829,0-1.5.671-1.5,1.5s.671,1.5,1.5,1.5h5.501v1.563c0,.863,1.043,1.295,1.653.685Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 745 B |
2
.workbench/POC/icons/coins.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M16.5,0c-4.206,0-7.5,1.977-7.5,4.5v2.587c-.483-.057-.985-.087-1.5-.087C3.294,7,0,8.977,0,11.5v8c0,2.523,3.294,4.5,7.5,4.5,3.407,0,6.216-1.297,7.16-3.131,.598,.087,1.214,.131,1.84,.131,4.206,0,7.5-1.977,7.5-4.5V4.5c0-2.523-3.294-4.5-7.5-4.5Zm5.5,12.5c0,1.18-2.352,2.5-5.5,2.5-.512,0-1.014-.035-1.5-.103v-1.984c.49,.057,.992,.087,1.5,.087,2.194,0,4.14-.538,5.5-1.411v.911ZM2,14.589c1.36,.873,3.306,1.411,5.5,1.411s4.14-.538,5.5-1.411v.911c0,1.18-2.352,2.5-5.5,2.5s-5.5-1.32-5.5-2.5v-.911Zm20-6.089c0,1.18-2.352,2.5-5.5,2.5-.535,0-1.06-.038-1.566-.112-.193-.887-.8-1.684-1.706-2.323,.984,.28,2.092,.435,3.272,.435,2.194,0,4.14-.538,5.5-1.411v.911Zm-5.5-6.5c3.148,0,5.5,1.32,5.5,2.5s-2.352,2.5-5.5,2.5-5.5-1.32-5.5-2.5,2.352-2.5,5.5-2.5ZM7.5,9c3.148,0,5.5,1.32,5.5,2.5s-2.352,2.5-5.5,2.5-5.5-1.32-5.5-2.5,2.352-2.5,5.5-2.5Zm0,13c-3.148,0-5.5-1.32-5.5-2.5v-.911c1.36,.873,3.306,1.411,5.5,1.411s4.14-.538,5.5-1.411v.911c0,1.18-2.352,2.5-5.5,2.5Zm9-3c-.512,0-1.014-.035-1.5-.103v-1.984c.49,.057,.992,.087,1.5,.087,2.194,0,4.14-.538,5.5-1.411v.911c0,1.18-2.352,2.5-5.5,2.5Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.2 KiB |
2
.workbench/POC/icons/comment-sms.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M19,24h-5.917C6.082,24,.47,19.208,.03,12.854-.211,9.378,1.057,5.977,3.509,3.521,5.96,1.066,9.364-.205,12.836,.028c6.26,.426,11.164,5.833,11.164,12.312v6.66c0,2.757-2.243,5-5,5ZM12.016,2.001c-2.657,0-5.209,1.049-7.092,2.934-2.043,2.046-3.1,4.882-2.899,7.781,.373,5.38,5.024,9.284,11.059,9.284h5.917c1.654,0,3-1.346,3-3v-6.66c0-5.431-4.084-9.962-9.299-10.315-.229-.016-.458-.023-.685-.023Zm2.984,7.624c0-.345-.28-.624-.625-.625-.399,0-.78,.173-1.042,.474l-1.333,1.526-1.352-1.548c-.251-.287-.578-.452-1.023-.452-.345,0-.625,.28-.625,.625v4.75c0,.345,.28,.625,.625,.625s.625-.28,.625-.625l.002-3.269,1.282,1.389c.251,.272,.681,.272,.932,0l1.281-1.388v3.267h.003c0,.345,.28,.625,.625,.625s.625-.28,.625-.625l-.003-.016,.003-4.734Zm-8.53,1.843c-.658-.243-1.257-.506-1.272-.506-.143-.097-.138-.243-.13-.302,.012-.079,.069-.273,.362-.361,.119-.035,.236-.049,.349-.047,.509,.008,.926,.324,.946,.34,.11,.095,.249,.158,.405,.158,.345,0,.625-.28,.625-.625,0-.197-.097-.365-.239-.48-.037-.031-.773-.648-1.766-.645-.216,0-.445,.03-.68,.101-.671,.202-1.146,.731-1.239,1.38-.087,.61,.178,1.197,.777,1.579,0,0,.678,.303,1.43,.58,.159,.059,.672,.276,.61,.621-.046,.256-.361,.521-.81,.521-.468,0-.919-.187-1.206-.503-.114-.125-.275-.206-.458-.206-.345,0-.625,.28-.625,.625,0,.161,.065,.304,.164,.414,.527,.566,1.309,.92,2.124,.92,1.021,0,1.88-.653,2.04-1.552,.121-.678-.186-1.562-1.408-2.014Zm12.558,0c-.658-.243-1.257-.506-1.272-.506-.143-.097-.138-.243-.13-.302,.012-.079,.069-.273,.362-.361,.119-.035,.236-.049,.349-.047,.509,.008,.926,.324,.946,.34,.11,.095,.249,.158,.405,.158,.345,0,.625-.28,.625-.625,0-.197-.097-.365-.239-.48-.037-.031-.773-.648-1.766-.645-.216,0-.445,.03-.68,.101-.671,.202-1.146,.731-1.239,1.38-.087,.61,.178,1.197,.777,1.579,0,0,.678,.303,1.43,.58,.159,.059,.672,.276,.61,.621-.046,.256-.361,.521-.81,.521-.468,0-.919-.187-1.206-.503-.114-.125-.275-.206-.458-.206-.345,0-.625,.28-.625,.625,0,.161,.065,.304,.164,.414,.527,.566,1.309,.92,2.124,.92,1.021,0,1.88-.653,2.04-1.552,.121-.678-.186-1.562-1.408-2.014Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
1
.workbench/POC/icons/created.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg id="Layer_1" height="512" viewBox="0 0 24 24" width="512" xmlns="http://www.w3.org/2000/svg" data-name="Layer 1"><path d="m18 9.064a3.049 3.049 0 0 0 -.9-2.164 3.139 3.139 0 0 0 -4.334 0l-11.866 11.869a3.064 3.064 0 0 0 4.33 4.331l11.87-11.869a3.047 3.047 0 0 0 .9-2.167zm-14.184 12.624a1.087 1.087 0 0 1 -1.5 0 1.062 1.062 0 0 1 0-1.5l7.769-7.77 1.505 1.505zm11.872-11.872-2.688 2.689-1.5-1.505 2.689-2.688a1.063 1.063 0 1 1 1.5 1.5zm-10.825-6.961 1.55-.442.442-1.55a1.191 1.191 0 0 1 2.29 0l.442 1.55 1.55.442a1.191 1.191 0 0 1 0 2.29l-1.55.442-.442 1.55a1.191 1.191 0 0 1 -2.29 0l-.442-1.55-1.55-.442a1.191 1.191 0 0 1 0-2.29zm18.274 14.29-1.55.442-.442 1.55a1.191 1.191 0 0 1 -2.29 0l-.442-1.55-1.55-.442a1.191 1.191 0 0 1 0-2.29l1.55-.442.442-1.55a1.191 1.191 0 0 1 2.29 0l.442 1.55 1.55.442a1.191 1.191 0 0 1 0 2.29zm-5.382-14.645 1.356-.387.389-1.358a1.042 1.042 0 0 1 2 0l.387 1.356 1.356.387a1.042 1.042 0 0 1 0 2l-1.356.387-.387 1.359a1.042 1.042 0 0 1 -2 0l-.387-1.355-1.358-.389a1.042 1.042 0 0 1 0-2z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1 KiB |
2
.workbench/POC/icons/credit-card.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Outline" viewBox="0 0 24 24" width="512" height="512"><circle cx="5.5" cy="15.5" r="1.5"/><path d="M19,3H5A5.006,5.006,0,0,0,0,8v8a5.006,5.006,0,0,0,5,5H19a5.006,5.006,0,0,0,5-5V8A5.006,5.006,0,0,0,19,3ZM5,5H19a3,3,0,0,1,3,3H2A3,3,0,0,1,5,5ZM19,19H5a3,3,0,0,1-3-3V10H22v6A3,3,0,0,1,19,19Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 381 B |
2
.workbench/POC/icons/drag.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
|
||||||
|
<svg fill="#000000" width="800px" height="800px" viewBox="-32 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M358.182 179.361c-19.493-24.768-52.679-31.945-79.872-19.098-15.127-15.687-36.182-22.487-56.595-19.629V67c0-36.944-29.736-67-66.286-67S89.143 30.056 89.143 67v161.129c-19.909-7.41-43.272-5.094-62.083 8.872-29.355 21.795-35.793 63.333-14.55 93.152l109.699 154.001C134.632 501.59 154.741 512 176 512h178.286c30.802 0 57.574-21.5 64.557-51.797l27.429-118.999A67.873 67.873 0 0 0 448 326v-84c0-46.844-46.625-79.273-89.818-62.639zM80.985 279.697l27.126 38.079c8.995 12.626 29.031 6.287 29.031-9.283V67c0-25.12 36.571-25.16 36.571 0v175c0 8.836 7.163 16 16 16h6.857c8.837 0 16-7.164 16-16v-35c0-25.12 36.571-25.16 36.571 0v35c0 8.836 7.163 16 16 16H272c8.837 0 16-7.164 16-16v-21c0-25.12 36.571-25.16 36.571 0v21c0 8.836 7.163 16 16 16h6.857c8.837 0 16-7.164 16-16 0-25.121 36.571-25.16 36.571 0v84c0 1.488-.169 2.977-.502 4.423l-27.43 119.001c-1.978 8.582-9.29 14.576-17.782 14.576H176c-5.769 0-11.263-2.878-14.697-7.697l-109.712-154c-14.406-20.223 14.994-42.818 29.394-22.606zM176.143 400v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.733 0-14-7.163-14-16zm75.428 0v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.732 0-14-7.163-14-16zM327 400v-96c0-8.837 6.268-16 14-16h6c7.732 0 14 7.163 14 16v96c0 8.837-6.268 16-14 16h-6c-7.732 0-14-7.163-14-16z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
2
.workbench/POC/icons/envelope.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Bold" viewBox="0 0 24 24" width="512" height="512"><path d="M18.5,1H5.5A5.506,5.506,0,0,0,0,6.5v11A5.506,5.506,0,0,0,5.5,23h13A5.506,5.506,0,0,0,24,17.5V6.5A5.506,5.506,0,0,0,18.5,1Zm0,3a2.476,2.476,0,0,1,1.643.631l-6.5,6.5a2.373,2.373,0,0,1-3.278,0l-6.5-6.5A2.476,2.476,0,0,1,5.5,4Zm0,16H5.5A2.5,2.5,0,0,1,3,17.5V8.017l5.239,5.239a5.317,5.317,0,0,0,7.521,0L21,8.017V17.5A2.5,2.5,0,0,1,18.5,20Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 487 B |
4
.workbench/POC/icons/exclamation.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24">
|
||||||
|
<path d="m22.389,5.418l-3.808-3.808c-1.039-1.039-2.42-1.611-3.889-1.611h-5.385c-1.469,0-2.85.572-3.889,1.611l-3.808,3.808c-1.039,1.04-1.611,2.421-1.611,3.889v5.385c0,1.468.572,2.85,1.611,3.889l3.808,3.808c1.039,1.039,2.42,1.611,3.889,1.611h5.385c1.469,0,2.85-.572,3.889-1.611l3.808-3.808c1.039-1.04,1.611-2.421,1.611-3.889v-5.385c0-1.468-.572-2.85-1.611-3.889Zm-1.389,9.274c0,.667-.261,1.295-.732,1.768l-3.808,3.808c-.466.465-1.109.732-1.768.732h-5.385c-.658,0-1.302-.267-1.768-.732l-3.808-3.808c-.472-.473-.732-1.101-.732-1.768v-5.385c0-.667.261-1.295.732-1.768l3.808-3.808c.466-.465,1.109-.732,1.768-.732h5.385c.658,0,1.302.267,1.768.732l3.808,3.808c.472.473.732,1.101.732,1.768v5.385Zm-7.5-7.192v5c0,.829-.672,1.5-1.5,1.5s-1.5-.671-1.5-1.5v-5c0-.829.672-1.5,1.5-1.5s1.5.671,1.5,1.5Zm0,9c0,.828-.672,1.5-1.5,1.5s-1.5-.672-1.5-1.5.672-1.5,1.5-1.5,1.5.672,1.5,1.5Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1,010 B |
2
.workbench/POC/icons/eye.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="512" height="512"><g id="_01_align_center" data-name="01 align center"><path d="M23.821,11.181v0C22.943,9.261,19.5,3,12,3S1.057,9.261.179,11.181a1.969,1.969,0,0,0,0,1.64C1.057,14.739,4.5,21,12,21s10.943-6.261,11.821-8.181A1.968,1.968,0,0,0,23.821,11.181ZM12,19c-6.307,0-9.25-5.366-10-6.989C2.75,10.366,5.693,5,12,5c6.292,0,9.236,5.343,10,7C21.236,13.657,18.292,19,12,19Z"/><path d="M12,7a5,5,0,1,0,5,5A5.006,5.006,0,0,0,12,7Zm0,8a3,3,0,1,1,3-3A3,3,0,0,1,12,15Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 580 B |
2
.workbench/POC/icons/gift-card.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M19,6h-1.226c1.413-1.38,1.629-3.195,.545-4.64-.545-.728-1.34-1.198-2.239-1.326-.902-.131-1.795,.102-2.521,.646-.678,.508-1.178,1.155-1.547,1.813-.369-.659-.869-1.305-1.547-1.813C9.739,.135,8.844-.097,7.945,.034c-.899,.128-1.694,.599-2.239,1.326-1.078,1.437-.87,3.24,.547,4.64h-1.253C2.243,6,0,8.243,0,11v8c0,2.757,2.243,5,5,5h14c2.757,0,5-2.243,5-5V11c0-2.757-2.243-5-5-5Zm-4.24-3.72c.245-.184,.537-.28,.837-.28,.403,0,.898,.261,1.123,.56,.641,.854,.043,1.644-.343,2.013-1.561,1.385-3.217,1.427-3.358,1.428h-.013c.019-.091,.025-.186,.017-.283l-.002-.021c.089-.598,.461-2.458,1.739-3.416Zm-7.084,2.316c-.414-.395-1.011-1.182-.37-2.037,.225-.299,.552-.493,.922-.546,.373-.048,.739,.043,1.038,.267,1.279,.959,1.651,2.822,1.74,3.416l-.002,.021c-.008,.097-.002,.192,.017,.283h-.013c-.141,0-1.797-.042-3.332-1.403Zm-2.676,3.403h5.824c-.751,1.951-3.666,1.999-3.826,2-.552,0-.999,.448-.999,1s.448,1,1,1c1.417,0,3.697-.488,5-2.056,1.303,1.569,3.583,2.056,5,2.056,.552,0,1-.447,1-1s-.448-1-1-1c-.142,0-3.078-.026-3.827-2h5.827c1.654,0,3,1.346,3,3v6H2v-6c0-1.654,1.346-3,3-3Zm14,14H5c-1.654,0-3-1.346-3-3H22c0,1.654-1.346,3-3,3Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 1.3 KiB |
4
.workbench/POC/icons/journal-alt.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24">
|
||||||
|
<path d="m15,2.766v-1.766c0-.553-.448-1-1-1s-1,.447-1,1v1h-2v-1c0-.553-.448-1-1-1s-1,.447-1,1v1h-2v-1c0-.553-.448-1-1-1s-1,.447-1,1v1h-2v-1c0-.553-.448-1-1-1s-1,.447-1,1v1.766c-.613.55-1,1.347-1,2.234v14c0,2.757,2.243,5,5,5h6c2.757,0,5-2.243,5-5V5c0-.886-.387-1.684-1-2.234Zm-1,16.234c0,1.654-1.346,3-3,3h-6c-1.654,0-3-1.346-3-3V5c0-.552.449-1,1-1h10c.551,0,1,.448,1,1v14Zm-2-11c0,.553-.448,1-1,1h-6c-.552,0-1-.447-1-1s.448-1,1-1h6c.552,0,1,.447,1,1Zm0,4c0,.553-.448,1-1,1h-6c-.552,0-1-.447-1-1s.448-1,1-1h6c.552,0,1,.447,1,1Zm-3,4c0,.553-.448,1-1,1h-3c-.552,0-1-.447-1-1s.448-1,1-1h3c.552,0,1,.447,1,1ZM21,0c-1.654,0-3,1.346-3,3v16.758c0,1.054.427,2.084,1.172,2.828l1.121,1.121c.195.195.451.293.707.293s.512-.098.707-.293l1.121-1.121c.745-.744,1.172-1.774,1.172-2.828V3c0-1.654-1.346-3-3-3Zm1,19.758c0,.526-.213,1.042-.586,1.414l-.414.414-.414-.414c-.373-.372-.586-.888-.586-1.414V3c0-.552.449-1,1-1s1,.448,1,1v16.758Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1 KiB |
4
.workbench/POC/icons/loan.svg
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24">
|
||||||
|
<path d="m23.018,8.785c-.595-.542-1.356-.821-2.169-.782-.804.037-1.545.386-2.085.981l-3.217,3.534c-.427-.704-1.124-1.224-1.945-1.425.246-.477.398-1.009.398-1.582,0-2.517-1.763-5.472-4.115-6.569.337-.352.666-.743.93-1.163.488-.772-.048-1.78-.962-1.78h-3.708c-.914,0-1.449,1.008-.962,1.78.265.42.593.81.93,1.163-2.352,1.096-4.115,4.052-4.115,6.569,0,.654.193,1.26.508,1.783-1.468.593-2.508,2.027-2.508,3.705v5c0,2.206,1.794,4,4,4h4.965c2.85,0,5.57-1.22,7.467-3.348l6.804-7.637c1.094-1.225.996-3.123-.218-4.23Zm-15.018-4.285c1.821.049,4,2.738,4,5.012,0,.821-.673,1.488-1.5,1.488h-5c-.827,0-1.5-.667-1.5-1.488,0-2.274,2.179-4.963,4-5.012Zm13.742,7.184l-6.805,7.638c-1.517,1.702-3.693,2.678-5.973,2.678h-4.965c-1.103,0-2-.897-2-2v-5c0-1.103.897-2,2-2h8.857c.63,0,1.143.512,1.143,1.142,0,.564-.422,1.051-.98,1.131l-5.161.737c-.547.078-.927.584-.849,1.131.078.546.584.922,1.132.848l5.161-.737c1.175-.168,2.128-.988,2.514-2.058l4.427-4.865c.181-.2.43-.316.699-.329.271-.007.528.082.728.262.407.372.44,1.009.072,1.421Z"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
19
.workbench/POC/icons/mobilepay.svg
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||||
|
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
|
||||||
|
<svg width="800px" height="800px" viewBox="0 0 48 48" xmlns="http://www.w3.org/2000/svg" fill="#000000" stroke="#000000" stroke-width="1.6799999999999997">
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
|
||||||
|
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="3.936">
|
||||||
|
<defs>
|
||||||
|
<style>.a{fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;}</style>
|
||||||
|
</defs>
|
||||||
|
<path class="a" d="M18.924,19.1788l4.3315,10.45a21.1489,21.1489,0,0,1,9.042-2.1117,19.2351,19.2351,0,0,1,8.7714,2.1117v-10.45a10.3349,10.3349,0,0,0-3.5735-1.4078l-2.22-5.5768A20.3917,20.3917,0,0,0,26.45,13.9268C20.1693,16.6882,18.924,19.1788,18.924,19.1788Z"/>
|
||||||
|
<path class="a" d="M32.8978,27.5311,35.6164,33.76a2.3649,2.3649,0,0,1-1.2215,3.1135L21.9571,42.302a2.3651,2.3651,0,0,1-3.1135-1.2215L7.1292,14.24a2.3649,2.3649,0,0,1,1.2215-3.1135L20.7885,5.698A2.3651,2.3651,0,0,1,23.902,6.92l2.98,6.8279"/>
|
||||||
|
</g>
|
||||||
|
<g id="SVGRepo_iconCarrier">
|
||||||
|
<defs>
|
||||||
|
<style>.a{fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;}</style>
|
||||||
|
</defs>
|
||||||
|
<path class="a" d="M18.924,19.1788l4.3315,10.45a21.1489,21.1489,0,0,1,9.042-2.1117,19.2351,19.2351,0,0,1,8.7714,2.1117v-10.45a10.3349,10.3349,0,0,0-3.5735-1.4078l-2.22-5.5768A20.3917,20.3917,0,0,0,26.45,13.9268C20.1693,16.6882,18.924,19.1788,18.924,19.1788Z"/>
|
||||||
|
<path class="a" d="M32.8978,27.5311,35.6164,33.76a2.3649,2.3649,0,0,1-1.2215,3.1135L21.9571,42.302a2.3651,2.3651,0,0,1-3.1135-1.2215L7.1292,14.24a2.3649,2.3649,0,0,1,1.2215-3.1135L20.7885,5.698A2.3651,2.3651,0,0,1,23.902,6.92l2.98,6.8279"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
2
.workbench/POC/icons/note-sticky.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M19,0H5C2.24,0,0,2.24,0,5v14c0,2.76,2.24,5,5,5h11.34c1.34,0,2.59-.52,3.54-1.46l2.66-2.66c.94-.94,1.46-2.2,1.46-3.54V5c0-2.76-2.24-5-5-5ZM5,22c-1.65,0-3-1.35-3-3V5c0-1.65,1.35-3,3-3h14c1.65,0,3,1.35,3,3V15h-4c-1.65,0-3,1.35-3,3v4H5Zm13.46-.88c-.4,.4-.91,.68-1.46,.8v-3.93c0-.55,.45-1,1-1h3.93c-.12,.55-.4,1.06-.8,1.46l-2.66,2.66Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 504 B |
2
.workbench/POC/icons/phone-flip.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M22.17,1.82l-1.05-.91c-1.21-1.21-3.17-1.21-4.38,0-.03,.03-1.88,2.44-1.88,2.44-1.14,1.2-1.14,3.09,0,4.28l1.16,1.46c-1.46,3.31-3.73,5.59-6.93,6.95l-1.46-1.17c-1.19-1.15-3.09-1.15-4.28,0,0,0-2.41,1.85-2.44,1.88-1.21,1.21-1.21,3.17-.05,4.33l1,1.15c1.15,1.15,2.7,1.78,4.38,1.78,7.64,0,17.76-10.13,17.76-17.76,0-1.67-.63-3.23-1.83-4.42ZM6.24,22c-1.14,0-2.19-.42-2.91-1.15l-1-1.15c-.41-.41-.43-1.08-.04-1.51,0,0,2.39-1.84,2.42-1.87,.41-.41,1.13-.41,1.55,0,.03,.03,2.04,1.64,2.04,1.64,.28,.22,.65,.28,.98,.15,4.14-1.58,7.11-4.54,8.82-8.81,.13-.33,.08-.71-.15-1,0,0-1.61-2.02-1.63-2.04-.43-.43-.43-1.12,0-1.55,.03-.03,1.87-2.42,1.87-2.42,.43-.39,1.1-.38,1.56,.08l1.05,.91c.77,.77,1.2,1.82,1.2,2.96,0,6.96-9.77,15.76-15.76,15.76Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 895 B |
22
.workbench/POC/icons/search.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 513.749 513.749" style="enable-background:new 0 0 513.749 513.749;" xml:space="preserve" width="512" height="512">
|
||||||
|
<g>
|
||||||
|
<path d="M504.352,459.061l-99.435-99.477c74.402-99.427,54.115-240.344-45.312-314.746S119.261-9.277,44.859,90.15 S-9.256,330.494,90.171,404.896c79.868,59.766,189.565,59.766,269.434,0l99.477,99.477c12.501,12.501,32.769,12.501,45.269,0 c12.501-12.501,12.501-32.769,0-45.269L504.352,459.061z M225.717,385.696c-88.366,0-160-71.634-160-160s71.634-160,160-160 s160,71.634,160,160C385.623,314.022,314.044,385.602,225.717,385.696z"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 850 B |
2
.workbench/POC/icons/square-plus.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M17,12c0,.553-.448,1-1,1h-3v3c0,.553-.448,1-1,1s-1-.447-1-1v-3h-3c-.552,0-1-.447-1-1s.448-1,1-1h3v-3c0-.553,.448-1,1-1s1,.447,1,1v3h3c.552,0,1,.447,1,1Zm7-7v14c0,2.757-2.243,5-5,5H5c-2.757,0-5-2.243-5-5V5C0,2.243,2.243,0,5,0h14c2.757,0,5,2.243,5,5Zm-2,0c0-1.654-1.346-3-3-3H5c-1.654,0-3,1.346-3,3v14c0,1.654,1.346,3,3,3h14c1.654,0,3-1.346,3-3V5Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 521 B |
2
.workbench/POC/icons/unlock.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Isolation_Mode" data-name="Isolation Mode" viewBox="0 0 24 24" width="512" height="512"><path d="M8,8V7.151A4,4,0,0,1,15.494,5.2l2.618-1.465A7,7,0,0,0,5,7.151V8H2V21a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V8ZM5,21V11H19l0,10Z"/><rect x="10" y="14" width="4" height="3"/></svg>
|
||||||
|
After Width: | Height: | Size: 351 B |
2
.workbench/POC/icons/user.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="512" height="512"><g id="_01_align_center" data-name="01 align center"><path d="M21,24H19V18.957A2.96,2.96,0,0,0,16.043,16H7.957A2.96,2.96,0,0,0,5,18.957V24H3V18.957A4.963,4.963,0,0,1,7.957,14h8.086A4.963,4.963,0,0,1,21,18.957Z"/><path d="M12,12a6,6,0,1,1,6-6A6.006,6.006,0,0,1,12,12ZM12,2a4,4,0,1,0,4,4A4,4,0,0,0,12,2Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 439 B |
2
.workbench/POC/icons/warning.svg
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M23.08,15.33L15,2.57c-.68-.98-1.81-1.57-3-1.57s-2.32,.58-3.03,1.6L.93,15.31c-1.02,1.46-1.21,3.21-.5,4.56,.7,1.35,2.17,2.12,4.01,2.12h15.12c1.85,0,3.31-.77,4.01-2.12,.7-1.35,.51-3.09-.49-4.54ZM11,7c0-.55,.45-1,1-1s1,.45,1,1v6c0,.55-.45,1-1,1s-1-.45-1-1V7Zm1,12c-.83,0-1.5-.67-1.5-1.5s.67-1.5,1.5-1.5,1.5,.67,1.5,1.5-.67,1.5-1.5,1.5Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 507 B |
536
.workbench/POC/month-view-design.html
Normal file
|
|
@ -0,0 +1,536 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Calendar Plantempus - Month View</title>
|
||||||
|
<style>
|
||||||
|
/* Use existing Calendar Plantempus variables and styling */
|
||||||
|
:root {
|
||||||
|
--hour-height: 60px;
|
||||||
|
--minute-height: 1px;
|
||||||
|
--snap-interval: 15;
|
||||||
|
--day-column-min-width: 140px;
|
||||||
|
--week-days: 7;
|
||||||
|
--header-height: 80px;
|
||||||
|
|
||||||
|
--color-primary: #2196f3;
|
||||||
|
--color-secondary: #ff9800;
|
||||||
|
--color-success: #4caf50;
|
||||||
|
--color-warning: #ff5722;
|
||||||
|
--color-error: #f44336;
|
||||||
|
--color-text: #2c3e50;
|
||||||
|
--color-text-secondary: #6c757d;
|
||||||
|
--color-border: #e0e0e0;
|
||||||
|
--color-background: #ffffff;
|
||||||
|
--color-surface: #f8f9fa;
|
||||||
|
--color-hover: #f0f0f0;
|
||||||
|
|
||||||
|
--transition-fast: 0.15s ease;
|
||||||
|
--border-radius: 4px;
|
||||||
|
--box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month grid container - matches existing swp-calendar-container */
|
||||||
|
.month-container {
|
||||||
|
background: var(--color-background);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month grid layout with week numbers */
|
||||||
|
.month-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 40px repeat(7, 1fr); /* Small column for week numbers + 7 days */
|
||||||
|
grid-template-rows: 40px repeat(6, 1fr);
|
||||||
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Week number header */
|
||||||
|
.week-header {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Day headers - only day names, right aligned, smaller height */
|
||||||
|
.month-day-header {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-header:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Week number cells */
|
||||||
|
.week-number {
|
||||||
|
grid-column: 1;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month day cells - similar to existing day columns */
|
||||||
|
.month-day-cell {
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 8px;
|
||||||
|
background: var(--color-background);
|
||||||
|
transition: background-color var(--transition-fast);
|
||||||
|
position: relative;
|
||||||
|
min-height: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell:hover {
|
||||||
|
background: var(--color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.other-month {
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.today {
|
||||||
|
background: #f0f8ff;
|
||||||
|
border-left: 3px solid var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.weekend {
|
||||||
|
background: #fafbfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-number {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.today .month-day-number {
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month events styling - compact version of existing events */
|
||||||
|
.month-events {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
max-height: 70px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event {
|
||||||
|
background: #e3f2fd;
|
||||||
|
color: var(--color-primary);
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
border-left: 2px solid var(--color-primary);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event categories - using existing color scheme */
|
||||||
|
.month-event.category-meeting {
|
||||||
|
background: #e8f5e8;
|
||||||
|
color: var(--color-success);
|
||||||
|
border-left-color: var(--color-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-deadline {
|
||||||
|
background: #ffebee;
|
||||||
|
color: var(--color-error);
|
||||||
|
border-left-color: var(--color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-work {
|
||||||
|
background: #fff8e1;
|
||||||
|
color: var(--color-secondary);
|
||||||
|
border-left-color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-personal {
|
||||||
|
background: #f3e5f5;
|
||||||
|
color: #7b1fa2;
|
||||||
|
border-left-color: #9c27b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event-more {
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
padding: 1px 4px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 9px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px dashed var(--color-border);
|
||||||
|
margin-top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event-more:hover {
|
||||||
|
background: var(--color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.month-container {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-grid {
|
||||||
|
grid-template-columns: 30px repeat(7, 1fr);
|
||||||
|
min-height: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell {
|
||||||
|
min-height: 60px;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-header {
|
||||||
|
padding: 8px 4px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event {
|
||||||
|
font-size: 9px;
|
||||||
|
padding: 1px 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-events {
|
||||||
|
max-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-number {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="month-container">
|
||||||
|
<div class="month-grid">
|
||||||
|
<!-- Week number header -->
|
||||||
|
<div class="week-header">Uge</div>
|
||||||
|
|
||||||
|
<!-- Day headers - only day names, right aligned -->
|
||||||
|
<div class="month-day-header">Man</div>
|
||||||
|
<div class="month-day-header">Tir</div>
|
||||||
|
<div class="month-day-header">Ons</div>
|
||||||
|
<div class="month-day-header">Tor</div>
|
||||||
|
<div class="month-day-header">Fre</div>
|
||||||
|
<div class="month-day-header">Lør</div>
|
||||||
|
<div class="month-day-header">Søn</div>
|
||||||
|
|
||||||
|
<!-- Week 1 -->
|
||||||
|
<div class="week-number">1</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">30</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">31</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal">Nytår</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">1</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal">Nytårsdag</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">2</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Tilbage på arbejde</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">3</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Team møde</div>
|
||||||
|
<div class="month-event category-work">Review</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">5</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal">Familie</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 2 -->
|
||||||
|
<div class="week-number">2</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">6</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Stand-up</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">7</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline">Rapport</div>
|
||||||
|
<div class="month-event category-meeting">1:1</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">8</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Code review</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">9</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Planning</div>
|
||||||
|
<div class="month-event category-work">Design</div>
|
||||||
|
<div class="month-event-more">+1</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">10</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Sprint review</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">11</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">12</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal">Brunch</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 3 -->
|
||||||
|
<div class="week-number">3</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">13</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">All hands</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">14</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Deploy</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">15</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline">Presentation</div>
|
||||||
|
<div class="month-event category-meeting">Retro</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">16</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Bug triage</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">17</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Planning</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">18</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal">Koncert</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">19</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 4 - Today -->
|
||||||
|
<div class="week-number">4</div>
|
||||||
|
<div class="month-day-cell today">
|
||||||
|
<div class="month-day-number">20</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Status møde</div>
|
||||||
|
<div class="month-event category-work">Refactoring</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">21</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline">Beta release</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">22</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Architecture</div>
|
||||||
|
<div class="month-event category-work">Performance</div>
|
||||||
|
<div class="month-event category-deadline">Docs</div>
|
||||||
|
<div class="month-event-more">+2</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">23</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Cleanup</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">24</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Weekly sync</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">25</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">26</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal">Fødselsdag</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 5 -->
|
||||||
|
<div class="week-number">5</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">27</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Q1 planning</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">28</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work">Tech talks</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">29</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline">Monthly report</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">30</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting">Team building</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">31</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline">End of month</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">1</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">2</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 6 -->
|
||||||
|
<div class="week-number">6</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">3</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">4</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">5</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">6</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">7</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">8</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">9</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Add click handlers for events and days
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
if (e.target.classList.contains('month-event')) {
|
||||||
|
console.log('Event clicked:', e.target.textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.target.classList.contains('month-event-more')) {
|
||||||
|
console.log('Show more events');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.target.classList.contains('month-day-cell') || e.target.closest('.month-day-cell')) {
|
||||||
|
const cell = e.target.closest('.month-day-cell');
|
||||||
|
const dayNumber = cell.querySelector('.month-day-number').textContent;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
848
.workbench/POC/month-view-expanded.html
Normal file
|
|
@ -0,0 +1,848 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Calendar Plantempus - Month View Expanded</title>
|
||||||
|
<style>
|
||||||
|
/* Use existing Calendar Plantempus variables and styling */
|
||||||
|
:root {
|
||||||
|
/* Event duration sizing */
|
||||||
|
--pixels-per-hour: 30px;
|
||||||
|
--min-event-height: 15px; /* 30 min minimum */
|
||||||
|
|
||||||
|
--color-primary: #2196f3;
|
||||||
|
--color-secondary: #ff9800;
|
||||||
|
--color-success: #4caf50;
|
||||||
|
--color-warning: #ff5722;
|
||||||
|
--color-error: #f44336;
|
||||||
|
--color-text: #2c3e50;
|
||||||
|
--color-text-secondary: #6c757d;
|
||||||
|
--color-border: #e0e0e0;
|
||||||
|
--color-background: #ffffff;
|
||||||
|
--color-surface: #f8f9fa;
|
||||||
|
--color-hover: #f0f0f0;
|
||||||
|
|
||||||
|
--transition-fast: 0.15s ease;
|
||||||
|
--border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
background-color: var(--color-surface);
|
||||||
|
color: var(--color-text);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month grid container */
|
||||||
|
.month-container {
|
||||||
|
background: var(--color-background);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month grid layout - rows auto-size based on content */
|
||||||
|
.month-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 40px repeat(7, 1fr);
|
||||||
|
grid-template-rows: 40px repeat(6, auto);
|
||||||
|
min-height: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Week number header */
|
||||||
|
.week-header {
|
||||||
|
grid-column: 1;
|
||||||
|
grid-row: 1;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Day headers */
|
||||||
|
.month-day-header {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-header:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Week number cells */
|
||||||
|
.week-number {
|
||||||
|
grid-column: 1;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
display: flex;
|
||||||
|
align-items: start;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 8px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Month day cells */
|
||||||
|
.month-day-cell {
|
||||||
|
border-right: 1px solid var(--color-border);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 8px;
|
||||||
|
background: var(--color-background);
|
||||||
|
transition: background-color var(--transition-fast);
|
||||||
|
min-height: 80px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell:hover {
|
||||||
|
background: var(--color-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell:last-child {
|
||||||
|
border-right: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.other-month {
|
||||||
|
background: var(--color-surface);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.today {
|
||||||
|
background: #f0f8ff;
|
||||||
|
border-left: 3px solid var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.weekend {
|
||||||
|
background: #fafbfc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-number {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell.today .month-day-number {
|
||||||
|
color: var(--color-primary);
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Events container */
|
||||||
|
.month-events {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Individual events with duration-based minimum height */
|
||||||
|
.month-event {
|
||||||
|
background: #e3f2fd;
|
||||||
|
color: var(--color-text);
|
||||||
|
padding: 6px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all var(--transition-fast);
|
||||||
|
border-left: 3px solid var(--color-primary);
|
||||||
|
/* Min-height set inline based on duration */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event time range */
|
||||||
|
.event-time-range {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event title */
|
||||||
|
.event-title {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event subtitle/description */
|
||||||
|
.event-subtitle {
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event:hover {
|
||||||
|
transform: translateX(2px);
|
||||||
|
background: #d1e7fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event categories */
|
||||||
|
.month-event.category-meeting {
|
||||||
|
background: #e8f5e8;
|
||||||
|
border-left-color: var(--color-success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-meeting:hover {
|
||||||
|
background: #d4edd4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-deadline {
|
||||||
|
background: #ffebee;
|
||||||
|
border-left-color: var(--color-error);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-deadline:hover {
|
||||||
|
background: #ffd6dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-work {
|
||||||
|
background: #fff8e1;
|
||||||
|
border-left-color: var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-work:hover {
|
||||||
|
background: #ffedcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-personal {
|
||||||
|
background: #f3e5f5;
|
||||||
|
border-left-color: #9c27b0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.category-personal:hover {
|
||||||
|
background: #e8d1ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* All-day events */
|
||||||
|
.month-event.all-day {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.all-day .event-time-range,
|
||||||
|
.month-event.all-day .event-title,
|
||||||
|
.month-event.all-day .event-subtitle {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.all-day:hover {
|
||||||
|
background: linear-gradient(135deg, #5a72e8 0%, #6b42a0 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Short events (30 min) - compact layout */
|
||||||
|
.month-event.short-event {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.short-event .event-time-range {
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.short-event .event-title {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event.short-event .event-subtitle {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.month-container {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-grid {
|
||||||
|
grid-template-columns: 30px repeat(7, 1fr);
|
||||||
|
min-height: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-cell {
|
||||||
|
padding: 4px;
|
||||||
|
min-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-day-header {
|
||||||
|
padding: 8px 4px;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.month-event {
|
||||||
|
padding: 4px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-title {
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.event-time-range,
|
||||||
|
.event-subtitle {
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-number {
|
||||||
|
font-size: 0.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--pixels-per-hour: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="month-container">
|
||||||
|
<div class="month-grid">
|
||||||
|
<!-- Week number header -->
|
||||||
|
<div class="week-header">Uge</div>
|
||||||
|
|
||||||
|
<!-- Day headers -->
|
||||||
|
<div class="month-day-header">Man</div>
|
||||||
|
<div class="month-day-header">Tir</div>
|
||||||
|
<div class="month-day-header">Ons</div>
|
||||||
|
<div class="month-day-header">Tor</div>
|
||||||
|
<div class="month-day-header">Fre</div>
|
||||||
|
<div class="month-day-header">Lør</div>
|
||||||
|
<div class="month-day-header">Søn</div>
|
||||||
|
|
||||||
|
<!-- Week 1 -->
|
||||||
|
<div class="week-number">1</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">30</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">31</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">20:00 - 22:00</div>
|
||||||
|
<div class="event-title">Nytårsaften</div>
|
||||||
|
<div class="event-subtitle">Fest med familie og venner</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">1</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">Nytårsdag</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">2</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">09:00 - 10:00</div>
|
||||||
|
<div class="event-title">Tilbage på arbejde</div>
|
||||||
|
<div class="event-subtitle">Opstart efter ferien</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">10:00 - 10:30</div>
|
||||||
|
<div class="event-title">Kick-off møde</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">3</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">09:00 - 10:30</div>
|
||||||
|
<div class="event-title">Team møde</div>
|
||||||
|
<div class="event-subtitle">Q1 planning og mål</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">11:00 - 13:00</div>
|
||||||
|
<div class="event-title">Projekt review</div>
|
||||||
|
<div class="event-subtitle">Gennemgang af December projekter og status på Q1 initiativer</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-deadline short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">15:00 - 15:30</div>
|
||||||
|
<div class="event-title">Sprint deadline</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">4</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">5</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal" style="min-height: 75px;">
|
||||||
|
<div class="event-time-range">18:00 - 20:30</div>
|
||||||
|
<div class="event-title">Familie middag</div>
|
||||||
|
<div class="event-subtitle">Hos mormor og morfar</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 2 -->
|
||||||
|
<div class="week-number">2</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">6</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting short-event" style="min-height: 7.5px;">
|
||||||
|
<div class="event-time-range">09:15 - 09:30</div>
|
||||||
|
<div class="event-title">Stand-up</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">10:00 - 11:30</div>
|
||||||
|
<div class="event-title">Code review</div>
|
||||||
|
<div class="event-subtitle">Frontend refactoring PR</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">7</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">12:00 - 13:00</div>
|
||||||
|
<div class="event-title">Rapport deadline</div>
|
||||||
|
<div class="event-subtitle">Månedlig status rapport</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">14:00 - 15:00</div>
|
||||||
|
<div class="event-title">1:1 med chef</div>
|
||||||
|
<div class="event-subtitle">Karriere udvikling</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">15:30 - 16:00</div>
|
||||||
|
<div class="event-title">Design review</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">8</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">10:00 - 11:00</div>
|
||||||
|
<div class="event-title">Feature demo</div>
|
||||||
|
<div class="event-subtitle">Ny dashboard funktionalitet</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">9</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">09:00 - 11:00</div>
|
||||||
|
<div class="event-title">Planning møde</div>
|
||||||
|
<div class="event-subtitle">Sprint 23 planning og estimering</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">11:00 - 12:30</div>
|
||||||
|
<div class="event-title">Design session</div>
|
||||||
|
<div class="event-subtitle">UX workshop for ny feature</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-deadline short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">14:00 - 14:30</div>
|
||||||
|
<div class="event-title">Release notes</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">15:00 - 16:00</div>
|
||||||
|
<div class="event-title">Tech sync</div>
|
||||||
|
<div class="event-subtitle">Arkitektur diskussion</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-personal short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">17:00 - 17:30</div>
|
||||||
|
<div class="event-title">Tandlæge</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">10</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">13:00 - 15:00</div>
|
||||||
|
<div class="event-title">Sprint review</div>
|
||||||
|
<div class="event-subtitle">Demo af Sprint 22 leverancer til stakeholders</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">15:00 - 16:00</div>
|
||||||
|
<div class="event-title">Retrospective</div>
|
||||||
|
<div class="event-subtitle">Sprint 22 læringer</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">11</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">12</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">11:00 - 13:00</div>
|
||||||
|
<div class="event-title">Brunch</div>
|
||||||
|
<div class="event-subtitle">Med gamle venner fra uni</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 3 -->
|
||||||
|
<div class="week-number">3</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">13</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">All hands møde</div>
|
||||||
|
<div class="event-subtitle">Quarterly business update</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">14:00 - 16:00</div>
|
||||||
|
<div class="event-title">Architecture planning</div>
|
||||||
|
<div class="event-subtitle">Microservices migration strategi</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">14</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work" style="min-height: 90px;">
|
||||||
|
<div class="event-time-range">10:00 - 13:00</div>
|
||||||
|
<div class="event-title">Feature deployment</div>
|
||||||
|
<div class="event-subtitle">Production release og monitoring af ny payment feature</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">15:00 - 16:30</div>
|
||||||
|
<div class="event-title">Client call</div>
|
||||||
|
<div class="event-subtitle">Requirements gathering</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">15</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">10:00 - 12:00</div>
|
||||||
|
<div class="event-title">Client presentation</div>
|
||||||
|
<div class="event-subtitle">Q4 results og Q1 roadmap præsentation</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">14:00 - 15:00</div>
|
||||||
|
<div class="event-title">Team retrospective</div>
|
||||||
|
<div class="event-subtitle">Monthly team health check</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">16:00 - 17:00</div>
|
||||||
|
<div class="event-title">Bug triage</div>
|
||||||
|
<div class="event-subtitle">Priority 1 issues</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">16</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">11:00 - 12:30</div>
|
||||||
|
<div class="event-title">Performance review</div>
|
||||||
|
<div class="event-subtitle">Database optimization results</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">17</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting" style="min-height: 90px;">
|
||||||
|
<div class="event-time-range">09:00 - 12:00</div>
|
||||||
|
<div class="event-title">Sprint planning</div>
|
||||||
|
<div class="event-subtitle">Sprint 24 - omfattende planning session med hele teamet</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">13:00 - 15:00</div>
|
||||||
|
<div class="event-title">Code cleanup</div>
|
||||||
|
<div class="event-subtitle">Technical debt reduction</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">18</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal" style="min-height: 90px;">
|
||||||
|
<div class="event-time-range">19:00 - 22:00</div>
|
||||||
|
<div class="event-title">Koncert</div>
|
||||||
|
<div class="event-subtitle">Royal Arena - med forband og afterparty</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">19</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 4 - Today -->
|
||||||
|
<div class="week-number">4</div>
|
||||||
|
<div class="month-day-cell today">
|
||||||
|
<div class="month-day-number">20</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">09:00 - 09:30</div>
|
||||||
|
<div class="event-title">Status møde</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">10:30 - 12:00</div>
|
||||||
|
<div class="event-title">Refactoring session</div>
|
||||||
|
<div class="event-subtitle">Legacy code modernization</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-deadline" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">12:00 - 13:00</div>
|
||||||
|
<div class="event-title">Documentation due</div>
|
||||||
|
<div class="event-subtitle">API documentation update</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">14:00 - 15:30</div>
|
||||||
|
<div class="event-title">Architecture review</div>
|
||||||
|
<div class="event-subtitle">System design review med senior architects</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">15:30 - 16:30</div>
|
||||||
|
<div class="event-title">Performance testing</div>
|
||||||
|
<div class="event-subtitle">Load testing results</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-personal short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">17:00 - 17:30</div>
|
||||||
|
<div class="event-title">Gym</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">21</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline" style="min-height: 120px;">
|
||||||
|
<div class="event-time-range">14:00 - 18:00</div>
|
||||||
|
<div class="event-title">Beta release</div>
|
||||||
|
<div class="event-subtitle">Full release process including deployment, smoke testing, monitoring setup og stakeholder notification</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">22</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">09:00 - 10:30</div>
|
||||||
|
<div class="event-title">Architecture review</div>
|
||||||
|
<div class="event-subtitle">Final design approval</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">11:00 - 13:00</div>
|
||||||
|
<div class="event-title">Performance testing</div>
|
||||||
|
<div class="event-subtitle">Full regression test suite execution</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-deadline" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">14:00 - 15:00</div>
|
||||||
|
<div class="event-title">Documentation deadline</div>
|
||||||
|
<div class="event-subtitle">User guide completion</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-meeting" style="min-height: 45px;">
|
||||||
|
<div class="event-time-range">15:00 - 16:30</div>
|
||||||
|
<div class="event-title">Stakeholder meeting</div>
|
||||||
|
<div class="event-subtitle">Project status update</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work short-event" style="min-height: 15px;">
|
||||||
|
<div class="event-time-range">16:30 - 17:00</div>
|
||||||
|
<div class="event-title">Deploy to staging</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">23</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-work all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">Code cleanup day</div>
|
||||||
|
<div class="event-subtitle">Team-wide technical debt reduction</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">24</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">14:00 - 15:00</div>
|
||||||
|
<div class="event-title">Weekly sync</div>
|
||||||
|
<div class="event-subtitle">Cross-team alignment</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">25</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell weekend">
|
||||||
|
<div class="month-day-number">26</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-personal all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">Fødselsdag</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-personal" style="min-height: 120px;">
|
||||||
|
<div class="event-time-range">18:00 - 22:00</div>
|
||||||
|
<div class="event-title">Fødselsdagsfest</div>
|
||||||
|
<div class="event-subtitle">Stor fest med familie og venner, middag og underholdning</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 5 -->
|
||||||
|
<div class="week-number">5</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">27</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">Q1 planning - Day 1</div>
|
||||||
|
<div class="event-subtitle">Quarterly planning workshop</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">28</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">Q1 planning - Day 2</div>
|
||||||
|
<div class="event-subtitle">OKR setting og roadmap</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">14:00 - 16:00</div>
|
||||||
|
<div class="event-title">Tech talks</div>
|
||||||
|
<div class="event-subtitle">Knowledge sharing session om nye teknologier</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">29</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">Q1 planning - Day 3</div>
|
||||||
|
<div class="event-subtitle">Final alignment og præsentation</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-deadline" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">16:00 - 18:00</div>
|
||||||
|
<div class="event-title">Monthly report</div>
|
||||||
|
<div class="event-subtitle">Januar status rapport og metrics sammensætning</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">30</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-meeting" style="min-height: 90px;">
|
||||||
|
<div class="event-time-range">15:00 - 18:00</div>
|
||||||
|
<div class="event-title">Team building</div>
|
||||||
|
<div class="event-subtitle">Off-site team building aktivitet med middag</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell">
|
||||||
|
<div class="month-day-number">31</div>
|
||||||
|
<div class="month-events">
|
||||||
|
<div class="month-event category-deadline all-day" style="min-height: 30px;">
|
||||||
|
<div class="event-time-range">Hele dagen</div>
|
||||||
|
<div class="event-title">End of month</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-event category-work" style="min-height: 60px;">
|
||||||
|
<div class="event-time-range">14:00 - 16:00</div>
|
||||||
|
<div class="event-title">Month wrap-up</div>
|
||||||
|
<div class="event-subtitle">Januar review og Februar forberedelse</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">1</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">2</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Week 6 -->
|
||||||
|
<div class="week-number">6</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">3</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">4</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">5</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">6</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">7</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">8</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
<div class="month-day-cell other-month">
|
||||||
|
<div class="month-day-number">9</div>
|
||||||
|
<div class="month-events"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Click handlers
|
||||||
|
document.addEventListener('click', function(e) {
|
||||||
|
if (e.target.closest('.month-event')) {
|
||||||
|
const event = e.target.closest('.month-event');
|
||||||
|
console.log('Event clicked:', event.querySelector('.event-title').textContent);
|
||||||
|
|
||||||
|
// Remove previous selection
|
||||||
|
document.querySelectorAll('.month-event').forEach(el => {
|
||||||
|
el.style.outline = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
// Highlight selected event
|
||||||
|
event.style.outline = '2px solid var(--color-primary)';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.target.closest('.month-day-cell')) {
|
||||||
|
const cell = e.target.closest('.month-day-cell');
|
||||||
|
const dayNumber = cell.querySelector('.month-day-number').textContent;
|
||||||
|
console.log('Day clicked:', dayNumber);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1896
.workbench/POC/plantempus-sales.html
Normal file
1009
.workbench/POC/poc-ai-booking-optimizer.html
Normal file
1783
.workbench/POC/poc-arbejdstidsplan.html
Normal file
2993
.workbench/POC/poc-booking-v2.html
Normal file
2499
.workbench/POC/poc-checkout.html
Normal file
3396
.workbench/POC/poc-customer-detail.html
Normal file
1642
.workbench/POC/poc-customer-list.html
Normal file
732
.workbench/POC/poc-dashboard.html
Normal file
|
|
@ -0,0 +1,732 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Dashboard - Salon OS</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<script src="https://unpkg.com/@phosphor-icons/web@2.1.1"></script>
|
||||||
|
<link rel="stylesheet" href="css/dashboard.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Page Header -->
|
||||||
|
<swp-page-header>
|
||||||
|
<swp-page-title>Dashboard</swp-page-title>
|
||||||
|
<swp-page-actions>
|
||||||
|
<swp-date-display>
|
||||||
|
<i class="ph ph-calendar-blank"></i>
|
||||||
|
<span>Mandag, 30. december 2024</span>
|
||||||
|
</swp-date-display>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<i class="ph ph-plus"></i>
|
||||||
|
Ny booking
|
||||||
|
</swp-btn>
|
||||||
|
</swp-page-actions>
|
||||||
|
</swp-page-header>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
<!-- Stats Bar -->
|
||||||
|
<swp-stats-bar>
|
||||||
|
<swp-stat-card class="highlight">
|
||||||
|
<swp-stat-value>12</swp-stat-value>
|
||||||
|
<swp-stat-label>Bookinger i dag</swp-stat-label>
|
||||||
|
<swp-stat-trend class="up">
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
4 gennemført, 2 i gang
|
||||||
|
</swp-stat-trend>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="success">
|
||||||
|
<swp-stat-value>8.450 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Forventet omsætning</swp-stat-label>
|
||||||
|
<swp-stat-trend class="up">
|
||||||
|
<i class="ph ph-trend-up"></i>
|
||||||
|
+12% vs. gennemsnit
|
||||||
|
</swp-stat-trend>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>78%</swp-stat-value>
|
||||||
|
<swp-stat-label>Belægningsgrad</swp-stat-label>
|
||||||
|
<swp-stat-trend class="up">
|
||||||
|
<i class="ph ph-trend-up"></i>
|
||||||
|
God kapacitet
|
||||||
|
</swp-stat-trend>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="warning">
|
||||||
|
<swp-stat-value>3</swp-stat-value>
|
||||||
|
<swp-stat-label>Kræver opmærksomhed</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
</swp-stats-bar>
|
||||||
|
|
||||||
|
<swp-dashboard-grid>
|
||||||
|
<!-- Main Column -->
|
||||||
|
<swp-main-column>
|
||||||
|
<!-- AI Insight -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-ai-insight>
|
||||||
|
<swp-ai-header>
|
||||||
|
<i class="ph ph-sparkle"></i>
|
||||||
|
<span>AI Analyse</span>
|
||||||
|
</swp-ai-header>
|
||||||
|
<swp-ai-text>
|
||||||
|
<strong>Godt i gang!</strong> 4 af 12 bookinger er gennemført. 2 er i gang nu, og 6 venter.
|
||||||
|
Forventet omsætning: <strong>8.450 kr</strong> – allerede realiseret <strong>2.150 kr</strong>.
|
||||||
|
Tip: Ida Rasmussen (11:30) har ikke bekræftet – overvej at sende en påmindelse.
|
||||||
|
</swp-ai-text>
|
||||||
|
</swp-ai-insight>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Today's Bookings -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>
|
||||||
|
<i class="ph ph-calendar-check"></i>
|
||||||
|
Dagens bookinger
|
||||||
|
</swp-card-title>
|
||||||
|
<swp-card-action>Se alle</swp-card-action>
|
||||||
|
</swp-card-header>
|
||||||
|
|
||||||
|
<swp-current-time>
|
||||||
|
<i class="ph ph-clock"></i>
|
||||||
|
<span>Nu: <swp-time>10:45</swp-time></span>
|
||||||
|
</swp-current-time>
|
||||||
|
|
||||||
|
<swp-booking-list>
|
||||||
|
<!-- Gennemførte bookinger -->
|
||||||
|
<swp-booking-item class="completed">
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>08:00</swp-time-start>
|
||||||
|
<swp-time-end>08:30</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Herreklip</swp-booking-service>
|
||||||
|
<swp-booking-customer>Thomas Berg</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>MH</swp-avatar-small>
|
||||||
|
<span>Maria</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="completed">Gennemført</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item class="completed">
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>08:30</swp-time-start>
|
||||||
|
<swp-time-end>09:00</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Dameklip</swp-booking-service>
|
||||||
|
<swp-booking-customer>Katrine Holm</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>AS</swp-avatar-small>
|
||||||
|
<span>Anna</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="completed">Gennemført</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item class="completed">
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>09:00</swp-time-start>
|
||||||
|
<swp-time-end>09:30</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Skægtrimning</swp-booking-service>
|
||||||
|
<swp-booking-customer>Mikkel Skov</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>PK</swp-avatar-small>
|
||||||
|
<span>Peter</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="completed">Gennemført</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item class="completed">
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>09:00</swp-time-start>
|
||||||
|
<swp-time-end>10:30</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Dameklip + Farve</swp-booking-service>
|
||||||
|
<swp-booking-customer>Sofie Nielsen</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>AS</swp-avatar-small>
|
||||||
|
<span>Anna</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="completed">Gennemført</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<!-- Igangværende -->
|
||||||
|
<swp-booking-item style="background: color-mix(in srgb, var(--color-teal) 8%, var(--color-background-alt));">
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>10:30</swp-time-start>
|
||||||
|
<swp-time-end>11:00</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="blue"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Herreklip</swp-booking-service>
|
||||||
|
<swp-booking-customer>Jonas Petersen</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>MH</swp-avatar-small>
|
||||||
|
<span>Maria</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="inprogress">I gang</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item style="background: color-mix(in srgb, var(--color-teal) 8%, var(--color-background-alt));">
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>10:00</swp-time-start>
|
||||||
|
<swp-time-end>11:00</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="purple"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Føn + Styling</swp-booking-service>
|
||||||
|
<swp-booking-customer>Rikke Dam</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>LJ</swp-avatar-small>
|
||||||
|
<span>Louise</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="inprogress">I gang</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<!-- Kommende -->
|
||||||
|
<swp-booking-item>
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>11:00</swp-time-start>
|
||||||
|
<swp-time-end>12:00</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="teal"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Balayage</swp-booking-service>
|
||||||
|
<swp-booking-customer>Emma Christensen</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>AS</swp-avatar-small>
|
||||||
|
<span>Anna</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="confirmed">Bekræftet</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item>
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>11:30</swp-time-start>
|
||||||
|
<swp-time-end>12:00</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="amber"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Dameklip</swp-booking-service>
|
||||||
|
<swp-booking-customer>Ida Rasmussen</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>MH</swp-avatar-small>
|
||||||
|
<span>Maria</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="pending">Afventer</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item>
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>13:00</swp-time-start>
|
||||||
|
<swp-time-end>14:00</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="green"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Farve + Føn</swp-booking-service>
|
||||||
|
<swp-booking-customer>Louise Andersen</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>AS</swp-avatar-small>
|
||||||
|
<span>Anna</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="confirmed">Bekræftet</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item>
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>14:00</swp-time-start>
|
||||||
|
<swp-time-end>14:30</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="blue"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Herreklip</swp-booking-service>
|
||||||
|
<swp-booking-customer>Anders Møller</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>PK</swp-avatar-small>
|
||||||
|
<span>Peter</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="confirmed">Bekræftet</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
|
||||||
|
<swp-booking-item>
|
||||||
|
<swp-booking-time>
|
||||||
|
<swp-time-start>15:30</swp-time-start>
|
||||||
|
<swp-time-end>16:30</swp-time-end>
|
||||||
|
</swp-booking-time>
|
||||||
|
<swp-booking-indicator class="purple"></swp-booking-indicator>
|
||||||
|
<swp-booking-details>
|
||||||
|
<swp-booking-service>Extensions</swp-booking-service>
|
||||||
|
<swp-booking-customer>Julie Lund</swp-booking-customer>
|
||||||
|
</swp-booking-details>
|
||||||
|
<swp-booking-employee>
|
||||||
|
<swp-avatar-small>LJ</swp-avatar-small>
|
||||||
|
<span>Louise</span>
|
||||||
|
</swp-booking-employee>
|
||||||
|
<swp-booking-status class="confirmed">Bekræftet</swp-booking-status>
|
||||||
|
</swp-booking-item>
|
||||||
|
</swp-booking-list>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Attention Items -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>
|
||||||
|
<i class="ph ph-warning-circle"></i>
|
||||||
|
Opmærksomheder
|
||||||
|
</swp-card-title>
|
||||||
|
</swp-card-header>
|
||||||
|
|
||||||
|
<swp-attention-list>
|
||||||
|
<swp-attention-item class="urgent">
|
||||||
|
<swp-attention-icon>
|
||||||
|
<i class="ph ph-x-circle"></i>
|
||||||
|
</swp-attention-icon>
|
||||||
|
<swp-attention-content>
|
||||||
|
<swp-attention-title>Aflyst booking</swp-attention-title>
|
||||||
|
<swp-attention-desc>Mette Hansen aflyste kl. 15:00 – tid nu ledig</swp-attention-desc>
|
||||||
|
</swp-attention-content>
|
||||||
|
<swp-attention-action>Fyld tid</swp-attention-action>
|
||||||
|
</swp-attention-item>
|
||||||
|
|
||||||
|
<swp-attention-item class="warning">
|
||||||
|
<swp-attention-icon>
|
||||||
|
<i class="ph ph-clock"></i>
|
||||||
|
</swp-attention-icon>
|
||||||
|
<swp-attention-content>
|
||||||
|
<swp-attention-title>Ubekræftet booking</swp-attention-title>
|
||||||
|
<swp-attention-desc>Ida Rasmussen har ikke bekræftet kl. 11:30</swp-attention-desc>
|
||||||
|
</swp-attention-content>
|
||||||
|
<swp-attention-action>Send påmindelse</swp-attention-action>
|
||||||
|
</swp-attention-item>
|
||||||
|
|
||||||
|
<swp-attention-item class="info">
|
||||||
|
<swp-attention-icon>
|
||||||
|
<i class="ph ph-gift"></i>
|
||||||
|
</swp-attention-icon>
|
||||||
|
<swp-attention-content>
|
||||||
|
<swp-attention-title>Gavekort udløber snart</swp-attention-title>
|
||||||
|
<swp-attention-desc>GC-D2R4-6TY9 udløber om 3 uger (200 DKK)</swp-attention-desc>
|
||||||
|
</swp-attention-content>
|
||||||
|
<swp-attention-action>Se gavekort</swp-attention-action>
|
||||||
|
</swp-attention-item>
|
||||||
|
</swp-attention-list>
|
||||||
|
</swp-card>
|
||||||
|
</swp-main-column>
|
||||||
|
|
||||||
|
<!-- Side Column -->
|
||||||
|
<swp-side-column>
|
||||||
|
<!-- Notifications -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>
|
||||||
|
<i class="ph ph-bell"></i>
|
||||||
|
Notifikationer
|
||||||
|
</swp-card-title>
|
||||||
|
<swp-card-action>Marker alle som læst</swp-card-action>
|
||||||
|
</swp-card-header>
|
||||||
|
|
||||||
|
<swp-notification-list>
|
||||||
|
<swp-notification-item class="unread">
|
||||||
|
<swp-notification-icon>
|
||||||
|
<i class="ph ph-calendar-plus"></i>
|
||||||
|
</swp-notification-icon>
|
||||||
|
<swp-notification-content>
|
||||||
|
<swp-notification-text>
|
||||||
|
<strong>Ny booking</strong> fra Emma Christensen til Balayage
|
||||||
|
</swp-notification-text>
|
||||||
|
<swp-notification-time>For 15 min. siden</swp-notification-time>
|
||||||
|
</swp-notification-content>
|
||||||
|
</swp-notification-item>
|
||||||
|
|
||||||
|
<swp-notification-item class="unread">
|
||||||
|
<swp-notification-icon>
|
||||||
|
<i class="ph ph-star"></i>
|
||||||
|
</swp-notification-icon>
|
||||||
|
<swp-notification-content>
|
||||||
|
<swp-notification-text>
|
||||||
|
<strong>Ny anmeldelse</strong> – 5 stjerner fra Sofie Nielsen
|
||||||
|
</swp-notification-text>
|
||||||
|
<swp-notification-time>For 1 time siden</swp-notification-time>
|
||||||
|
</swp-notification-content>
|
||||||
|
</swp-notification-item>
|
||||||
|
|
||||||
|
<swp-notification-item>
|
||||||
|
<swp-notification-icon>
|
||||||
|
<i class="ph ph-x"></i>
|
||||||
|
</swp-notification-icon>
|
||||||
|
<swp-notification-content>
|
||||||
|
<swp-notification-text>
|
||||||
|
<strong>Aflysning</strong> – Mette Hansen aflyste kl. 15:00
|
||||||
|
</swp-notification-text>
|
||||||
|
<swp-notification-time>For 2 timer siden</swp-notification-time>
|
||||||
|
</swp-notification-content>
|
||||||
|
</swp-notification-item>
|
||||||
|
|
||||||
|
<swp-notification-item>
|
||||||
|
<swp-notification-icon>
|
||||||
|
<i class="ph ph-check"></i>
|
||||||
|
</swp-notification-icon>
|
||||||
|
<swp-notification-content>
|
||||||
|
<swp-notification-text>
|
||||||
|
<strong>Bekræftet</strong> – Louise Andersen bekræftede kl. 13:00
|
||||||
|
</swp-notification-text>
|
||||||
|
<swp-notification-time>I går kl. 18:30</swp-notification-time>
|
||||||
|
</swp-notification-content>
|
||||||
|
</swp-notification-item>
|
||||||
|
</swp-notification-list>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Waitlist Mini Card -->
|
||||||
|
<swp-waitlist-card>
|
||||||
|
<swp-waitlist-icon>
|
||||||
|
<i class="ph ph-users-three"></i>
|
||||||
|
<swp-waitlist-badge>4</swp-waitlist-badge>
|
||||||
|
</swp-waitlist-icon>
|
||||||
|
<swp-waitlist-label>På venteliste</swp-waitlist-label>
|
||||||
|
</swp-waitlist-card>
|
||||||
|
|
||||||
|
<!-- Quick Stats -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>
|
||||||
|
<i class="ph ph-chart-line-up"></i>
|
||||||
|
Denne uge
|
||||||
|
</swp-card-title>
|
||||||
|
</swp-card-header>
|
||||||
|
|
||||||
|
<swp-quick-stats>
|
||||||
|
<swp-quick-stat>
|
||||||
|
<swp-stat-value>47</swp-stat-value>
|
||||||
|
<swp-stat-label>Bookinger</swp-stat-label>
|
||||||
|
</swp-quick-stat>
|
||||||
|
<swp-quick-stat>
|
||||||
|
<swp-stat-value>38.200 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Omsætning</swp-stat-label>
|
||||||
|
</swp-quick-stat>
|
||||||
|
<swp-quick-stat>
|
||||||
|
<swp-stat-value>8</swp-stat-value>
|
||||||
|
<swp-stat-label>Nye kunder</swp-stat-label>
|
||||||
|
</swp-quick-stat>
|
||||||
|
<swp-quick-stat>
|
||||||
|
<swp-stat-value>72%</swp-stat-value>
|
||||||
|
<swp-stat-label>Gns. belægning</swp-stat-label>
|
||||||
|
</swp-quick-stat>
|
||||||
|
</swp-quick-stats>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Employee Status -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>
|
||||||
|
<i class="ph ph-users"></i>
|
||||||
|
Medarbejdere
|
||||||
|
</swp-card-title>
|
||||||
|
</swp-card-header>
|
||||||
|
|
||||||
|
<swp-employee-list>
|
||||||
|
<swp-employee-status-item>
|
||||||
|
<swp-employee-avatar>AS</swp-employee-avatar>
|
||||||
|
<swp-employee-info>
|
||||||
|
<swp-employee-name>Anna Sørensen</swp-employee-name>
|
||||||
|
<swp-employee-current>Ledig til kl. 11:00 (Balayage)</swp-employee-current>
|
||||||
|
</swp-employee-info>
|
||||||
|
<swp-employee-status-badge class="available">Ledig</swp-employee-status-badge>
|
||||||
|
</swp-employee-status-item>
|
||||||
|
|
||||||
|
<swp-employee-status-item>
|
||||||
|
<swp-employee-avatar>MH</swp-employee-avatar>
|
||||||
|
<swp-employee-info>
|
||||||
|
<swp-employee-name>Maria Hansen</swp-employee-name>
|
||||||
|
<swp-employee-current>Herreklip med Jonas</swp-employee-current>
|
||||||
|
</swp-employee-info>
|
||||||
|
<swp-employee-status-badge class="busy">Optaget</swp-employee-status-badge>
|
||||||
|
</swp-employee-status-item>
|
||||||
|
|
||||||
|
<swp-employee-status-item>
|
||||||
|
<swp-employee-avatar>LJ</swp-employee-avatar>
|
||||||
|
<swp-employee-info>
|
||||||
|
<swp-employee-name>Louise Jensen</swp-employee-name>
|
||||||
|
<swp-employee-current>Føn + Styling med Rikke</swp-employee-current>
|
||||||
|
</swp-employee-info>
|
||||||
|
<swp-employee-status-badge class="busy">Optaget</swp-employee-status-badge>
|
||||||
|
</swp-employee-status-item>
|
||||||
|
|
||||||
|
<swp-employee-status-item>
|
||||||
|
<swp-employee-avatar>PK</swp-employee-avatar>
|
||||||
|
<swp-employee-info>
|
||||||
|
<swp-employee-name>Peter Kristensen</swp-employee-name>
|
||||||
|
<swp-employee-current>Ledig til kl. 14:00</swp-employee-current>
|
||||||
|
</swp-employee-info>
|
||||||
|
<swp-employee-status-badge class="available">Ledig</swp-employee-status-badge>
|
||||||
|
</swp-employee-status-item>
|
||||||
|
</swp-employee-list>
|
||||||
|
</swp-card>
|
||||||
|
</swp-side-column>
|
||||||
|
</swp-dashboard-grid>
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<!-- Waitlist Drawer Overlay -->
|
||||||
|
<swp-drawer-overlay></swp-drawer-overlay>
|
||||||
|
|
||||||
|
<!-- Waitlist Drawer -->
|
||||||
|
<swp-waitlist-drawer>
|
||||||
|
<swp-drawer-header>
|
||||||
|
<swp-drawer-title>
|
||||||
|
Venteliste <swp-count>(4)</swp-count>
|
||||||
|
</swp-drawer-title>
|
||||||
|
<swp-drawer-close>
|
||||||
|
<i class="ph ph-x"></i>
|
||||||
|
</swp-drawer-close>
|
||||||
|
</swp-drawer-header>
|
||||||
|
<swp-drawer-body>
|
||||||
|
<swp-waitlist-list>
|
||||||
|
<!-- Entry 1 -->
|
||||||
|
<swp-waitlist-item>
|
||||||
|
<swp-waitlist-customer>
|
||||||
|
<swp-avatar>EC</swp-avatar>
|
||||||
|
<swp-waitlist-customer-info>
|
||||||
|
<swp-waitlist-name>Emma Christensen</swp-waitlist-name>
|
||||||
|
<swp-waitlist-phone>+45 12 34 56 78</swp-waitlist-phone>
|
||||||
|
</swp-waitlist-customer-info>
|
||||||
|
</swp-waitlist-customer>
|
||||||
|
<swp-waitlist-service>Dameklip + Farve</swp-waitlist-service>
|
||||||
|
<swp-waitlist-meta>
|
||||||
|
<swp-waitlist-periods>
|
||||||
|
<swp-label>Ønsker:</swp-label>
|
||||||
|
<swp-waitlist-period-tag>Mandag-Onsdag</swp-waitlist-period-tag>
|
||||||
|
<swp-waitlist-period-tag>Formiddag</swp-waitlist-period-tag>
|
||||||
|
</swp-waitlist-periods>
|
||||||
|
<swp-waitlist-dates>
|
||||||
|
<swp-waitlist-date>
|
||||||
|
<i class="ph ph-calendar"></i>
|
||||||
|
Tilmeldt: 2. jan 2026
|
||||||
|
</swp-waitlist-date>
|
||||||
|
<swp-waitlist-date class="expires">
|
||||||
|
<i class="ph ph-clock"></i>
|
||||||
|
Udløber: 16. jan 2026
|
||||||
|
</swp-waitlist-date>
|
||||||
|
</swp-waitlist-dates>
|
||||||
|
</swp-waitlist-meta>
|
||||||
|
<swp-waitlist-actions>
|
||||||
|
<swp-btn class="secondary">
|
||||||
|
<i class="ph ph-phone"></i>
|
||||||
|
Kontakt
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<i class="ph ph-calendar-plus"></i>
|
||||||
|
Book nu
|
||||||
|
</swp-btn>
|
||||||
|
</swp-waitlist-actions>
|
||||||
|
</swp-waitlist-item>
|
||||||
|
|
||||||
|
<!-- Entry 2 -->
|
||||||
|
<swp-waitlist-item>
|
||||||
|
<swp-waitlist-customer>
|
||||||
|
<swp-avatar>MS</swp-avatar>
|
||||||
|
<swp-waitlist-customer-info>
|
||||||
|
<swp-waitlist-name>Mikkel Sørensen</swp-waitlist-name>
|
||||||
|
<swp-waitlist-phone>+45 23 45 67 89</swp-waitlist-phone>
|
||||||
|
</swp-waitlist-customer-info>
|
||||||
|
</swp-waitlist-customer>
|
||||||
|
<swp-waitlist-service>Herreklip</swp-waitlist-service>
|
||||||
|
<swp-waitlist-meta>
|
||||||
|
<swp-waitlist-periods>
|
||||||
|
<swp-label>Ønsker:</swp-label>
|
||||||
|
<swp-waitlist-period-tag>Weekend</swp-waitlist-period-tag>
|
||||||
|
</swp-waitlist-periods>
|
||||||
|
<swp-waitlist-dates>
|
||||||
|
<swp-waitlist-date>
|
||||||
|
<i class="ph ph-calendar"></i>
|
||||||
|
Tilmeldt: 30. dec 2025
|
||||||
|
</swp-waitlist-date>
|
||||||
|
<swp-waitlist-date class="expires soon">
|
||||||
|
<i class="ph ph-clock"></i>
|
||||||
|
Udløber: 6. jan 2026
|
||||||
|
</swp-waitlist-date>
|
||||||
|
</swp-waitlist-dates>
|
||||||
|
</swp-waitlist-meta>
|
||||||
|
<swp-waitlist-actions>
|
||||||
|
<swp-btn class="secondary">
|
||||||
|
<i class="ph ph-phone"></i>
|
||||||
|
Kontakt
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<i class="ph ph-calendar-plus"></i>
|
||||||
|
Book nu
|
||||||
|
</swp-btn>
|
||||||
|
</swp-waitlist-actions>
|
||||||
|
</swp-waitlist-item>
|
||||||
|
|
||||||
|
<!-- Entry 3 -->
|
||||||
|
<swp-waitlist-item>
|
||||||
|
<swp-waitlist-customer>
|
||||||
|
<swp-avatar>LA</swp-avatar>
|
||||||
|
<swp-waitlist-customer-info>
|
||||||
|
<swp-waitlist-name>Lise Andersen</swp-waitlist-name>
|
||||||
|
<swp-waitlist-phone>+45 34 56 78 90</swp-waitlist-phone>
|
||||||
|
</swp-waitlist-customer-info>
|
||||||
|
</swp-waitlist-customer>
|
||||||
|
<swp-waitlist-service>Balayage</swp-waitlist-service>
|
||||||
|
<swp-waitlist-meta>
|
||||||
|
<swp-waitlist-periods>
|
||||||
|
<swp-label>Ønsker:</swp-label>
|
||||||
|
<swp-waitlist-period-tag>Tirsdag-Torsdag</swp-waitlist-period-tag>
|
||||||
|
<swp-waitlist-period-tag>Eftermiddag</swp-waitlist-period-tag>
|
||||||
|
</swp-waitlist-periods>
|
||||||
|
<swp-waitlist-dates>
|
||||||
|
<swp-waitlist-date>
|
||||||
|
<i class="ph ph-calendar"></i>
|
||||||
|
Tilmeldt: 28. dec 2025
|
||||||
|
</swp-waitlist-date>
|
||||||
|
<swp-waitlist-date class="expires">
|
||||||
|
<i class="ph ph-clock"></i>
|
||||||
|
Udløber: 11. jan 2026
|
||||||
|
</swp-waitlist-date>
|
||||||
|
</swp-waitlist-dates>
|
||||||
|
</swp-waitlist-meta>
|
||||||
|
<swp-waitlist-actions>
|
||||||
|
<swp-btn class="secondary">
|
||||||
|
<i class="ph ph-phone"></i>
|
||||||
|
Kontakt
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<i class="ph ph-calendar-plus"></i>
|
||||||
|
Book nu
|
||||||
|
</swp-btn>
|
||||||
|
</swp-waitlist-actions>
|
||||||
|
</swp-waitlist-item>
|
||||||
|
|
||||||
|
<!-- Entry 4 -->
|
||||||
|
<swp-waitlist-item>
|
||||||
|
<swp-waitlist-customer>
|
||||||
|
<swp-avatar>PH</swp-avatar>
|
||||||
|
<swp-waitlist-customer-info>
|
||||||
|
<swp-waitlist-name>Peter Hansen</swp-waitlist-name>
|
||||||
|
<swp-waitlist-phone>+45 45 67 89 01</swp-waitlist-phone>
|
||||||
|
</swp-waitlist-customer-info>
|
||||||
|
</swp-waitlist-customer>
|
||||||
|
<swp-waitlist-service>Herreklip + Skæg</swp-waitlist-service>
|
||||||
|
<swp-waitlist-meta>
|
||||||
|
<swp-waitlist-periods>
|
||||||
|
<swp-label>Ønsker:</swp-label>
|
||||||
|
<swp-waitlist-period-tag>Fleksibel</swp-waitlist-period-tag>
|
||||||
|
</swp-waitlist-periods>
|
||||||
|
<swp-waitlist-dates>
|
||||||
|
<swp-waitlist-date>
|
||||||
|
<i class="ph ph-calendar"></i>
|
||||||
|
Tilmeldt: 27. dec 2025
|
||||||
|
</swp-waitlist-date>
|
||||||
|
<swp-waitlist-date class="expires">
|
||||||
|
<i class="ph ph-clock"></i>
|
||||||
|
Udløber: 10. jan 2026
|
||||||
|
</swp-waitlist-date>
|
||||||
|
</swp-waitlist-dates>
|
||||||
|
</swp-waitlist-meta>
|
||||||
|
<swp-waitlist-actions>
|
||||||
|
<swp-btn class="secondary">
|
||||||
|
<i class="ph ph-phone"></i>
|
||||||
|
Kontakt
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<i class="ph ph-calendar-plus"></i>
|
||||||
|
Book nu
|
||||||
|
</swp-btn>
|
||||||
|
</swp-waitlist-actions>
|
||||||
|
</swp-waitlist-item>
|
||||||
|
</swp-waitlist-list>
|
||||||
|
</swp-drawer-body>
|
||||||
|
</swp-waitlist-drawer>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Update current time
|
||||||
|
function updateTime() {
|
||||||
|
const now = new Date();
|
||||||
|
const hours = String(now.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
||||||
|
const timeEl = document.querySelector('swp-current-time swp-time');
|
||||||
|
if (timeEl) {
|
||||||
|
timeEl.textContent = `${hours}:${minutes}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTime();
|
||||||
|
setInterval(updateTime, 60000);
|
||||||
|
|
||||||
|
// Click handlers for attention items
|
||||||
|
document.querySelectorAll('swp-attention-action').forEach(action => {
|
||||||
|
action.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
alert('Handling: ' + action.textContent);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handlers for bookings
|
||||||
|
document.querySelectorAll('swp-booking-item').forEach(item => {
|
||||||
|
item.addEventListener('click', () => {
|
||||||
|
const service = item.querySelector('swp-booking-service').textContent;
|
||||||
|
alert('Åbn booking: ' + service);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Waitlist Drawer functionality
|
||||||
|
const waitlistCard = document.querySelector('swp-waitlist-card');
|
||||||
|
const waitlistDrawer = document.querySelector('swp-waitlist-drawer');
|
||||||
|
const drawerOverlay = document.querySelector('swp-drawer-overlay');
|
||||||
|
const drawerClose = document.querySelector('swp-drawer-close');
|
||||||
|
|
||||||
|
function openWaitlistDrawer() {
|
||||||
|
waitlistDrawer.classList.add('open');
|
||||||
|
drawerOverlay.classList.add('visible');
|
||||||
|
document.body.style.overflow = 'hidden';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeWaitlistDrawer() {
|
||||||
|
waitlistDrawer.classList.remove('open');
|
||||||
|
drawerOverlay.classList.remove('visible');
|
||||||
|
document.body.style.overflow = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
waitlistCard.addEventListener('click', openWaitlistDrawer);
|
||||||
|
drawerClose.addEventListener('click', closeWaitlistDrawer);
|
||||||
|
drawerOverlay.addEventListener('click', closeWaitlistDrawer);
|
||||||
|
|
||||||
|
// Close on Escape key
|
||||||
|
document.addEventListener('keydown', (e) => {
|
||||||
|
if (e.key === 'Escape' && waitlistDrawer.classList.contains('open')) {
|
||||||
|
closeWaitlistDrawer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Click handlers for waitlist actions
|
||||||
|
document.querySelectorAll('swp-waitlist-actions swp-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', (e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const isContact = btn.classList.contains('secondary');
|
||||||
|
const name = btn.closest('swp-waitlist-item').querySelector('swp-waitlist-name').textContent;
|
||||||
|
if (isContact) {
|
||||||
|
alert('Kontakt: ' + name);
|
||||||
|
} else {
|
||||||
|
alert('Book nu for: ' + name);
|
||||||
|
closeWaitlistDrawer();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
3481
.workbench/POC/poc-detail-drawer.html
Normal file
4150
.workbench/POC/poc-employee.html
Normal file
1533
.workbench/POC/poc-gavekort-detail.html
Normal file
1203
.workbench/POC/poc-gavekort.html
Normal file
4470
.workbench/POC/poc-indstillinger.html
Normal file
995
.workbench/POC/poc-kasseafstemning.html
Normal file
|
|
@ -0,0 +1,995 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Kasseafstemning - POC</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 {
|
||||||
|
--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: #f59e0b;
|
||||||
|
--color-purple: #8b5cf6;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--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-page-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-topbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-2 {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
.grid-2 { grid-template-columns: 1fr; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PAGE HEADER
|
||||||
|
========================================== */
|
||||||
|
swp-page-header {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-header h1 {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-subtitle {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
CARDS
|
||||||
|
========================================== */
|
||||||
|
swp-card {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
margin-bottom: 20px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-card-title {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-card-hint {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-card-body {
|
||||||
|
display: block;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FORM ELEMENTS
|
||||||
|
========================================== */
|
||||||
|
swp-form-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-field {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-field.full-width {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-bottom: 6px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-label .required {
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-input input,
|
||||||
|
swp-form-input select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
transition: border-color 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-form-input input:focus,
|
||||||
|
swp-form-input select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-auto-id {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 16px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PERIOD DISPLAY
|
||||||
|
========================================== */
|
||||||
|
swp-period-display {
|
||||||
|
display: block;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-value {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-value .arrow {
|
||||||
|
color: var(--color-teal);
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-hint {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
DATA TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-data-table {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-header {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 100px 140px;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 10px 0;
|
||||||
|
border-bottom: 2px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-header span {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-header span:not(:first-child) {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 100px 140px;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 14px 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-system {
|
||||||
|
text-align: right;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-input input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
text-align: right;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-input input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-input input::placeholder {
|
||||||
|
color: #bbb;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-value {
|
||||||
|
text-align: right;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-data-value.muted {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-note {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 16px;
|
||||||
|
padding: 12px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
CASH CALCULATION
|
||||||
|
========================================== */
|
||||||
|
swp-calc-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 14px 0;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-row:last-of-type {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-row.input-row {
|
||||||
|
padding: 18px 0;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
margin: 16px -20px -20px -20px;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-label span {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-label small {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-value {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-value.muted {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-input input {
|
||||||
|
width: 140px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
text-align: right;
|
||||||
|
border: 2px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-calc-input input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
DIFFERENCE BOX
|
||||||
|
========================================== */
|
||||||
|
swp-difference-box {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-box.positive {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 10%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-box.negative {
|
||||||
|
background: color-mix(in srgb, var(--color-red) 10%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-box.neutral {
|
||||||
|
background: color-mix(in srgb, var(--color-teal) 10%, white);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-label {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-label small {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-value {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-box.positive swp-difference-value {
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-box.negative swp-difference-value {
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-difference-box.neutral swp-difference-value {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
NOTE FIELD
|
||||||
|
========================================== */
|
||||||
|
swp-note-field textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 80px;
|
||||||
|
padding: 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-note-field textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-note-hint {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATUS & APPROVAL
|
||||||
|
========================================== */
|
||||||
|
swp-status-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.draft {
|
||||||
|
background: color-mix(in srgb, var(--color-amber) 15%, white);
|
||||||
|
color: #b45309;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.approved {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, white);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge::before {
|
||||||
|
content: '';
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-approval-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-checkbox-field {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-checkbox-field input[type="checkbox"] {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
margin-top: 2px;
|
||||||
|
accent-color: var(--color-teal);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-checkbox-field label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text);
|
||||||
|
cursor: pointer;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ACTIONS
|
||||||
|
========================================== */
|
||||||
|
swp-card-footer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-actions-right {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.ghost {
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.ghost:hover {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary {
|
||||||
|
background: var(--color-teal);
|
||||||
|
border: 1px solid var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:hover {
|
||||||
|
background: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:disabled {
|
||||||
|
background: #ccc;
|
||||||
|
border-color: #ccc;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-system-note {
|
||||||
|
display: block;
|
||||||
|
font-size: 11px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
text-align: center;
|
||||||
|
padding: 12px;
|
||||||
|
}
|
||||||
|
</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
|
||||||
|
</swp-back-link>
|
||||||
|
<swp-page-title>Kasseafstemning</swp-page-title>
|
||||||
|
</swp-topbar-left>
|
||||||
|
<swp-topbar-right>
|
||||||
|
<swp-status-badge class="draft" id="statusBadge">Kladde</swp-status-badge>
|
||||||
|
</swp-topbar-right>
|
||||||
|
</swp-topbar>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
<!-- Page Header -->
|
||||||
|
<swp-page-header>
|
||||||
|
<h1>Kasseafstemning</h1>
|
||||||
|
<swp-page-subtitle>Enkel dagsafslutning med fokus på kontanter. Kort afstemmes separat mod bank/indløser.</swp-page-subtitle>
|
||||||
|
</swp-page-header>
|
||||||
|
|
||||||
|
<div class="grid-2">
|
||||||
|
<!-- VENSTRE KOLONNE -->
|
||||||
|
<div>
|
||||||
|
<!-- Dagens tal -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>Dagens tal</swp-card-title>
|
||||||
|
<swp-card-hint>Systemtal vs. kontrol</swp-card-hint>
|
||||||
|
</swp-card-header>
|
||||||
|
<swp-card-body>
|
||||||
|
<swp-data-table>
|
||||||
|
<swp-data-header>
|
||||||
|
<span>Type</span>
|
||||||
|
<span>System</span>
|
||||||
|
<span>Kontrol</span>
|
||||||
|
</swp-data-header>
|
||||||
|
|
||||||
|
<swp-data-row>
|
||||||
|
<swp-data-label>Kortbetalinger</swp-data-label>
|
||||||
|
<swp-data-system>12.875,50</swp-data-system>
|
||||||
|
<swp-data-input>
|
||||||
|
<input type="text" placeholder="Valgfrit" />
|
||||||
|
</swp-data-input>
|
||||||
|
</swp-data-row>
|
||||||
|
|
||||||
|
<swp-data-row>
|
||||||
|
<swp-data-label>MobilePay / Online</swp-data-label>
|
||||||
|
<swp-data-system>2.450,00</swp-data-system>
|
||||||
|
<swp-data-input>
|
||||||
|
<input type="text" placeholder="Valgfrit" />
|
||||||
|
</swp-data-input>
|
||||||
|
</swp-data-row>
|
||||||
|
|
||||||
|
<swp-data-row>
|
||||||
|
<swp-data-label>Kontantsalg</swp-data-label>
|
||||||
|
<swp-data-system>3.540,00</swp-data-system>
|
||||||
|
<swp-data-value class="muted">..</swp-data-value>
|
||||||
|
</swp-data-row>
|
||||||
|
</swp-data-table>
|
||||||
|
|
||||||
|
<swp-table-note>Kort og MobilePay afstemmes mod bank/indløser. Kontanter tælles op nedenfor.</swp-table-note>
|
||||||
|
</swp-card-body>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Kontanter i kassen -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>Kontanter i kassen</swp-card-title>
|
||||||
|
</swp-card-header>
|
||||||
|
<swp-card-body>
|
||||||
|
<swp-calc-row>
|
||||||
|
<swp-calc-label>
|
||||||
|
<span>Startbeholdning</span>
|
||||||
|
<small>Overført fra sidste afstemning</small>
|
||||||
|
</swp-calc-label>
|
||||||
|
<swp-calc-value class="muted">2.000,00</swp-calc-value>
|
||||||
|
</swp-calc-row>
|
||||||
|
|
||||||
|
<swp-calc-row>
|
||||||
|
<swp-calc-label>
|
||||||
|
<span>Udbetalinger / Bilag</span>
|
||||||
|
<small>Sammentæl bilag betalt kontant</small>
|
||||||
|
</swp-calc-label>
|
||||||
|
<swp-calc-input>
|
||||||
|
<input type="text" id="payouts" placeholder="0,00" />
|
||||||
|
</swp-calc-input>
|
||||||
|
</swp-calc-row>
|
||||||
|
|
||||||
|
<swp-calc-row>
|
||||||
|
<swp-calc-label>
|
||||||
|
<span>Udtaget til bank</span>
|
||||||
|
<small>Kontanter lagt til side</small>
|
||||||
|
</swp-calc-label>
|
||||||
|
<swp-calc-input>
|
||||||
|
<input type="text" id="toBank" placeholder="0,00" />
|
||||||
|
</swp-calc-input>
|
||||||
|
</swp-calc-row>
|
||||||
|
|
||||||
|
<swp-calc-row>
|
||||||
|
<swp-calc-label>
|
||||||
|
<span>Forventet kontantbeholdning</span>
|
||||||
|
</swp-calc-label>
|
||||||
|
<swp-calc-value id="expectedCash">5.220,00</swp-calc-value>
|
||||||
|
</swp-calc-row>
|
||||||
|
|
||||||
|
<swp-calc-row class="input-row">
|
||||||
|
<swp-calc-label>
|
||||||
|
<span>Optalt kontantbeholdning <span style="color: var(--color-red)">*</span></span>
|
||||||
|
<small>Hvad ligger der faktisk i kassen?</small>
|
||||||
|
</swp-calc-label>
|
||||||
|
<swp-calc-input>
|
||||||
|
<input type="text" id="actualCash" placeholder="0,00" />
|
||||||
|
</swp-calc-input>
|
||||||
|
</swp-calc-row>
|
||||||
|
</swp-card-body>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Difference -->
|
||||||
|
<swp-difference-box id="differenceBox" class="neutral">
|
||||||
|
<swp-difference-label>
|
||||||
|
Kontant difference
|
||||||
|
<small>Optalt minus forventet</small>
|
||||||
|
</swp-difference-label>
|
||||||
|
<swp-difference-value id="differenceValue">– kr</swp-difference-value>
|
||||||
|
</swp-difference-box>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- HØJRE KOLONNE -->
|
||||||
|
<div>
|
||||||
|
<!-- Dagsoplysninger -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>Dagsoplysninger</swp-card-title>
|
||||||
|
<swp-card-hint>Identificér afstemningen</swp-card-hint>
|
||||||
|
</swp-card-header>
|
||||||
|
<swp-card-body>
|
||||||
|
<swp-period-display>
|
||||||
|
<swp-period-label>Periode</swp-period-label>
|
||||||
|
<swp-period-value>
|
||||||
|
<span class="from">28. dec 2025 kl. 18:00</span>
|
||||||
|
<span class="arrow">→</span>
|
||||||
|
<span class="to">29. dec 2025</span>
|
||||||
|
</swp-period-value>
|
||||||
|
</swp-period-display>
|
||||||
|
|
||||||
|
<swp-form-grid style="margin-top: 20px;">
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Kassepunkt</swp-form-label>
|
||||||
|
<swp-form-input>
|
||||||
|
<select id="register">
|
||||||
|
<option>Kasse 1 – Reception</option>
|
||||||
|
<option>Kasse 2 – Salon</option>
|
||||||
|
</select>
|
||||||
|
</swp-form-input>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Afsluttet af</swp-form-label>
|
||||||
|
<swp-form-input>
|
||||||
|
<select id="employee">
|
||||||
|
<option>Anna Jensen</option>
|
||||||
|
<option>Karina Knudsen</option>
|
||||||
|
<option>Martin Nielsen</option>
|
||||||
|
</select>
|
||||||
|
</swp-form-input>
|
||||||
|
</swp-form-field>
|
||||||
|
</swp-form-grid>
|
||||||
|
|
||||||
|
<swp-auto-id>Afstemnings-ID: <strong>KA-2025-12-29</strong> · Z-043</swp-auto-id>
|
||||||
|
</swp-card-body>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Note -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>Note til difference</swp-card-title>
|
||||||
|
<swp-card-hint>Valgfrit</swp-card-hint>
|
||||||
|
</swp-card-header>
|
||||||
|
<swp-card-body>
|
||||||
|
<swp-note-field>
|
||||||
|
<textarea placeholder="Fx kassedifference, fejlslag, runding osv."></textarea>
|
||||||
|
</swp-note-field>
|
||||||
|
<swp-note-hint>Kan gøres obligatorisk ved difference over 100 kr.</swp-note-hint>
|
||||||
|
</swp-card-body>
|
||||||
|
</swp-card>
|
||||||
|
|
||||||
|
<!-- Godkendelse -->
|
||||||
|
<swp-card>
|
||||||
|
<swp-card-header>
|
||||||
|
<swp-card-title>Afslut dagen</swp-card-title>
|
||||||
|
</swp-card-header>
|
||||||
|
<swp-card-body>
|
||||||
|
<swp-approval-grid>
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Status</swp-form-label>
|
||||||
|
<swp-status-row>
|
||||||
|
<swp-status-badge class="draft">Kladde</swp-status-badge>
|
||||||
|
</swp-status-row>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-form-field>
|
||||||
|
<swp-form-label>Godkendt af (valgfrit)</swp-form-label>
|
||||||
|
<swp-form-input>
|
||||||
|
<select id="approver">
|
||||||
|
<option value="">Vælg...</option>
|
||||||
|
<option>Karina Knudsen</option>
|
||||||
|
<option>Butikschef</option>
|
||||||
|
</select>
|
||||||
|
</swp-form-input>
|
||||||
|
</swp-form-field>
|
||||||
|
|
||||||
|
<swp-checkbox-field>
|
||||||
|
<input type="checkbox" id="confirmCheckbox" />
|
||||||
|
<label for="confirmCheckbox">Jeg bekræfter, at kassen er talt op, og at tallene er indtastet efter bedste evne.</label>
|
||||||
|
</swp-checkbox-field>
|
||||||
|
</swp-approval-grid>
|
||||||
|
</swp-card-body>
|
||||||
|
<swp-card-footer>
|
||||||
|
<swp-btn class="secondary">Gem som kladde</swp-btn>
|
||||||
|
<swp-actions-right>
|
||||||
|
<swp-btn class="ghost">Fortryd</swp-btn>
|
||||||
|
<swp-btn class="primary" id="approveBtn" disabled>Godkend & lås</swp-btn>
|
||||||
|
</swp-actions-right>
|
||||||
|
</swp-card-footer>
|
||||||
|
</swp-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<swp-system-note>Systemet gemmer hvornår og af hvem der er godkendt – enkelt kontrolspor.</swp-system-note>
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Base values (from system)
|
||||||
|
const startBalance = 2000;
|
||||||
|
const cashSales = 3540;
|
||||||
|
|
||||||
|
// Format number as Danish currency
|
||||||
|
function formatNumber(num) {
|
||||||
|
return num.toLocaleString('da-DK', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse Danish number format
|
||||||
|
function parseNumber(str) {
|
||||||
|
if (!str) return 0;
|
||||||
|
return parseFloat(str.replace(/\./g, '').replace(',', '.')) || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate expected cash and difference
|
||||||
|
function calculate() {
|
||||||
|
const payoutsInput = document.getElementById('payouts');
|
||||||
|
const toBankInput = document.getElementById('toBank');
|
||||||
|
const actualInput = document.getElementById('actualCash');
|
||||||
|
|
||||||
|
const payouts = parseNumber(payoutsInput.value);
|
||||||
|
const toBank = parseNumber(toBankInput.value);
|
||||||
|
const actual = parseNumber(actualInput.value);
|
||||||
|
|
||||||
|
// Forventet = start + salg - udbetalinger - til bank
|
||||||
|
const expectedCash = startBalance + cashSales - payouts - toBank;
|
||||||
|
document.getElementById('expectedCash').textContent = formatNumber(expectedCash);
|
||||||
|
|
||||||
|
// Difference
|
||||||
|
const box = document.getElementById('differenceBox');
|
||||||
|
const value = document.getElementById('differenceValue');
|
||||||
|
const diff = actual - expectedCash;
|
||||||
|
|
||||||
|
box.classList.remove('positive', 'negative', 'neutral');
|
||||||
|
|
||||||
|
if (actual === 0 && actualInput.value === '') {
|
||||||
|
value.textContent = '– kr';
|
||||||
|
box.classList.add('neutral');
|
||||||
|
} else if (diff > 0) {
|
||||||
|
value.textContent = '+' + formatNumber(diff) + ' kr';
|
||||||
|
box.classList.add('positive');
|
||||||
|
} else if (diff < 0) {
|
||||||
|
value.textContent = formatNumber(diff) + ' kr';
|
||||||
|
box.classList.add('negative');
|
||||||
|
} else {
|
||||||
|
value.textContent = '0,00 kr';
|
||||||
|
box.classList.add('neutral');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('payouts').addEventListener('input', calculate);
|
||||||
|
document.getElementById('toBank').addEventListener('input', calculate);
|
||||||
|
document.getElementById('actualCash').addEventListener('input', calculate);
|
||||||
|
|
||||||
|
// Enable approve button when checkbox is checked
|
||||||
|
const checkbox = document.getElementById('confirmCheckbox');
|
||||||
|
const approveBtn = document.getElementById('approveBtn');
|
||||||
|
|
||||||
|
checkbox.addEventListener('change', () => {
|
||||||
|
approveBtn.disabled = !checkbox.checked;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initial display
|
||||||
|
calculate();
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
798
.workbench/POC/poc-kasseafstemninger.html
Normal file
|
|
@ -0,0 +1,798 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Kasseafstemninger - POC</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 {
|
||||||
|
--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: #f59e0b;
|
||||||
|
--color-purple: #8b5cf6;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--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-page-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-topbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FILTER BAR
|
||||||
|
========================================== */
|
||||||
|
swp-filter-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-bar input,
|
||||||
|
swp-filter-bar select {
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-bar input:focus,
|
||||||
|
swp-filter-bar select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATS BAR
|
||||||
|
========================================== */
|
||||||
|
swp-stats-bar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-value {
|
||||||
|
display: block;
|
||||||
|
font-size: 24px;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.warning swp-stat-value {
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.negative swp-stat-value {
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ACTION BAR
|
||||||
|
========================================== */
|
||||||
|
swp-action-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 16px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px 8px 0 0;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-selection-info {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-table {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 0 0 8px 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.checkbox,
|
||||||
|
swp-td.checkbox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table input[type="checkbox"] {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
accent-color: var(--color-teal);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 40px 70px 60px minmax(140px, 1fr) 90px 100px 100px 90px 100px 40px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header {
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 12px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
transition: background 150ms ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.mono {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.muted {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.negative {
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.positive {
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-cell {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-cell .dates {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATUS BADGE
|
||||||
|
========================================== */
|
||||||
|
swp-status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.approved {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, white);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.draft {
|
||||||
|
background: color-mix(in srgb, var(--color-amber) 15%, white);
|
||||||
|
color: #b45309;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge::before {
|
||||||
|
content: '';
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td:nth-child(9) {
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.id {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABLE FOOTER
|
||||||
|
========================================== */
|
||||||
|
swp-table-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 20px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
BUTTONS
|
||||||
|
========================================== */
|
||||||
|
swp-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary {
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:hover {
|
||||||
|
background: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-row-arrow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-row-arrow svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
RESPONSIVE
|
||||||
|
========================================== */
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
swp-stats-bar {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
grid-template-columns: 80px 1fr 100px 100px 80px 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th:nth-child(3),
|
||||||
|
swp-td:nth-child(3),
|
||||||
|
swp-th:nth-child(4),
|
||||||
|
swp-td:nth-child(4) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</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
|
||||||
|
</swp-back-link>
|
||||||
|
<swp-page-title>Kasseafstemninger</swp-page-title>
|
||||||
|
</swp-topbar-left>
|
||||||
|
<swp-topbar-right>
|
||||||
|
</swp-topbar-right>
|
||||||
|
</swp-topbar>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
<!-- Filter Bar -->
|
||||||
|
<swp-filter-bar>
|
||||||
|
<swp-filter-group>
|
||||||
|
<swp-filter-label>Fra</swp-filter-label>
|
||||||
|
<input type="date" id="dateFrom" />
|
||||||
|
</swp-filter-group>
|
||||||
|
<swp-filter-group>
|
||||||
|
<swp-filter-label>Til</swp-filter-label>
|
||||||
|
<input type="date" id="dateTo" />
|
||||||
|
</swp-filter-group>
|
||||||
|
<swp-filter-group>
|
||||||
|
<swp-filter-label>Kassepunkt</swp-filter-label>
|
||||||
|
<select id="register">
|
||||||
|
<option>Alle</option>
|
||||||
|
<option>Kasse 1 – Reception</option>
|
||||||
|
<option>Kasse 2 – Salon</option>
|
||||||
|
</select>
|
||||||
|
</swp-filter-group>
|
||||||
|
<swp-filter-group>
|
||||||
|
<swp-filter-label>Status</swp-filter-label>
|
||||||
|
<select id="status">
|
||||||
|
<option>Alle</option>
|
||||||
|
<option>Godkendt</option>
|
||||||
|
<option>Kladde</option>
|
||||||
|
</select>
|
||||||
|
</swp-filter-group>
|
||||||
|
<swp-filter-spacer></swp-filter-spacer>
|
||||||
|
<swp-btn class="secondary">Nulstil</swp-btn>
|
||||||
|
</swp-filter-bar>
|
||||||
|
|
||||||
|
<!-- Stats Bar -->
|
||||||
|
<swp-stats-bar>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>12</swp-stat-value>
|
||||||
|
<swp-stat-label>Afstemninger i periode</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="highlight">
|
||||||
|
<swp-stat-value>186.450 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Total omsætning</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>42.340 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Kontantsalg</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="warning">
|
||||||
|
<swp-stat-value>-75 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Samlet difference</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
</swp-stats-bar>
|
||||||
|
|
||||||
|
<!-- Action Bar -->
|
||||||
|
<swp-action-bar>
|
||||||
|
<swp-selection-info>
|
||||||
|
<span id="selectionCount">0 valgt</span>
|
||||||
|
</swp-selection-info>
|
||||||
|
<swp-btn class="primary" id="exportBtn" disabled>
|
||||||
|
<svg viewBox="0 0 24 24"><path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/></svg>
|
||||||
|
Eksporter SAF-T
|
||||||
|
</swp-btn>
|
||||||
|
</swp-action-bar>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<swp-table>
|
||||||
|
<swp-table-header>
|
||||||
|
<swp-th class="checkbox"><input type="checkbox" id="selectAll" /></swp-th>
|
||||||
|
<swp-th>Dato</swp-th>
|
||||||
|
<swp-th>ID</swp-th>
|
||||||
|
<swp-th>Periode</swp-th>
|
||||||
|
<swp-th>Kassepunkt</swp-th>
|
||||||
|
<swp-th>Afsluttet af</swp-th>
|
||||||
|
<swp-th class="right">Omsætning</swp-th>
|
||||||
|
<swp-th class="right">Difference</swp-th>
|
||||||
|
<swp-th>Status</swp-th>
|
||||||
|
<swp-th></swp-th>
|
||||||
|
</swp-table-header>
|
||||||
|
<swp-table-body>
|
||||||
|
<swp-table-row data-id="draft" class="draft-row">
|
||||||
|
<swp-td class="checkbox"></swp-td>
|
||||||
|
<swp-td class="muted">I dag</swp-td>
|
||||||
|
<swp-td class="id muted">–</swp-td>
|
||||||
|
<swp-td>
|
||||||
|
<swp-period-cell>
|
||||||
|
<span class="dates">29. dec 17:45 → ...</span>
|
||||||
|
</swp-period-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Kasse 1</swp-td>
|
||||||
|
<swp-td class="muted">–</swp-td>
|
||||||
|
<swp-td class="right mono muted">4.250 kr</swp-td>
|
||||||
|
<swp-td class="right mono muted">–</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="draft">Kladde</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="043">
|
||||||
|
<swp-td class="checkbox"><input type="checkbox" class="row-select" /></swp-td>
|
||||||
|
<swp-td>29. dec</swp-td>
|
||||||
|
<swp-td class="id">Z-043</swp-td>
|
||||||
|
<swp-td>
|
||||||
|
<swp-period-cell>
|
||||||
|
<span class="dates">28. dec 18:00 → 29. dec 17:45</span>
|
||||||
|
</swp-period-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Kasse 1</swp-td>
|
||||||
|
<swp-td>Anna Jensen</swp-td>
|
||||||
|
<swp-td class="right mono">18.865 kr</swp-td>
|
||||||
|
<swp-td class="right mono">0 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="approved">Godkendt</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="042">
|
||||||
|
<swp-td class="checkbox"><input type="checkbox" class="row-select" /></swp-td>
|
||||||
|
<swp-td>28. dec</swp-td>
|
||||||
|
<swp-td class="id">Z-042</swp-td>
|
||||||
|
<swp-td>
|
||||||
|
<swp-period-cell>
|
||||||
|
<span class="dates">27. dec 18:30 → 28. dec 18:00</span>
|
||||||
|
</swp-period-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Kasse 1</swp-td>
|
||||||
|
<swp-td>Karina Knudsen</swp-td>
|
||||||
|
<swp-td class="right mono">12.450 kr</swp-td>
|
||||||
|
<swp-td class="right mono negative">-25 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="approved">Godkendt</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="041">
|
||||||
|
<swp-td class="checkbox"><input type="checkbox" class="row-select" /></swp-td>
|
||||||
|
<swp-td>27. dec</swp-td>
|
||||||
|
<swp-td class="id">Z-041</swp-td>
|
||||||
|
<swp-td>
|
||||||
|
<swp-period-cell>
|
||||||
|
<span class="dates">26. dec 18:00 → 27. dec 18:30</span>
|
||||||
|
</swp-period-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Kasse 1</swp-td>
|
||||||
|
<swp-td>Martin Nielsen</swp-td>
|
||||||
|
<swp-td class="right mono">21.340 kr</swp-td>
|
||||||
|
<swp-td class="right mono">0 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="approved">Godkendt</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="040">
|
||||||
|
<swp-td class="checkbox"><input type="checkbox" class="row-select" /></swp-td>
|
||||||
|
<swp-td>23. dec</swp-td>
|
||||||
|
<swp-td class="id">Z-040</swp-td>
|
||||||
|
<swp-td>
|
||||||
|
<swp-period-cell>
|
||||||
|
<span class="dates">22. dec 18:00 → 23. dec 17:30</span>
|
||||||
|
</swp-period-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Kasse 1</swp-td>
|
||||||
|
<swp-td>Anna Jensen</swp-td>
|
||||||
|
<swp-td class="right mono">28.750 kr</swp-td>
|
||||||
|
<swp-td class="right mono negative">-50 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="approved">Godkendt</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="039">
|
||||||
|
<swp-td class="checkbox"><input type="checkbox" class="row-select" /></swp-td>
|
||||||
|
<swp-td>22. dec</swp-td>
|
||||||
|
<swp-td class="id">Z-039</swp-td>
|
||||||
|
<swp-td>
|
||||||
|
<swp-period-cell>
|
||||||
|
<span class="dates">21. dec 18:15 → 22. dec 18:00</span>
|
||||||
|
</swp-period-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Kasse 1</swp-td>
|
||||||
|
<swp-td>Karina Knudsen</swp-td>
|
||||||
|
<swp-td class="right mono">15.890 kr</swp-td>
|
||||||
|
<swp-td class="right mono">0 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="approved">Godkendt</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
</swp-table-body>
|
||||||
|
<swp-table-footer>
|
||||||
|
<span>Viser 6 afstemninger</span>
|
||||||
|
<span>Z-038 → Z-043</span>
|
||||||
|
</swp-table-footer>
|
||||||
|
</swp-table>
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Set default date range (last 30 days)
|
||||||
|
const today = new Date();
|
||||||
|
const thirtyDaysAgo = new Date(today);
|
||||||
|
thirtyDaysAgo.setDate(today.getDate() - 30);
|
||||||
|
|
||||||
|
document.getElementById('dateTo').value = today.toISOString().split('T')[0];
|
||||||
|
document.getElementById('dateFrom').value = thirtyDaysAgo.toISOString().split('T')[0];
|
||||||
|
|
||||||
|
// Checkbox selection handling
|
||||||
|
const selectAll = document.getElementById('selectAll');
|
||||||
|
const rowCheckboxes = document.querySelectorAll('.row-select');
|
||||||
|
const exportBtn = document.getElementById('exportBtn');
|
||||||
|
const selectionCount = document.getElementById('selectionCount');
|
||||||
|
|
||||||
|
function updateSelection() {
|
||||||
|
const checked = document.querySelectorAll('.row-select:checked');
|
||||||
|
const count = checked.length;
|
||||||
|
selectionCount.textContent = count === 0 ? '0 valgt' : `${count} valgt`;
|
||||||
|
exportBtn.disabled = count === 0;
|
||||||
|
|
||||||
|
// Update select all state
|
||||||
|
selectAll.checked = count === rowCheckboxes.length && count > 0;
|
||||||
|
selectAll.indeterminate = count > 0 && count < rowCheckboxes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectAll.addEventListener('change', function() {
|
||||||
|
rowCheckboxes.forEach(cb => cb.checked = this.checked);
|
||||||
|
updateSelection();
|
||||||
|
});
|
||||||
|
|
||||||
|
rowCheckboxes.forEach(cb => {
|
||||||
|
cb.addEventListener('change', updateSelection);
|
||||||
|
// Stop click from bubbling to row
|
||||||
|
cb.addEventListener('click', e => e.stopPropagation());
|
||||||
|
});
|
||||||
|
|
||||||
|
// SAF-T Export
|
||||||
|
document.getElementById('exportBtn').addEventListener('click', function() {
|
||||||
|
const selected = document.querySelectorAll('.row-select:checked');
|
||||||
|
const ids = Array.from(selected).map(cb => cb.closest('swp-table-row').dataset.id);
|
||||||
|
// Generate demo SAF-T XML
|
||||||
|
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<AuditFile xmlns="urn:StandardAuditFile-Taxation-CashRegister:DK">
|
||||||
|
<Header>
|
||||||
|
<AuditFileVersion>1.30</AuditFileVersion>
|
||||||
|
<AuditFileCountry>DK</AuditFileCountry>
|
||||||
|
<AuditFileDateCreated>${today.toISOString().split('T')[0]}</AuditFileDateCreated>
|
||||||
|
<SoftwareCompanyName>Calendar Plantempus</SoftwareCompanyName>
|
||||||
|
<SoftwareID>SWP-POS</SoftwareID>
|
||||||
|
<SoftwareVersion>1.0</SoftwareVersion>
|
||||||
|
<Company>
|
||||||
|
<Name>Demo Salon ApS</Name>
|
||||||
|
<RegistrationNumber>12345678</RegistrationNumber>
|
||||||
|
</Company>
|
||||||
|
<DefaultCurrencyCode>DKK</DefaultCurrencyCode>
|
||||||
|
<SelectionCriteria>
|
||||||
|
<SelectionStartDate>${document.getElementById('dateFrom').value}</SelectionStartDate>
|
||||||
|
<SelectionEndDate>${document.getElementById('dateTo').value}</SelectionEndDate>
|
||||||
|
</SelectionCriteria>
|
||||||
|
</Header>
|
||||||
|
<CashRegisters>
|
||||||
|
<CashRegister>
|
||||||
|
<CashRegisterID>KASSE-001</CashRegisterID>
|
||||||
|
<CashRegisterLocation>Reception</CashRegisterLocation>
|
||||||
|
<Periods>
|
||||||
|
<Period>
|
||||||
|
<PeriodNumber>043</PeriodNumber>
|
||||||
|
<StartDateTime>2025-12-28T18:00:00</StartDateTime>
|
||||||
|
<EndDateTime>2025-12-29T17:45:00</EndDateTime>
|
||||||
|
<CashStatement>
|
||||||
|
<OpeningBalance>2000.00</OpeningBalance>
|
||||||
|
<ClosingBalance>5220.00</ClosingBalance>
|
||||||
|
<CashSales>3540.00</CashSales>
|
||||||
|
<CardSales>12875.50</CardSales>
|
||||||
|
<MobilePaySales>2450.00</MobilePaySales>
|
||||||
|
<TotalSales>18865.50</TotalSales>
|
||||||
|
<NumberOfTransactions>47</NumberOfTransactions>
|
||||||
|
<CashDifference>0.00</CashDifference>
|
||||||
|
</CashStatement>
|
||||||
|
<TaxSummary>
|
||||||
|
<TaxCode>S</TaxCode>
|
||||||
|
<TaxPercentage>25.00</TaxPercentage>
|
||||||
|
<TaxBase>15092.40</TaxBase>
|
||||||
|
<TaxAmount>3773.10</TaxAmount>
|
||||||
|
</TaxSummary>
|
||||||
|
</Period>
|
||||||
|
</Periods>
|
||||||
|
</CashRegister>
|
||||||
|
</CashRegisters>
|
||||||
|
</AuditFile>`;
|
||||||
|
|
||||||
|
// Download file
|
||||||
|
const blob = new Blob([xml], { type: 'application/xml' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `SAF-T_CashRegister_${document.getElementById('dateFrom').value}_${document.getElementById('dateTo').value}.xml`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
433
.workbench/POC/poc-konto.html
Normal file
|
|
@ -0,0 +1,433 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Abonnement & Konto - Salon OS</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/web@2.1.2/src/regular/style.css" />
|
||||||
|
<link rel="stylesheet" href="css/konto.css">
|
||||||
|
<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 {
|
||||||
|
--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: #f59e0b;
|
||||||
|
--color-purple: #8b5cf6;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode - system preference */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not(.light-mode) {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manual dark mode override */
|
||||||
|
:root.dark-mode {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
|
||||||
|
<!-- Page Header -->
|
||||||
|
<swp-page-header>
|
||||||
|
<swp-page-title>
|
||||||
|
<h1>Abonnement & Konto</h1>
|
||||||
|
<p>Administrer dit abonnement og betalingsinfo</p>
|
||||||
|
</swp-page-title>
|
||||||
|
</swp-page-header>
|
||||||
|
|
||||||
|
<!-- ==========================================
|
||||||
|
SUBSCRIPTION SECTION
|
||||||
|
========================================== -->
|
||||||
|
<swp-section>
|
||||||
|
<swp-section-header>
|
||||||
|
<swp-section-title>
|
||||||
|
<i class="ph ph-crown"></i>
|
||||||
|
Dit abonnement
|
||||||
|
</swp-section-title>
|
||||||
|
</swp-section-header>
|
||||||
|
|
||||||
|
<swp-plan-grid>
|
||||||
|
<!-- Basis Plan -->
|
||||||
|
<swp-plan-card>
|
||||||
|
<swp-plan-name>Basis</swp-plan-name>
|
||||||
|
<swp-plan-users>1-3 brugere</swp-plan-users>
|
||||||
|
<swp-plan-price>
|
||||||
|
<swp-plan-price-amount>299</swp-plan-price-amount>
|
||||||
|
<swp-plan-price-period>kr/md</swp-plan-price-period>
|
||||||
|
</swp-plan-price>
|
||||||
|
<swp-plan-features>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Op til 3 brugere
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Online booking
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Kalender & aftalestyring
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Kundekartotek
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
SMS-påmindelser
|
||||||
|
</swp-plan-feature>
|
||||||
|
</swp-plan-features>
|
||||||
|
<swp-plan-action>
|
||||||
|
<swp-btn class="secondary">Skift til Basis</swp-btn>
|
||||||
|
</swp-plan-action>
|
||||||
|
</swp-plan-card>
|
||||||
|
|
||||||
|
<!-- Pro Plan (Current) -->
|
||||||
|
<swp-plan-card class="current">
|
||||||
|
<swp-plan-badge class="current">
|
||||||
|
<i class="ph ph-check"></i>
|
||||||
|
Nuværende plan
|
||||||
|
</swp-plan-badge>
|
||||||
|
<swp-plan-name>Pro</swp-plan-name>
|
||||||
|
<swp-plan-users>4-8 brugere</swp-plan-users>
|
||||||
|
<swp-plan-price>
|
||||||
|
<swp-plan-price-amount>599</swp-plan-price-amount>
|
||||||
|
<swp-plan-price-period>kr/md</swp-plan-price-period>
|
||||||
|
</swp-plan-price>
|
||||||
|
<swp-plan-features>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Op til 8 brugere
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Alt fra Basis
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Lagerstyring
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Avancerede rapporter
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Gavekort & klippekort
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Prioriteret support
|
||||||
|
</swp-plan-feature>
|
||||||
|
</swp-plan-features>
|
||||||
|
<swp-plan-action>
|
||||||
|
<swp-btn class="secondary">Nuværende plan</swp-btn>
|
||||||
|
</swp-plan-action>
|
||||||
|
</swp-plan-card>
|
||||||
|
|
||||||
|
<!-- Enterprise Plan -->
|
||||||
|
<swp-plan-card class="enterprise">
|
||||||
|
<swp-plan-badge class="popular">
|
||||||
|
<i class="ph ph-star"></i>
|
||||||
|
Til større saloner
|
||||||
|
</swp-plan-badge>
|
||||||
|
<swp-plan-name>Enterprise</swp-plan-name>
|
||||||
|
<swp-plan-users>8+ brugere</swp-plan-users>
|
||||||
|
<swp-plan-price>
|
||||||
|
<swp-plan-price-amount>Kontakt os</swp-plan-price-amount>
|
||||||
|
</swp-plan-price>
|
||||||
|
<swp-plan-features>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Ubegrænset antal brugere
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Alt fra Pro
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Flere lokationer
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Tilpasset integration
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Dedikeret kontaktperson
|
||||||
|
</swp-plan-feature>
|
||||||
|
<swp-plan-feature>
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
SLA & uptime garanti
|
||||||
|
</swp-plan-feature>
|
||||||
|
</swp-plan-features>
|
||||||
|
<swp-plan-action>
|
||||||
|
<swp-btn class="outline">Kontakt salg</swp-btn>
|
||||||
|
</swp-plan-action>
|
||||||
|
</swp-plan-card>
|
||||||
|
</swp-plan-grid>
|
||||||
|
</swp-section>
|
||||||
|
|
||||||
|
<!-- ==========================================
|
||||||
|
BILLING SECTION
|
||||||
|
========================================== -->
|
||||||
|
<swp-section>
|
||||||
|
<swp-section-header>
|
||||||
|
<swp-section-title>
|
||||||
|
<i class="ph ph-credit-card"></i>
|
||||||
|
Betaling & Fakturaer
|
||||||
|
</swp-section-title>
|
||||||
|
</swp-section-header>
|
||||||
|
|
||||||
|
<swp-billing-grid>
|
||||||
|
<!-- Payment Info -->
|
||||||
|
<swp-payment-card>
|
||||||
|
<swp-payment-method>
|
||||||
|
<swp-payment-icon>
|
||||||
|
<i class="ph ph-credit-card"></i>
|
||||||
|
</swp-payment-icon>
|
||||||
|
<swp-payment-info>
|
||||||
|
<swp-payment-type>Visa</swp-payment-type>
|
||||||
|
<swp-payment-number>**** **** **** 4582</swp-payment-number>
|
||||||
|
</swp-payment-info>
|
||||||
|
<swp-btn class="secondary" style="padding: 8px 12px; font-size: 12px;">
|
||||||
|
<i class="ph ph-pencil"></i>
|
||||||
|
Skift
|
||||||
|
</swp-btn>
|
||||||
|
</swp-payment-method>
|
||||||
|
|
||||||
|
<swp-payment-detail>
|
||||||
|
<swp-payment-label>Betalingsfrekvens</swp-payment-label>
|
||||||
|
<swp-payment-value>Månedlig</swp-payment-value>
|
||||||
|
</swp-payment-detail>
|
||||||
|
|
||||||
|
<swp-payment-detail>
|
||||||
|
<swp-payment-label>Næste betaling</swp-payment-label>
|
||||||
|
<swp-payment-value class="highlight">1. januar 2026</swp-payment-value>
|
||||||
|
</swp-payment-detail>
|
||||||
|
|
||||||
|
<swp-payment-detail>
|
||||||
|
<swp-payment-label>Beløb</swp-payment-label>
|
||||||
|
<swp-payment-value>599,00 kr</swp-payment-value>
|
||||||
|
</swp-payment-detail>
|
||||||
|
|
||||||
|
<swp-payment-detail>
|
||||||
|
<swp-payment-label>Kortudløb</swp-payment-label>
|
||||||
|
<swp-payment-value>08/2027</swp-payment-value>
|
||||||
|
</swp-payment-detail>
|
||||||
|
|
||||||
|
<swp-btn class="outline" style="margin-top: 8px;">
|
||||||
|
<i class="ph ph-arrows-clockwise"></i>
|
||||||
|
Skift til årlig betaling (spar 15%)
|
||||||
|
</swp-btn>
|
||||||
|
</swp-payment-card>
|
||||||
|
|
||||||
|
<!-- Invoices -->
|
||||||
|
<swp-invoices-card>
|
||||||
|
<swp-invoices-header>
|
||||||
|
<swp-invoices-title>Faktura-historik</swp-invoices-title>
|
||||||
|
</swp-invoices-header>
|
||||||
|
|
||||||
|
<swp-table>
|
||||||
|
<swp-table-header>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>Dato</swp-table-cell>
|
||||||
|
<swp-table-cell>Fakturanr.</swp-table-cell>
|
||||||
|
<swp-table-cell>Beløb</swp-table-cell>
|
||||||
|
<swp-table-cell>Status</swp-table-cell>
|
||||||
|
<swp-table-cell></swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
</swp-table-header>
|
||||||
|
<swp-table-body>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>1. dec 2025</swp-table-cell>
|
||||||
|
<swp-table-cell style="font-family: var(--font-mono); font-size: 12px;">INV-2025-0012</swp-table-cell>
|
||||||
|
<swp-table-cell>599,00 kr</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-invoice-status class="paid">
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Betalt
|
||||||
|
</swp-invoice-status>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-download-btn>
|
||||||
|
<i class="ph ph-download"></i>
|
||||||
|
PDF
|
||||||
|
</swp-download-btn>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>1. nov 2025</swp-table-cell>
|
||||||
|
<swp-table-cell style="font-family: var(--font-mono); font-size: 12px;">INV-2025-0011</swp-table-cell>
|
||||||
|
<swp-table-cell>599,00 kr</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-invoice-status class="paid">
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Betalt
|
||||||
|
</swp-invoice-status>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-download-btn>
|
||||||
|
<i class="ph ph-download"></i>
|
||||||
|
PDF
|
||||||
|
</swp-download-btn>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>1. okt 2025</swp-table-cell>
|
||||||
|
<swp-table-cell style="font-family: var(--font-mono); font-size: 12px;">INV-2025-0010</swp-table-cell>
|
||||||
|
<swp-table-cell>599,00 kr</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-invoice-status class="paid">
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Betalt
|
||||||
|
</swp-invoice-status>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-download-btn>
|
||||||
|
<i class="ph ph-download"></i>
|
||||||
|
PDF
|
||||||
|
</swp-download-btn>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>1. sep 2025</swp-table-cell>
|
||||||
|
<swp-table-cell style="font-family: var(--font-mono); font-size: 12px;">INV-2025-0009</swp-table-cell>
|
||||||
|
<swp-table-cell>599,00 kr</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-invoice-status class="paid">
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Betalt
|
||||||
|
</swp-invoice-status>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-download-btn>
|
||||||
|
<i class="ph ph-download"></i>
|
||||||
|
PDF
|
||||||
|
</swp-download-btn>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>1. aug 2025</swp-table-cell>
|
||||||
|
<swp-table-cell style="font-family: var(--font-mono); font-size: 12px;">INV-2025-0008</swp-table-cell>
|
||||||
|
<swp-table-cell>599,00 kr</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-invoice-status class="paid">
|
||||||
|
<i class="ph ph-check-circle"></i>
|
||||||
|
Betalt
|
||||||
|
</swp-invoice-status>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-download-btn>
|
||||||
|
<i class="ph ph-download"></i>
|
||||||
|
PDF
|
||||||
|
</swp-download-btn>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
</swp-table-body>
|
||||||
|
</swp-table>
|
||||||
|
</swp-invoices-card>
|
||||||
|
</swp-billing-grid>
|
||||||
|
</swp-section>
|
||||||
|
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
2992
.workbench/POC/poc-layout.html
Normal file
1367
.workbench/POC/poc-leverandoer.html
Normal file
719
.workbench/POC/poc-leverandoerer.html
Normal file
|
|
@ -0,0 +1,719 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Leverandører - Backend</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 {
|
||||||
|
--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: #f59e0b;
|
||||||
|
--color-purple: #8b5cf6;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode - følger system preference ELLER manuel toggle */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not(.light-mode) {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manuel dark mode override */
|
||||||
|
:root.dark-mode {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-teal);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
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-page-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-topbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
BUTTONS
|
||||||
|
========================================== */
|
||||||
|
swp-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary {
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:hover {
|
||||||
|
background: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.icon-only {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.icon-only svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FILTER BAR
|
||||||
|
========================================== */
|
||||||
|
swp-filter-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-search-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-search-input img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not(.light-mode) swp-search-input img {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark-mode swp-search-input img {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-search-input input {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
width: 400px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATS BAR
|
||||||
|
========================================== */
|
||||||
|
swp-stats-bar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card swp-stat-value {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card swp-stat-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.highlight swp-stat-value {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.warning swp-stat-value {
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-table {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(200px, 1fr) 150px 80px 140px 80px 40px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header {
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 12px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
transition: background 150ms ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.mono {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.muted {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
SUPPLIER CELL
|
||||||
|
========================================== */
|
||||||
|
swp-supplier-cell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-supplier-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-supplier-city {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATUS BADGE
|
||||||
|
========================================== */
|
||||||
|
swp-status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.active {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, white);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.inactive {
|
||||||
|
background: color-mix(in srgb, var(--color-text-secondary) 15%, white);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ROW ARROW
|
||||||
|
========================================== */
|
||||||
|
swp-row-arrow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-row-arrow svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
fill: var(--color-text-secondary);
|
||||||
|
transition: transform 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:hover swp-row-arrow svg {
|
||||||
|
transform: translateX(4px);
|
||||||
|
fill: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABLE FOOTER
|
||||||
|
========================================== */
|
||||||
|
swp-table-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 20px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
RESPONSIVE
|
||||||
|
========================================== */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
swp-stats-bar {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
grid-template-columns: 1fr 80px 80px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th:nth-child(2),
|
||||||
|
swp-td:nth-child(2),
|
||||||
|
swp-th:nth-child(3),
|
||||||
|
swp-td:nth-child(3),
|
||||||
|
swp-th:nth-child(4),
|
||||||
|
swp-td:nth-child(4) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Topbar -->
|
||||||
|
<swp-topbar>
|
||||||
|
<swp-topbar-left>
|
||||||
|
<swp-page-title>Leverandører</swp-page-title>
|
||||||
|
</swp-topbar-left>
|
||||||
|
<swp-topbar-right>
|
||||||
|
<swp-btn class="secondary icon-only" id="themeToggle" title="Skift tema">
|
||||||
|
<svg id="sunIcon" viewBox="0 0 24 24"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/></svg>
|
||||||
|
<svg id="moonIcon" viewBox="0 0 24 24" style="display:none"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/></svg>
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||||
|
Ny leverandør
|
||||||
|
</swp-btn>
|
||||||
|
</swp-topbar-right>
|
||||||
|
</swp-topbar>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
<!-- Filter Bar -->
|
||||||
|
<swp-filter-bar>
|
||||||
|
<swp-search-input>
|
||||||
|
<img src="icons/search.svg" alt="Søg" />
|
||||||
|
<input type="search" id="searchInput" placeholder="Søg leverandør, kontaktperson..." />
|
||||||
|
</swp-search-input>
|
||||||
|
<swp-filter-spacer></swp-filter-spacer>
|
||||||
|
</swp-filter-bar>
|
||||||
|
|
||||||
|
<!-- Stats Bar -->
|
||||||
|
<swp-stats-bar>
|
||||||
|
<swp-stat-card class="highlight">
|
||||||
|
<swp-stat-value>12</swp-stat-value>
|
||||||
|
<swp-stat-label>Leverandører i alt</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>10</swp-stat-value>
|
||||||
|
<swp-stat-label>Aktive</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>45.230 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Indkøb denne måned</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="warning">
|
||||||
|
<swp-stat-value>3</swp-stat-value>
|
||||||
|
<swp-stat-label>Afventende ordrer</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
</swp-stats-bar>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<swp-table>
|
||||||
|
<swp-table-header>
|
||||||
|
<swp-th>Leverandør</swp-th>
|
||||||
|
<swp-th>Kontakt</swp-th>
|
||||||
|
<swp-th class="center">Produkter</swp-th>
|
||||||
|
<swp-th>Sidste ordre</swp-th>
|
||||||
|
<swp-th>Status</swp-th>
|
||||||
|
<swp-th></swp-th>
|
||||||
|
</swp-table-header>
|
||||||
|
<swp-table-body>
|
||||||
|
<swp-table-row data-id="1" onclick="location.href='poc-leverandoer.html'">
|
||||||
|
<swp-td>
|
||||||
|
<swp-supplier-cell>
|
||||||
|
<swp-supplier-name>Beauty Group Denmark</swp-supplier-name>
|
||||||
|
<swp-supplier-city>København</swp-supplier-city>
|
||||||
|
</swp-supplier-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Lars Hansen</swp-td>
|
||||||
|
<swp-td class="center mono">24</swp-td>
|
||||||
|
<swp-td class="muted">15. december 2024</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="2">
|
||||||
|
<swp-td>
|
||||||
|
<swp-supplier-cell>
|
||||||
|
<swp-supplier-name>Salon Supplies ApS</swp-supplier-name>
|
||||||
|
<swp-supplier-city>Aarhus</swp-supplier-city>
|
||||||
|
</swp-supplier-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Mette Nielsen</swp-td>
|
||||||
|
<swp-td class="center mono">18</swp-td>
|
||||||
|
<swp-td class="muted">22. december 2024</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="3">
|
||||||
|
<swp-td>
|
||||||
|
<swp-supplier-cell>
|
||||||
|
<swp-supplier-name>Pro Hair Distribution</swp-supplier-name>
|
||||||
|
<swp-supplier-city>Odense</swp-supplier-city>
|
||||||
|
</swp-supplier-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Anders Sørensen</swp-td>
|
||||||
|
<swp-td class="center mono">32</swp-td>
|
||||||
|
<swp-td class="muted">10. december 2024</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="4">
|
||||||
|
<swp-td>
|
||||||
|
<swp-supplier-cell>
|
||||||
|
<swp-supplier-name>Nordic Beauty Import</swp-supplier-name>
|
||||||
|
<swp-supplier-city>Aalborg</swp-supplier-city>
|
||||||
|
</swp-supplier-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Pia Kristensen</swp-td>
|
||||||
|
<swp-td class="center mono">15</swp-td>
|
||||||
|
<swp-td class="muted">28. november 2024</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="5">
|
||||||
|
<swp-td>
|
||||||
|
<swp-supplier-cell>
|
||||||
|
<swp-supplier-name>Color World A/S</swp-supplier-name>
|
||||||
|
<swp-supplier-city>Vejle</swp-supplier-city>
|
||||||
|
</swp-supplier-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Thomas Berg</swp-td>
|
||||||
|
<swp-td class="center mono">8</swp-td>
|
||||||
|
<swp-td class="muted">5. december 2024</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="inactive">Inaktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="6">
|
||||||
|
<swp-td>
|
||||||
|
<swp-supplier-cell>
|
||||||
|
<swp-supplier-name>Tools & More</swp-supplier-name>
|
||||||
|
<swp-supplier-city>Roskilde</swp-supplier-city>
|
||||||
|
</swp-supplier-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td>Karen Olsen</swp-td>
|
||||||
|
<swp-td class="center mono">12</swp-td>
|
||||||
|
<swp-td class="muted">18. december 2024</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
</swp-table-body>
|
||||||
|
<swp-table-footer>
|
||||||
|
<span>Viser 6 af 12 leverandører</span>
|
||||||
|
<span>Side 1 af 2</span>
|
||||||
|
</swp-table-footer>
|
||||||
|
</swp-table>
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/fuse.js@7.0.0"></script>
|
||||||
|
<script>
|
||||||
|
// Supplier data for search
|
||||||
|
const suppliers = [
|
||||||
|
{ id: 1, name: 'Beauty Group Denmark', contact: 'Lars Hansen', city: 'København' },
|
||||||
|
{ id: 2, name: 'Salon Supplies ApS', contact: 'Mette Nielsen', city: 'Aarhus' },
|
||||||
|
{ id: 3, name: 'Pro Hair Distribution', contact: 'Anders Sørensen', city: 'Odense' },
|
||||||
|
{ id: 4, name: 'Nordic Beauty Import', contact: 'Pia Kristensen', city: 'Aalborg' },
|
||||||
|
{ id: 5, name: 'Color World A/S', contact: 'Thomas Berg', city: 'Vejle' },
|
||||||
|
{ id: 6, name: 'Tools & More', contact: 'Karen Olsen', city: 'Roskilde' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Initialize Fuse.js
|
||||||
|
const fuse = new Fuse(suppliers, {
|
||||||
|
keys: ['name', 'contact', 'city'],
|
||||||
|
threshold: 0.3,
|
||||||
|
ignoreLocation: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchInput = document.getElementById('searchInput');
|
||||||
|
const tableBody = document.querySelector('swp-table-body');
|
||||||
|
const allRows = Array.from(tableBody.querySelectorAll('swp-table-row'));
|
||||||
|
|
||||||
|
// Search handler
|
||||||
|
searchInput.addEventListener('input', (e) => {
|
||||||
|
const query = e.target.value.trim();
|
||||||
|
|
||||||
|
if (query === '') {
|
||||||
|
// Show all rows
|
||||||
|
allRows.forEach(row => row.style.display = '');
|
||||||
|
} else {
|
||||||
|
// Search with Fuse.js
|
||||||
|
const results = fuse.search(query);
|
||||||
|
const matchedIds = results.map(r => r.item.id);
|
||||||
|
|
||||||
|
allRows.forEach(row => {
|
||||||
|
const rowId = parseInt(row.dataset.id);
|
||||||
|
row.style.display = matchedIds.includes(rowId) ? '' : 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Theme toggle
|
||||||
|
const themeToggle = document.getElementById('themeToggle');
|
||||||
|
const sunIcon = document.getElementById('sunIcon');
|
||||||
|
const moonIcon = document.getElementById('moonIcon');
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
function updateIcons() {
|
||||||
|
const isDark = root.classList.contains('dark-mode') ||
|
||||||
|
(window.matchMedia('(prefers-color-scheme: dark)').matches && !root.classList.contains('light-mode'));
|
||||||
|
sunIcon.style.display = isDark ? 'none' : 'block';
|
||||||
|
moonIcon.style.display = isDark ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIcons();
|
||||||
|
|
||||||
|
themeToggle.addEventListener('click', () => {
|
||||||
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
|
if (prefersDark) {
|
||||||
|
// System is dark - toggle to light or back to system
|
||||||
|
root.classList.toggle('light-mode');
|
||||||
|
root.classList.remove('dark-mode');
|
||||||
|
} else {
|
||||||
|
// System is light - toggle to dark or back to system
|
||||||
|
root.classList.toggle('dark-mode');
|
||||||
|
root.classList.remove('light-mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIcons();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1525
.workbench/POC/poc-loen-provision.html
Normal file
533
.workbench/POC/poc-loenspecifikation.html
Normal file
|
|
@ -0,0 +1,533 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Lønspecifikation – Januar 2026</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* ===== Print setup ===== */
|
||||||
|
@page { size: A4; margin: 14mm; }
|
||||||
|
@media print {
|
||||||
|
.no-print { display: none !important; }
|
||||||
|
.page-break { break-after: page; page-break-after: always; }
|
||||||
|
a { color: inherit; text-decoration: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Base ===== */
|
||||||
|
:root {
|
||||||
|
--ink: #0f172a;
|
||||||
|
--muted: #475569;
|
||||||
|
--line: #e2e8f0;
|
||||||
|
--soft: #f8fafc;
|
||||||
|
--accent: #0ea5e9;
|
||||||
|
--accent-2: #22c55e;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
* { box-sizing: border-box; }
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
|
||||||
|
color: var(--ink);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.sheet {
|
||||||
|
max-width: 210mm;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Header ===== */
|
||||||
|
.hdr {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 14px 0 10px;
|
||||||
|
border-bottom: 2px solid var(--line);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.brand {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: .2px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
.subtitle {
|
||||||
|
margin: 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.meta {
|
||||||
|
text-align: right;
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
.meta .pill {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: var(--soft);
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.meta .kv {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
gap: 4px 12px;
|
||||||
|
justify-content: end;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.meta .kv b { color: var(--ink); font-weight: 600; }
|
||||||
|
|
||||||
|
/* ===== Blocks ===== */
|
||||||
|
.card {
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.card .hd {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: linear-gradient(0deg, var(--soft), #fff);
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
.card .hd h2 {
|
||||||
|
font-size: 13px;
|
||||||
|
margin: 0;
|
||||||
|
letter-spacing: .2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.card .bd { padding: 12px; }
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1.2fr .8fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Total ===== */
|
||||||
|
.total {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
padding: 14px 14px;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: var(--soft);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.total .label {
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 12px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .25px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
.total .big {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 900;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
margin: 0;
|
||||||
|
line-height: 1.05;
|
||||||
|
}
|
||||||
|
.total .big small {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
.badge {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 11px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border-radius: 999px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: var(--soft);
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tables ===== */
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 8px 8px;
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
color: var(--muted);
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 11px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .2px;
|
||||||
|
background: var(--soft);
|
||||||
|
}
|
||||||
|
td.num, th.num { text-align: right; }
|
||||||
|
td.num { font-family: var(--font-mono); }
|
||||||
|
tr:last-child td { border-bottom: none; }
|
||||||
|
|
||||||
|
.note {
|
||||||
|
margin: 8px 0 0;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Footer ===== */
|
||||||
|
.ftr {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top: 1px solid var(--line);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 12px;
|
||||||
|
font-size: 10.5px;
|
||||||
|
color: var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Ensure content doesn't get split awkwardly ===== */
|
||||||
|
.avoid-break { break-inside: avoid; page-break-inside: avoid; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- ===================== PAGE 1: OVERBLIK ===================== -->
|
||||||
|
<div class="sheet">
|
||||||
|
<div class="hdr">
|
||||||
|
<div class="brand">
|
||||||
|
<p class="title">Lønspecifikation</p>
|
||||||
|
<p class="subtitle">Periode: <b>Januar 2026</b></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meta">
|
||||||
|
<div class="pill">Medarbejdernr.: <b>EMP-001</b></div>
|
||||||
|
<div class="kv">
|
||||||
|
<span>Medarbejder:</span><b>Emma Larsen</b>
|
||||||
|
<span>Afdeling:</span><b>Frisør</b>
|
||||||
|
<span>Ansættelse:</span><b>Fuldtid (37 t/uge)</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="total avoid-break">
|
||||||
|
<div>
|
||||||
|
<div class="label">Bruttoløn (Januar 2026)</div>
|
||||||
|
<p class="big">34.063,50 <small>kr</small></p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="grid">
|
||||||
|
<div class="card avoid-break">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Samlet lønopgørelse</h2>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Løndel</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Grundløn inkl. overarbejde</td>
|
||||||
|
<td class="num">29.322,50 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Provision i alt</td>
|
||||||
|
<td class="num">3.685,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tillæg i alt</td>
|
||||||
|
<td class="num">1.056,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Bruttoløn</b></td>
|
||||||
|
<td class="num"><b>34.063,50 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card avoid-break">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Saldi</h2>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Type</th>
|
||||||
|
<th class="num">Optjent</th>
|
||||||
|
<th class="num">Afholdt</th>
|
||||||
|
<th class="num">Rest</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Ferie (dage)</td>
|
||||||
|
<td class="num">18,5</td>
|
||||||
|
<td class="num">6,0</td>
|
||||||
|
<td class="num">12,5</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Afspadsering (timer)</td>
|
||||||
|
<td class="num">12,0</td>
|
||||||
|
<td class="num">4,0</td>
|
||||||
|
<td class="num">8,0</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">Saldi er opgjort som angivet på lønspecifikationen.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card avoid-break">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Hurtigt resumé</h2>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nøglepunkt</th>
|
||||||
|
<th class="num">Værdi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Normaltimer</td>
|
||||||
|
<td class="num">148,0 t</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Overarbejde</td>
|
||||||
|
<td class="num">7,0 t</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Provision (services + produkter)</td>
|
||||||
|
<td class="num">3.685,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tillæg (aften + lørdag + søndag)</td>
|
||||||
|
<td class="num">1.056,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="ftr">
|
||||||
|
<div>Overblik</div>
|
||||||
|
<div style="text-align:right">Lønspecifikation · Januar 2026</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-break"></div>
|
||||||
|
|
||||||
|
<!-- ===================== PAGE 2: DETALJER ===================== -->
|
||||||
|
<section class="card">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Arbejdstid pr. uge</h2>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Uge</th>
|
||||||
|
<th class="num">Normaltimer</th>
|
||||||
|
<th class="num">Overtid</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 1 (30. dec – 5. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">2,0 t</td>
|
||||||
|
<td class="num">7.400,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 2 (6. – 12. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">3,5 t</td>
|
||||||
|
<td class="num">7.816,25 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 3 (13. – 19. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">0,0 t</td>
|
||||||
|
<td class="num">6.845,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 4 (20. – 26. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">1,5 t</td>
|
||||||
|
<td class="num">7.261,25 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>I alt</b></td>
|
||||||
|
<td class="num"><b>148,0 t</b></td>
|
||||||
|
<td class="num"><b>7,0 t</b></td>
|
||||||
|
<td class="num"><b>29.322,50 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">
|
||||||
|
Satser: Normal 185,00 kr/time. Overtid (50%) 277,50 kr/time.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Provision</h2>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<p class="note" style="margin-top:0">
|
||||||
|
<b>Services:</b> 15% af omsætning over minimum (220 kr/time).<br/>
|
||||||
|
<b>Produkter:</b> 10% af salg.
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Uge</th>
|
||||||
|
<th class="num">Service prov.</th>
|
||||||
|
<th class="num">Produkt prov.</th>
|
||||||
|
<th class="num">I alt</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 1</td>
|
||||||
|
<td class="num">573,00 kr</td>
|
||||||
|
<td class="num">210,00 kr</td>
|
||||||
|
<td class="num">783,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 2</td>
|
||||||
|
<td class="num">883,50 kr</td>
|
||||||
|
<td class="num">320,00 kr</td>
|
||||||
|
<td class="num">1.203,50 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 3</td>
|
||||||
|
<td class="num">459,00 kr</td>
|
||||||
|
<td class="num">180,00 kr</td>
|
||||||
|
<td class="num">639,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 4</td>
|
||||||
|
<td class="num">769,50 kr</td>
|
||||||
|
<td class="num">290,00 kr</td>
|
||||||
|
<td class="num">1.059,50 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>I alt</b></td>
|
||||||
|
<td class="num"><b>2.685,00 kr</b></td>
|
||||||
|
<td class="num"><b>1.000,00 kr</b></td>
|
||||||
|
<td class="num"><b>3.685,00 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Tillæg & fravær</h2>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<div class="grid" style="grid-template-columns: 1fr 1fr;">
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Tillæg</th>
|
||||||
|
<th class="num">Timer</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Aftentillæg (hverdage 18–21)</td>
|
||||||
|
<td class="num">12,0</td>
|
||||||
|
<td class="num">336,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lørdagstillæg (før kl. 14)</td>
|
||||||
|
<td class="num">16,0</td>
|
||||||
|
<td class="num">720,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Søndagstillæg</td>
|
||||||
|
<td class="num">0,0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Tillæg i alt</b></td>
|
||||||
|
<td class="num"></td>
|
||||||
|
<td class="num"><b>1.056,00 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Fravær</th>
|
||||||
|
<th class="num">Dage</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Ferie med løn</td>
|
||||||
|
<td class="num">0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Sygdom</td>
|
||||||
|
<td class="num">0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Barns sygedag</td>
|
||||||
|
<td class="num">0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">Ingen fravær registreret i perioden.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="ftr">
|
||||||
|
<div>Detaljer</div>
|
||||||
|
<div style="text-align:right">Lønspecifikation · Januar 2026</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
588
.workbench/POC/poc-medarbejdere.html
Normal file
|
|
@ -0,0 +1,588 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Medarbejdere - Salon OS</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@phosphor-icons/web@2.1.2/src/regular/style.css" />
|
||||||
|
<link rel="stylesheet" href="css/konto.css">
|
||||||
|
<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 {
|
||||||
|
--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: #f59e0b;
|
||||||
|
--color-purple: #8b5cf6;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode - system preference */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not(.light-mode) {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manual dark mode override */
|
||||||
|
:root.dark-mode {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ROLE BADGES
|
||||||
|
========================================== */
|
||||||
|
swp-role-badge.leader {
|
||||||
|
background: color-mix(in srgb, var(--color-blue) 15%, transparent);
|
||||||
|
color: var(--color-blue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATS CARDS
|
||||||
|
========================================== */
|
||||||
|
swp-stats-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 12px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-value {
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-label {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.teal swp-stat-value {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.amber swp-stat-value {
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.purple swp-stat-value {
|
||||||
|
color: var(--color-purple);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABS
|
||||||
|
========================================== */
|
||||||
|
swp-tabs {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-tab {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 20px;
|
||||||
|
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-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-tab[data-active="true"] {
|
||||||
|
color: var(--color-teal);
|
||||||
|
border-bottom-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-tab i {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-tab-content {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-tab-content[data-active="true"] {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PERMISSIONS MATRIX
|
||||||
|
========================================== */
|
||||||
|
swp-permissions-matrix {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
swp-permissions-matrix table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
swp-permissions-matrix th,
|
||||||
|
swp-permissions-matrix td {
|
||||||
|
padding: 14px 16px;
|
||||||
|
text-align: center;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
swp-permissions-matrix th:first-child,
|
||||||
|
swp-permissions-matrix td:first-child {
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
swp-permissions-matrix thead th {
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
swp-permissions-matrix tbody tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
swp-permissions-matrix .permission-name {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
swp-permissions-matrix .permission-name i {
|
||||||
|
font-size: 18px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
swp-permissions-matrix .check {
|
||||||
|
color: var(--color-teal);
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
swp-permissions-matrix .no-access {
|
||||||
|
color: var(--color-border);
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
|
||||||
|
<!-- Page Header -->
|
||||||
|
<swp-page-header>
|
||||||
|
<swp-page-title>
|
||||||
|
<h1>Medarbejdere</h1>
|
||||||
|
<p>Administrer brugere, roller og rettigheder</p>
|
||||||
|
</swp-page-title>
|
||||||
|
</swp-page-header>
|
||||||
|
|
||||||
|
<!-- Stats Cards -->
|
||||||
|
<swp-stats-row>
|
||||||
|
<swp-stat-card class="teal">
|
||||||
|
<swp-stat-value>4</swp-stat-value>
|
||||||
|
<swp-stat-label>Aktive medarbejdere</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="amber">
|
||||||
|
<swp-stat-value>1</swp-stat-value>
|
||||||
|
<swp-stat-label>Afventer invitation</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="purple">
|
||||||
|
<swp-stat-value>4</swp-stat-value>
|
||||||
|
<swp-stat-label>Roller defineret</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
</swp-stats-row>
|
||||||
|
|
||||||
|
<!-- Tabs -->
|
||||||
|
<swp-tabs>
|
||||||
|
<swp-tab data-tab="brugere" data-active="true">
|
||||||
|
<i class="ph ph-users"></i>
|
||||||
|
Brugere
|
||||||
|
</swp-tab>
|
||||||
|
<swp-tab data-tab="roller">
|
||||||
|
<i class="ph ph-shield-check"></i>
|
||||||
|
Roller
|
||||||
|
</swp-tab>
|
||||||
|
</swp-tabs>
|
||||||
|
|
||||||
|
<!-- Tab: Brugere -->
|
||||||
|
<swp-tab-content data-tab="brugere" data-active="true">
|
||||||
|
<swp-users-header>
|
||||||
|
<swp-users-count>
|
||||||
|
<strong>5 af 8</strong> brugere
|
||||||
|
<swp-users-progress>
|
||||||
|
<swp-users-progress-bar style="width: 62.5%"></swp-users-progress-bar>
|
||||||
|
</swp-users-progress>
|
||||||
|
</swp-users-count>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<i class="ph ph-user-plus"></i>
|
||||||
|
Inviter bruger
|
||||||
|
</swp-btn>
|
||||||
|
</swp-users-header>
|
||||||
|
|
||||||
|
<swp-table-card>
|
||||||
|
<swp-table>
|
||||||
|
<swp-table-header>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>Bruger</swp-table-cell>
|
||||||
|
<swp-table-cell>Rolle</swp-table-cell>
|
||||||
|
<swp-table-cell>Status</swp-table-cell>
|
||||||
|
<swp-table-cell>Sidst aktiv</swp-table-cell>
|
||||||
|
<swp-table-cell></swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
</swp-table-header>
|
||||||
|
<swp-table-body>
|
||||||
|
<!-- User 1 - Owner -->
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-user-info>
|
||||||
|
<swp-user-avatar>MJ</swp-user-avatar>
|
||||||
|
<swp-user-details>
|
||||||
|
<swp-user-name>Maria Jensen</swp-user-name>
|
||||||
|
<swp-user-email>maria@salonbeauty.dk</swp-user-email>
|
||||||
|
</swp-user-details>
|
||||||
|
</swp-user-info>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-role-badge class="owner">Ejer</swp-role-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-status-badge class="active">
|
||||||
|
<swp-status-dot></swp-status-dot>
|
||||||
|
Aktiv
|
||||||
|
</swp-status-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>I dag, 14:32</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-table-actions>
|
||||||
|
<swp-icon-btn title="Rediger">
|
||||||
|
<i class="ph ph-pencil"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
</swp-table-actions>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<!-- User 2 - Admin -->
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-user-info>
|
||||||
|
<swp-user-avatar class="purple">AS</swp-user-avatar>
|
||||||
|
<swp-user-details>
|
||||||
|
<swp-user-name>Anna Sørensen</swp-user-name>
|
||||||
|
<swp-user-email>anna@salonbeauty.dk</swp-user-email>
|
||||||
|
</swp-user-details>
|
||||||
|
</swp-user-info>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-role-badge class="admin">Admin</swp-role-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-status-badge class="active">
|
||||||
|
<swp-status-dot></swp-status-dot>
|
||||||
|
Aktiv
|
||||||
|
</swp-status-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>I dag, 12:15</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-table-actions>
|
||||||
|
<swp-icon-btn title="Rediger">
|
||||||
|
<i class="ph ph-pencil"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
<swp-icon-btn class="danger" title="Fjern bruger">
|
||||||
|
<i class="ph ph-trash"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
</swp-table-actions>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<!-- User 3 - Leder -->
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-user-info>
|
||||||
|
<swp-user-avatar class="blue">LP</swp-user-avatar>
|
||||||
|
<swp-user-details>
|
||||||
|
<swp-user-name>Louise Pedersen</swp-user-name>
|
||||||
|
<swp-user-email>louise@salonbeauty.dk</swp-user-email>
|
||||||
|
</swp-user-details>
|
||||||
|
</swp-user-info>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-role-badge class="leader">Leder</swp-role-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-status-badge class="active">
|
||||||
|
<swp-status-dot></swp-status-dot>
|
||||||
|
Aktiv
|
||||||
|
</swp-status-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>I går, 17:45</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-table-actions>
|
||||||
|
<swp-icon-btn title="Rediger">
|
||||||
|
<i class="ph ph-pencil"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
<swp-icon-btn class="danger" title="Fjern bruger">
|
||||||
|
<i class="ph ph-trash"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
</swp-table-actions>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<!-- User 4 -->
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-user-info>
|
||||||
|
<swp-user-avatar class="amber">KN</swp-user-avatar>
|
||||||
|
<swp-user-details>
|
||||||
|
<swp-user-name>Katrine Nielsen</swp-user-name>
|
||||||
|
<swp-user-email>katrine@salonbeauty.dk</swp-user-email>
|
||||||
|
</swp-user-details>
|
||||||
|
</swp-user-info>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-role-badge>Medarbejder</swp-role-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-status-badge class="active">
|
||||||
|
<swp-status-dot></swp-status-dot>
|
||||||
|
Aktiv
|
||||||
|
</swp-status-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>27. dec, 09:30</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-table-actions>
|
||||||
|
<swp-icon-btn title="Rediger">
|
||||||
|
<i class="ph ph-pencil"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
<swp-icon-btn class="danger" title="Fjern bruger">
|
||||||
|
<i class="ph ph-trash"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
</swp-table-actions>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<!-- User 5 - Invited -->
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-user-info>
|
||||||
|
<swp-user-avatar class="purple">SH</swp-user-avatar>
|
||||||
|
<swp-user-details>
|
||||||
|
<swp-user-name>Sofie Hansen</swp-user-name>
|
||||||
|
<swp-user-email>sofie@salonbeauty.dk</swp-user-email>
|
||||||
|
</swp-user-details>
|
||||||
|
</swp-user-info>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-role-badge>Medarbejder</swp-role-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-status-badge class="invited">
|
||||||
|
<swp-status-dot></swp-status-dot>
|
||||||
|
Invitation sendt
|
||||||
|
</swp-status-badge>
|
||||||
|
</swp-table-cell>
|
||||||
|
<swp-table-cell>-</swp-table-cell>
|
||||||
|
<swp-table-cell>
|
||||||
|
<swp-table-actions>
|
||||||
|
<swp-icon-btn title="Send invitation igen">
|
||||||
|
<i class="ph ph-paper-plane-tilt"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
<swp-icon-btn class="danger" title="Annuller invitation">
|
||||||
|
<i class="ph ph-x"></i>
|
||||||
|
</swp-icon-btn>
|
||||||
|
</swp-table-actions>
|
||||||
|
</swp-table-cell>
|
||||||
|
</swp-table-row>
|
||||||
|
</swp-table-body>
|
||||||
|
</swp-table>
|
||||||
|
</swp-table-card>
|
||||||
|
</swp-tab-content>
|
||||||
|
|
||||||
|
<!-- Tab: Roller -->
|
||||||
|
<swp-tab-content data-tab="roller">
|
||||||
|
<swp-permissions-matrix>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Rettighed</th>
|
||||||
|
<th>Ejer</th>
|
||||||
|
<th>Admin</th>
|
||||||
|
<th>Leder</th>
|
||||||
|
<th>Medarbejder</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="permission-name">
|
||||||
|
<i class="ph ph-calendar"></i>
|
||||||
|
Kalender
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="permission-name">
|
||||||
|
<i class="ph ph-users"></i>
|
||||||
|
Medarbejdere
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-minus no-access"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="permission-name">
|
||||||
|
<i class="ph ph-address-book"></i>
|
||||||
|
Kunder
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<span class="permission-name">
|
||||||
|
<i class="ph ph-chart-bar"></i>
|
||||||
|
Rapporter & Økonomi
|
||||||
|
</span>
|
||||||
|
</td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-check-circle check"></i></td>
|
||||||
|
<td><i class="ph ph-minus no-access"></i></td>
|
||||||
|
<td><i class="ph ph-minus no-access"></i></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</swp-permissions-matrix>
|
||||||
|
</swp-tab-content>
|
||||||
|
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Simple tab switching
|
||||||
|
document.querySelectorAll('swp-tab').forEach(tab => {
|
||||||
|
tab.addEventListener('click', () => {
|
||||||
|
const tabName = tab.dataset.tab;
|
||||||
|
|
||||||
|
// Update tab active states
|
||||||
|
document.querySelectorAll('swp-tab').forEach(t => t.removeAttribute('data-active'));
|
||||||
|
tab.setAttribute('data-active', 'true');
|
||||||
|
|
||||||
|
// Update content active states
|
||||||
|
document.querySelectorAll('swp-tab-content').forEach(c => c.removeAttribute('data-active'));
|
||||||
|
document.querySelector(`swp-tab-content[data-tab="${tabName}"]`).setAttribute('data-active', 'true');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1458
.workbench/POC/poc-produkt-opret.html
Normal file
1251
.workbench/POC/poc-produkt.html
Normal file
818
.workbench/POC/poc-produkter.html
Normal file
|
|
@ -0,0 +1,818 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Produkter - Backend</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 {
|
||||||
|
--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: #f59e0b;
|
||||||
|
--color-purple: #8b5cf6;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
--font-mono: 'JetBrains Mono', monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode - følger system preference ELLER manuel toggle */
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not(.light-mode) {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manuel dark mode override */
|
||||||
|
:root.dark-mode {
|
||||||
|
--color-surface: #1e1e1e;
|
||||||
|
--color-background: #121212;
|
||||||
|
--color-background-hover: #2a2a2a;
|
||||||
|
--color-background-alt: #1a1a1a;
|
||||||
|
--color-border: #333;
|
||||||
|
--color-text: #e0e0e0;
|
||||||
|
--color-text-secondary: #999;
|
||||||
|
--color-teal: #26a69a;
|
||||||
|
--color-blue: #42a5f5;
|
||||||
|
--color-red: #ef5350;
|
||||||
|
--color-amber: #ffb74d;
|
||||||
|
--color-purple: #a78bfa;
|
||||||
|
--color-green: #66bb6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-teal);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
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-page-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-topbar-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
BUTTONS
|
||||||
|
========================================== */
|
||||||
|
swp-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 10px 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn svg {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary {
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.primary:hover {
|
||||||
|
background: #00796b;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.secondary:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.icon-only {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-btn.icon-only svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FILTER BAR
|
||||||
|
========================================== */
|
||||||
|
swp-filter-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-group {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-label {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-bar input,
|
||||||
|
swp-filter-bar select {
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-bar input:focus,
|
||||||
|
swp-filter-bar select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-search-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-search-input img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root:not(.light-mode) swp-search-input img {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:root.dark-mode swp-search-input img {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-search-input input {
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
font-size: 13px;
|
||||||
|
font-family: var(--font-family);
|
||||||
|
width: 400px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-filter-spacer {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATS BAR
|
||||||
|
========================================== */
|
||||||
|
swp-stats-bar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card swp-stat-value {
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card swp-stat-label {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.highlight swp-stat-value {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.warning swp-stat-value {
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-table {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: minmax(200px, 1fr) 100px 100px 100px 80px 90px 80px 40px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header {
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 12px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
transition: background 150ms ease;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td {
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.right {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.mono {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.muted {
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
PRODUCT NAME CELL
|
||||||
|
========================================== */
|
||||||
|
swp-product-cell {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-product-name {
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-product-brand {
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STOCK INDICATOR
|
||||||
|
========================================== */
|
||||||
|
swp-stock-indicator {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stock-indicator::before {
|
||||||
|
content: '';
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stock-indicator.warning::before {
|
||||||
|
background: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stock-indicator.critical::before {
|
||||||
|
background: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATUS BADGE
|
||||||
|
========================================== */
|
||||||
|
swp-status-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 4px 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.active {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, white);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-status-badge.inactive {
|
||||||
|
background: color-mix(in srgb, var(--color-text-secondary) 15%, white);
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
ROW ARROW
|
||||||
|
========================================== */
|
||||||
|
swp-row-arrow {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-row-arrow svg {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
fill: var(--color-text-secondary);
|
||||||
|
transition: transform 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:hover swp-row-arrow svg {
|
||||||
|
transform: translateX(4px);
|
||||||
|
fill: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
TABLE FOOTER
|
||||||
|
========================================== */
|
||||||
|
swp-table-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 20px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
RESPONSIVE
|
||||||
|
========================================== */
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
swp-stats-bar {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 900px) {
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
grid-template-columns: 1fr 80px 80px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th:nth-child(2),
|
||||||
|
swp-td:nth-child(2),
|
||||||
|
swp-th:nth-child(3),
|
||||||
|
swp-td:nth-child(3),
|
||||||
|
swp-th:nth-child(4),
|
||||||
|
swp-td:nth-child(4) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- Topbar -->
|
||||||
|
<swp-topbar>
|
||||||
|
<swp-topbar-left>
|
||||||
|
<swp-page-title>Produkter</swp-page-title>
|
||||||
|
</swp-topbar-left>
|
||||||
|
<swp-topbar-right>
|
||||||
|
<swp-btn class="secondary icon-only" id="themeToggle" title="Skift tema">
|
||||||
|
<svg id="sunIcon" viewBox="0 0 24 24"><path d="M12 7c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zM2 13h2c.55 0 1-.45 1-1s-.45-1-1-1H2c-.55 0-1 .45-1 1s.45 1 1 1zm18 0h2c.55 0 1-.45 1-1s-.45-1-1-1h-2c-.55 0-1 .45-1 1s.45 1 1 1zM11 2v2c0 .55.45 1 1 1s1-.45 1-1V2c0-.55-.45-1-1-1s-1 .45-1 1zm0 18v2c0 .55.45 1 1 1s1-.45 1-1v-2c0-.55-.45-1-1-1s-1 .45-1 1zM5.99 4.58c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0s.39-1.03 0-1.41L5.99 4.58zm12.37 12.37c-.39-.39-1.03-.39-1.41 0-.39.39-.39 1.03 0 1.41l1.06 1.06c.39.39 1.03.39 1.41 0 .39-.39.39-1.03 0-1.41l-1.06-1.06zm1.06-10.96c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06zM7.05 18.36c.39-.39.39-1.03 0-1.41-.39-.39-1.03-.39-1.41 0l-1.06 1.06c-.39.39-.39 1.03 0 1.41s1.03.39 1.41 0l1.06-1.06z"/></svg>
|
||||||
|
<svg id="moonIcon" viewBox="0 0 24 24" style="display:none"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9 9-4.03 9-9c0-.46-.04-.92-.1-1.36-.98 1.37-2.58 2.26-4.4 2.26-2.98 0-5.4-2.42-5.4-5.4 0-1.81.89-3.42 2.26-4.4-.44-.06-.9-.1-1.36-.1z"/></svg>
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="secondary">
|
||||||
|
<svg viewBox="0 0 24 24"><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z"/></svg>
|
||||||
|
Importer
|
||||||
|
</swp-btn>
|
||||||
|
<swp-btn class="primary">
|
||||||
|
<svg viewBox="0 0 24 24"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>
|
||||||
|
Nyt produkt
|
||||||
|
</swp-btn>
|
||||||
|
</swp-topbar-right>
|
||||||
|
</swp-topbar>
|
||||||
|
|
||||||
|
<swp-page-container>
|
||||||
|
<!-- Filter Bar -->
|
||||||
|
<swp-filter-bar>
|
||||||
|
<swp-search-input>
|
||||||
|
<img src="icons/search.svg" alt="Søg" />
|
||||||
|
<input type="search" id="searchInput" placeholder="Søg produkt, varenr, brand..." />
|
||||||
|
</swp-search-input>
|
||||||
|
<swp-filter-spacer></swp-filter-spacer>
|
||||||
|
</swp-filter-bar>
|
||||||
|
|
||||||
|
<!-- Stats Bar -->
|
||||||
|
<swp-stats-bar>
|
||||||
|
<swp-stat-card class="highlight">
|
||||||
|
<swp-stat-value>47</swp-stat-value>
|
||||||
|
<swp-stat-label>Produkter i alt</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>142.850 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Samlet lagerværdi</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="warning">
|
||||||
|
<swp-stat-value>5</swp-stat-value>
|
||||||
|
<swp-stat-label>Lavt lager</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>12.450 kr</swp-stat-value>
|
||||||
|
<swp-stat-label>Salg denne måned</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
</swp-stats-bar>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<swp-table>
|
||||||
|
<swp-table-header>
|
||||||
|
<swp-th>Produkt</swp-th>
|
||||||
|
<swp-th>Varenr</swp-th>
|
||||||
|
<swp-th>Kategori</swp-th>
|
||||||
|
<swp-th>Brand</swp-th>
|
||||||
|
<swp-th class="right">Lager</swp-th>
|
||||||
|
<swp-th class="right">Pris</swp-th>
|
||||||
|
<swp-th>Status</swp-th>
|
||||||
|
<swp-th></swp-th>
|
||||||
|
</swp-table-header>
|
||||||
|
<swp-table-body>
|
||||||
|
<swp-table-row data-id="1" onclick="location.href='poc-produkt.html'">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>Acidic Bonding Concentrate Serum 100ml</swp-product-name>
|
||||||
|
<swp-product-brand>Redken</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">RDK-ABC-100</swp-td>
|
||||||
|
<swp-td>Hårpleje</swp-td>
|
||||||
|
<swp-td>Redken</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator>10</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">379 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="2">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>No. 3 Hair Perfector 100ml</swp-product-name>
|
||||||
|
<swp-product-brand>Olaplex</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">OLP-003</swp-td>
|
||||||
|
<swp-td>Hårpleje</swp-td>
|
||||||
|
<swp-td>Olaplex</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator class="warning">3</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">349 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="3">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>Elixir Ultime L'Huile Originale 100ml</swp-product-name>
|
||||||
|
<swp-product-brand>Kérastase</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">KER-ELX-100</swp-td>
|
||||||
|
<swp-td>Hårpleje</swp-td>
|
||||||
|
<swp-td>Kérastase</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator>8</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">459 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="4">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>EIMI Ocean Spritz 150ml</swp-product-name>
|
||||||
|
<swp-product-brand>Wella</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">WEL-OCN-150</swp-td>
|
||||||
|
<swp-td>Styling</swp-td>
|
||||||
|
<swp-td>Wella</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator>15</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">169 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="5">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>No. 4 Bond Maintenance Shampoo 250ml</swp-product-name>
|
||||||
|
<swp-product-brand>Olaplex</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">OLP-004-250</swp-td>
|
||||||
|
<swp-td>Hårpleje</swp-td>
|
||||||
|
<swp-td>Olaplex</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator class="critical">0</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">299 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="6">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>IGORA Royal 6-0 60ml</swp-product-name>
|
||||||
|
<swp-product-brand>Schwarzkopf</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">SCH-IGR-60</swp-td>
|
||||||
|
<swp-td>Farve</swp-td>
|
||||||
|
<swp-td>Schwarzkopf</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator>24</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">89 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="7">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>All Soft Shampoo 300ml</swp-product-name>
|
||||||
|
<swp-product-brand>Redken</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">RDK-ALS-300</swp-td>
|
||||||
|
<swp-td>Hårpleje</swp-td>
|
||||||
|
<swp-td>Redken</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator class="warning">4</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">249 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="active">Aktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
<swp-table-row data-id="8">
|
||||||
|
<swp-td>
|
||||||
|
<swp-product-cell>
|
||||||
|
<swp-product-name>Paddle Brush Large</swp-product-name>
|
||||||
|
<swp-product-brand>Denman</swp-product-brand>
|
||||||
|
</swp-product-cell>
|
||||||
|
</swp-td>
|
||||||
|
<swp-td class="mono muted">DNM-PBL-01</swp-td>
|
||||||
|
<swp-td>Tilbehør</swp-td>
|
||||||
|
<swp-td>Denman</swp-td>
|
||||||
|
<swp-td class="right"><swp-stock-indicator>7</swp-stock-indicator></swp-td>
|
||||||
|
<swp-td class="right mono">189 kr</swp-td>
|
||||||
|
<swp-td><swp-status-badge class="inactive">Inaktiv</swp-status-badge></swp-td>
|
||||||
|
<swp-td><swp-row-arrow><svg viewBox="0 0 24 24"><path d="M8.59 16.59L13.17 12 8.59 7.41 10 6l6 6-6 6-1.41-1.41z"/></svg></swp-row-arrow></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
|
||||||
|
</swp-table-body>
|
||||||
|
<swp-table-footer>
|
||||||
|
<span>Viser 8 af 47 produkter</span>
|
||||||
|
<span>Side 1 af 6</span>
|
||||||
|
</swp-table-footer>
|
||||||
|
</swp-table>
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/fuse.js@7.0.0"></script>
|
||||||
|
<script>
|
||||||
|
// Product data for search
|
||||||
|
const products = [
|
||||||
|
{ id: 1, name: 'Acidic Bonding Concentrate Serum 100ml', brand: 'Redken', sku: 'RDK-ABC-100', category: 'Hårpleje' },
|
||||||
|
{ id: 2, name: 'No. 3 Hair Perfector 100ml', brand: 'Olaplex', sku: 'OLP-003', category: 'Hårpleje' },
|
||||||
|
{ id: 3, name: 'Elixir Ultime L\'Huile Originale 100ml', brand: 'Kérastase', sku: 'KER-ELX-100', category: 'Hårpleje' },
|
||||||
|
{ id: 4, name: 'EIMI Ocean Spritz 150ml', brand: 'Wella', sku: 'WEL-OCN-150', category: 'Styling' },
|
||||||
|
{ id: 5, name: 'No. 4 Bond Maintenance Shampoo 250ml', brand: 'Olaplex', sku: 'OLP-004-250', category: 'Hårpleje' },
|
||||||
|
{ id: 6, name: 'IGORA Royal 6-0 60ml', brand: 'Schwarzkopf', sku: 'SCH-IGR-60', category: 'Farve' },
|
||||||
|
{ id: 7, name: 'All Soft Shampoo 300ml', brand: 'Redken', sku: 'RDK-ALS-300', category: 'Hårpleje' },
|
||||||
|
{ id: 8, name: 'Paddle Brush Large', brand: 'Denman', sku: 'DNM-PBL-01', category: 'Tilbehør' }
|
||||||
|
];
|
||||||
|
|
||||||
|
// Initialize Fuse.js
|
||||||
|
const fuse = new Fuse(products, {
|
||||||
|
keys: ['name', 'brand', 'sku', 'category'],
|
||||||
|
threshold: 0.3,
|
||||||
|
ignoreLocation: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const searchInput = document.getElementById('searchInput');
|
||||||
|
const tableBody = document.querySelector('swp-table-body');
|
||||||
|
const allRows = Array.from(tableBody.querySelectorAll('swp-table-row'));
|
||||||
|
|
||||||
|
// Search handler
|
||||||
|
searchInput.addEventListener('input', (e) => {
|
||||||
|
const query = e.target.value.trim();
|
||||||
|
|
||||||
|
if (query === '') {
|
||||||
|
// Show all rows
|
||||||
|
allRows.forEach(row => row.style.display = '');
|
||||||
|
} else {
|
||||||
|
// Search with Fuse.js
|
||||||
|
const results = fuse.search(query);
|
||||||
|
const matchedIds = results.map(r => r.item.id);
|
||||||
|
|
||||||
|
allRows.forEach(row => {
|
||||||
|
const rowId = parseInt(row.dataset.id);
|
||||||
|
row.style.display = matchedIds.includes(rowId) ? '' : 'none';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Theme toggle
|
||||||
|
const themeToggle = document.getElementById('themeToggle');
|
||||||
|
const sunIcon = document.getElementById('sunIcon');
|
||||||
|
const moonIcon = document.getElementById('moonIcon');
|
||||||
|
const root = document.documentElement;
|
||||||
|
|
||||||
|
function updateIcons() {
|
||||||
|
const isDark = root.classList.contains('dark-mode') ||
|
||||||
|
(window.matchMedia('(prefers-color-scheme: dark)').matches && !root.classList.contains('light-mode'));
|
||||||
|
sunIcon.style.display = isDark ? 'none' : 'block';
|
||||||
|
moonIcon.style.display = isDark ? 'block' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIcons();
|
||||||
|
|
||||||
|
themeToggle.addEventListener('click', () => {
|
||||||
|
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
|
||||||
|
if (prefersDark) {
|
||||||
|
// System is dark - toggle to light or back to system
|
||||||
|
root.classList.toggle('light-mode');
|
||||||
|
root.classList.remove('dark-mode');
|
||||||
|
} else {
|
||||||
|
// System is light - toggle to dark or back to system
|
||||||
|
root.classList.toggle('dark-mode');
|
||||||
|
root.classList.remove('light-mode');
|
||||||
|
}
|
||||||
|
|
||||||
|
updateIcons();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
615
.workbench/POC/poc-rapport.html
Normal file
|
|
@ -0,0 +1,615 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Rapport - POC</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 {
|
||||||
|
--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-purple: #8b5cf6;
|
||||||
|
--color-amber: #f59e0b;
|
||||||
|
--color-red: #e53935;
|
||||||
|
--color-green: #43a047;
|
||||||
|
--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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
LAYOUT
|
||||||
|
========================================== */
|
||||||
|
swp-page-container {
|
||||||
|
display: block;
|
||||||
|
max-width: 1400px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
HEADER
|
||||||
|
========================================== */
|
||||||
|
swp-page-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-page-title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FILTERS
|
||||||
|
========================================== */
|
||||||
|
swp-report-filters {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-selector {
|
||||||
|
display: flex;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 4px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-selector button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-selector button:hover {
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-period-selector button.active {
|
||||||
|
background: var(--color-teal);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-employee-filter select {
|
||||||
|
padding: 10px 32px 10px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
border: 1px solid var(--color-border);
|
||||||
|
border-radius: 6px;
|
||||||
|
background: var(--color-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%23666' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 10px center;
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
min-width: 180px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
STATS BAR
|
||||||
|
========================================== */
|
||||||
|
swp-stats-bar {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-value {
|
||||||
|
display: block;
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
margin-top: 4px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-stat-card.teal swp-stat-value { color: var(--color-teal); }
|
||||||
|
swp-stat-card.red swp-stat-value { color: var(--color-red); }
|
||||||
|
swp-stat-card.amber swp-stat-value { color: var(--color-amber); }
|
||||||
|
swp-stat-card.purple swp-stat-value { color: var(--color-purple); }
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
CHARTS GRID
|
||||||
|
========================================== */
|
||||||
|
swp-charts-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 1fr;
|
||||||
|
gap: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-chart-card {
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 20px 24px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-chart-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--color-text);
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-chart-container {
|
||||||
|
display: block;
|
||||||
|
height: 240px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
REPORT TABLE
|
||||||
|
========================================== */
|
||||||
|
swp-report-table {
|
||||||
|
display: block;
|
||||||
|
background: var(--color-surface);
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header,
|
||||||
|
swp-table-row {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 200px repeat(7, 1fr);
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-header {
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
padding: 14px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th {
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.sortable {
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
transition: color 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.sortable:hover {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.sorted {
|
||||||
|
color: var(--color-teal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sort-icon {
|
||||||
|
font-size: 10px;
|
||||||
|
opacity: 0.4;
|
||||||
|
transition: opacity 150ms ease, transform 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.sorted .sort-icon {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.sorted.desc .sort-icon {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-th.right,
|
||||||
|
swp-td.right {
|
||||||
|
text-align: right;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-body {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row {
|
||||||
|
padding: 14px 20px;
|
||||||
|
border-bottom: 1px solid var(--color-border);
|
||||||
|
transition: background 150ms ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-table-row:hover {
|
||||||
|
background: var(--color-background-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td {
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.name {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.number {
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-td.red { color: var(--color-red); }
|
||||||
|
swp-td.amber { color: var(--color-amber); }
|
||||||
|
swp-td.purple { color: var(--color-purple); }
|
||||||
|
|
||||||
|
swp-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-badge.low {
|
||||||
|
background: color-mix(in srgb, var(--color-green) 15%, white);
|
||||||
|
color: var(--color-green);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-badge.medium {
|
||||||
|
background: color-mix(in srgb, var(--color-amber) 15%, white);
|
||||||
|
color: var(--color-amber);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-badge.high {
|
||||||
|
background: color-mix(in srgb, var(--color-red) 15%, white);
|
||||||
|
color: var(--color-red);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================
|
||||||
|
FOOTER
|
||||||
|
========================================== */
|
||||||
|
swp-table-footer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14px 20px;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
border-top: 1px solid var(--color-border);
|
||||||
|
font-size: 13px;
|
||||||
|
color: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<swp-page-container>
|
||||||
|
<!-- Header -->
|
||||||
|
<swp-page-header>
|
||||||
|
<swp-page-title>Rapport</swp-page-title>
|
||||||
|
<swp-report-filters>
|
||||||
|
<swp-period-selector>
|
||||||
|
<button>Uge</button>
|
||||||
|
<button class="active">Måned</button>
|
||||||
|
<button>Kvartal</button>
|
||||||
|
<button>År</button>
|
||||||
|
</swp-period-selector>
|
||||||
|
<swp-employee-filter>
|
||||||
|
<select>
|
||||||
|
<option>Alle medarbejdere</option>
|
||||||
|
<option>Anna Jensen</option>
|
||||||
|
<option>Martin Nielsen</option>
|
||||||
|
<option>Sofie Larsen</option>
|
||||||
|
<option>Peter Hansen</option>
|
||||||
|
</select>
|
||||||
|
</swp-employee-filter>
|
||||||
|
</swp-report-filters>
|
||||||
|
</swp-page-header>
|
||||||
|
|
||||||
|
<!-- Stats Bar -->
|
||||||
|
<swp-stats-bar>
|
||||||
|
<swp-stat-card class="teal">
|
||||||
|
<swp-stat-value>320 t</swp-stat-value>
|
||||||
|
<swp-stat-label>Planlagte timer</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="red">
|
||||||
|
<swp-stat-value>24 t</swp-stat-value>
|
||||||
|
<swp-stat-label>Fravær total</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card class="amber">
|
||||||
|
<swp-stat-value>8 t</swp-stat-value>
|
||||||
|
<swp-stat-label>Overarbejde</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
<swp-stat-card>
|
||||||
|
<swp-stat-value>7.5%</swp-stat-value>
|
||||||
|
<swp-stat-label>Fraværsprocent</swp-stat-label>
|
||||||
|
</swp-stat-card>
|
||||||
|
</swp-stats-bar>
|
||||||
|
|
||||||
|
<!-- Charts -->
|
||||||
|
<swp-charts-grid>
|
||||||
|
<swp-chart-card>
|
||||||
|
<swp-chart-title>Timer pr. uge</swp-chart-title>
|
||||||
|
<swp-chart-container id="hoursChart"></swp-chart-container>
|
||||||
|
</swp-chart-card>
|
||||||
|
|
||||||
|
<swp-chart-card>
|
||||||
|
<swp-chart-title>Fraværsfordeling</swp-chart-title>
|
||||||
|
<swp-chart-container id="absenceChart"></swp-chart-container>
|
||||||
|
</swp-chart-card>
|
||||||
|
</swp-charts-grid>
|
||||||
|
|
||||||
|
<!-- Table -->
|
||||||
|
<swp-report-table>
|
||||||
|
<swp-table-header>
|
||||||
|
<swp-th class="sortable sorted">Medarbejder <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Planlagt <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Fravær <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Syg <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Ferie <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Fri <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Overarbejde <span class="sort-icon">▲</span></swp-th>
|
||||||
|
<swp-th class="sortable right">Fraværs-% <span class="sort-icon">▲</span></swp-th>
|
||||||
|
</swp-table-header>
|
||||||
|
<swp-table-body>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-td class="name">Anna Jensen</swp-td>
|
||||||
|
<swp-td class="number right">80 t</swp-td>
|
||||||
|
<swp-td class="number right">4 t</swp-td>
|
||||||
|
<swp-td class="number right red">0 t</swp-td>
|
||||||
|
<swp-td class="number right amber">4 t</swp-td>
|
||||||
|
<swp-td class="number right purple">0 t</swp-td>
|
||||||
|
<swp-td class="number right">2 t</swp-td>
|
||||||
|
<swp-td class="right"><swp-badge class="low">5.0%</swp-badge></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-td class="name">Martin Nielsen</swp-td>
|
||||||
|
<swp-td class="number right">80 t</swp-td>
|
||||||
|
<swp-td class="number right">8 t</swp-td>
|
||||||
|
<swp-td class="number right red">8 t</swp-td>
|
||||||
|
<swp-td class="number right amber">0 t</swp-td>
|
||||||
|
<swp-td class="number right purple">0 t</swp-td>
|
||||||
|
<swp-td class="number right">0 t</swp-td>
|
||||||
|
<swp-td class="right"><swp-badge class="medium">10.0%</swp-badge></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-td class="name">Sofie Larsen</swp-td>
|
||||||
|
<swp-td class="number right">80 t</swp-td>
|
||||||
|
<swp-td class="number right">4 t</swp-td>
|
||||||
|
<swp-td class="number right red">0 t</swp-td>
|
||||||
|
<swp-td class="number right amber">0 t</swp-td>
|
||||||
|
<swp-td class="number right purple">4 t</swp-td>
|
||||||
|
<swp-td class="number right">4 t</swp-td>
|
||||||
|
<swp-td class="right"><swp-badge class="low">5.0%</swp-badge></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
<swp-table-row>
|
||||||
|
<swp-td class="name">Peter Hansen</swp-td>
|
||||||
|
<swp-td class="number right">80 t</swp-td>
|
||||||
|
<swp-td class="number right">8 t</swp-td>
|
||||||
|
<swp-td class="number right red">4 t</swp-td>
|
||||||
|
<swp-td class="number right amber">4 t</swp-td>
|
||||||
|
<swp-td class="number right purple">0 t</swp-td>
|
||||||
|
<swp-td class="number right">2 t</swp-td>
|
||||||
|
<swp-td class="right"><swp-badge class="medium">10.0%</swp-badge></swp-td>
|
||||||
|
</swp-table-row>
|
||||||
|
</swp-table-body>
|
||||||
|
<swp-table-footer>
|
||||||
|
<span>Viser 4 medarbejdere</span>
|
||||||
|
<span>Total: 320 t planlagt, 24 t fravær, 8 t overarbejde</span>
|
||||||
|
</swp-table-footer>
|
||||||
|
</swp-report-table>
|
||||||
|
</swp-page-container>
|
||||||
|
|
||||||
|
<script type="module">
|
||||||
|
// Import charting library
|
||||||
|
import { createChart } from 'https://unpkg.com/@sevenweirdpeople/swp-charting@latest/dist/index.js';
|
||||||
|
|
||||||
|
// Initialize pie chart with breakdown
|
||||||
|
createChart(document.getElementById('absenceChart'), {
|
||||||
|
height: 240,
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Syg',
|
||||||
|
color: '#e53935',
|
||||||
|
type: 'pie',
|
||||||
|
unit: 't',
|
||||||
|
data: [
|
||||||
|
{ x: 'Martin Nielsen', y: 8 },
|
||||||
|
{ x: 'Peter Hansen', y: 4 },
|
||||||
|
],
|
||||||
|
pie: { innerRadius: 25, outerRadius: 100 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Ferie',
|
||||||
|
color: '#f59e0b',
|
||||||
|
type: 'pie',
|
||||||
|
unit: 't',
|
||||||
|
data: [
|
||||||
|
{ x: 'Anna Jensen', y: 4 },
|
||||||
|
{ x: 'Peter Hansen', y: 4 },
|
||||||
|
],
|
||||||
|
pie: { innerRadius: 25, outerRadius: 100 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Fri',
|
||||||
|
color: '#8b5cf6',
|
||||||
|
type: 'pie',
|
||||||
|
unit: 't',
|
||||||
|
data: [
|
||||||
|
{ x: 'Sofie Larsen', y: 4 },
|
||||||
|
],
|
||||||
|
pie: { innerRadius: 25, outerRadius: 100 }
|
||||||
|
}
|
||||||
|
],
|
||||||
|
legend: { position: 'right', align: 'center' }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize grouped bar chart
|
||||||
|
createChart(document.getElementById('hoursChart'), {
|
||||||
|
xAxis: { categories: ['Uge 48', 'Uge 49', 'Uge 50', 'Uge 51', 'Uge 52'] },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'Anna Jensen',
|
||||||
|
color: '#00897b',
|
||||||
|
type: 'bar',
|
||||||
|
data: [
|
||||||
|
{ x: 'Uge 48', y: 32 },
|
||||||
|
{ x: 'Uge 49', y: 40 },
|
||||||
|
{ x: 'Uge 50', y: 38 },
|
||||||
|
{ x: 'Uge 51', y: 40 },
|
||||||
|
{ x: 'Uge 52', y: 20 },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Martin Nielsen',
|
||||||
|
color: '#3b82f6',
|
||||||
|
type: 'bar',
|
||||||
|
data: [
|
||||||
|
{ x: 'Uge 48', y: 30 },
|
||||||
|
{ x: 'Uge 49', y: 40 },
|
||||||
|
{ x: 'Uge 50', y: 35 },
|
||||||
|
{ x: 'Uge 51', y: 40 },
|
||||||
|
{ x: 'Uge 52', y: 16 },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Sofie Larsen',
|
||||||
|
color: '#8b5cf6',
|
||||||
|
type: 'bar',
|
||||||
|
data: [
|
||||||
|
{ x: 'Uge 48', y: 28 },
|
||||||
|
{ x: 'Uge 49', y: 36 },
|
||||||
|
{ x: 'Uge 50', y: 40 },
|
||||||
|
{ x: 'Uge 51', y: 40 },
|
||||||
|
{ x: 'Uge 52', y: 18 },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Peter Hansen',
|
||||||
|
color: '#f59e0b',
|
||||||
|
type: 'bar',
|
||||||
|
data: [
|
||||||
|
{ x: 'Uge 48', y: 34 },
|
||||||
|
{ x: 'Uge 49', y: 38 },
|
||||||
|
{ x: 'Uge 50', y: 32 },
|
||||||
|
{ x: 'Uge 51', y: 40 },
|
||||||
|
{ x: 'Uge 52', y: 14 },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: { format: (v) => v + ' t' },
|
||||||
|
legend: { position: 'bottom', align: 'center', gap: 0 },
|
||||||
|
height: 240
|
||||||
|
});
|
||||||
|
|
||||||
|
// Period selector
|
||||||
|
document.querySelectorAll('swp-period-selector button').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => {
|
||||||
|
document.querySelectorAll('swp-period-selector button').forEach(b => b.classList.remove('active'));
|
||||||
|
btn.classList.add('active');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sort columns
|
||||||
|
document.querySelectorAll('swp-th.sortable').forEach(th => {
|
||||||
|
th.addEventListener('click', () => {
|
||||||
|
const wasSorted = th.classList.contains('sorted');
|
||||||
|
const wasDesc = th.classList.contains('desc');
|
||||||
|
|
||||||
|
// Remove sorted state from all
|
||||||
|
document.querySelectorAll('swp-th.sortable').forEach(t => {
|
||||||
|
t.classList.remove('sorted', 'desc');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Toggle this column
|
||||||
|
th.classList.add('sorted');
|
||||||
|
if (wasSorted && !wasDesc) {
|
||||||
|
th.classList.add('desc');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1133
.workbench/POC/poc-salg.html
Normal file
2521
.workbench/POC/poc-service-detail.html
Normal file
3633
.workbench/POC/poc-website-builder.html
Normal file
564
.workbench/POC/spec-salary.html
Normal file
|
|
@ -0,0 +1,564 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="da">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Lønspecifikation – Januar 2026 (2 sider)</title>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* ===== Print setup ===== */
|
||||||
|
@page { size: A4; margin: 14mm; }
|
||||||
|
@media print {
|
||||||
|
.no-print { display: none !important; }
|
||||||
|
.page-break { break-after: page; page-break-after: always; }
|
||||||
|
a { color: inherit; text-decoration: none; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Base ===== */
|
||||||
|
:root{
|
||||||
|
--ink:#0f172a;
|
||||||
|
--muted:#475569;
|
||||||
|
--line:#e2e8f0;
|
||||||
|
--soft:#f8fafc;
|
||||||
|
--accent:#0ea5e9;
|
||||||
|
--accent-2:#22c55e;
|
||||||
|
}
|
||||||
|
*{ box-sizing:border-box; }
|
||||||
|
body{
|
||||||
|
margin:0;
|
||||||
|
font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
|
||||||
|
color:var(--ink);
|
||||||
|
background:#fff;
|
||||||
|
}
|
||||||
|
.sheet{
|
||||||
|
max-width: 210mm;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Header ===== */
|
||||||
|
.hdr{
|
||||||
|
display:flex;
|
||||||
|
justify-content:space-between;
|
||||||
|
gap:16px;
|
||||||
|
padding: 14px 0 10px;
|
||||||
|
border-bottom: 2px solid var(--line);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.brand{
|
||||||
|
display:flex;
|
||||||
|
flex-direction:column;
|
||||||
|
gap:6px;
|
||||||
|
}
|
||||||
|
.title{
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 800;
|
||||||
|
letter-spacing: .2px;
|
||||||
|
margin:0;
|
||||||
|
line-height:1.1;
|
||||||
|
}
|
||||||
|
.subtitle{
|
||||||
|
margin:0;
|
||||||
|
color:var(--muted);
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.meta{
|
||||||
|
text-align:right;
|
||||||
|
min-width: 260px;
|
||||||
|
}
|
||||||
|
.meta .pill{
|
||||||
|
display:inline-block;
|
||||||
|
font-size:12px;
|
||||||
|
padding:6px 10px;
|
||||||
|
border:1px solid var(--line);
|
||||||
|
border-radius:999px;
|
||||||
|
background:var(--soft);
|
||||||
|
margin-bottom:8px;
|
||||||
|
}
|
||||||
|
.meta .kv{
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: auto auto;
|
||||||
|
gap:4px 12px;
|
||||||
|
justify-content:end;
|
||||||
|
font-size:12px;
|
||||||
|
color:var(--muted);
|
||||||
|
}
|
||||||
|
.meta .kv b{ color:var(--ink); font-weight:600; }
|
||||||
|
|
||||||
|
/* ===== Blocks ===== */
|
||||||
|
.card{
|
||||||
|
border:1px solid var(--line);
|
||||||
|
border-radius: 14px;
|
||||||
|
overflow:hidden;
|
||||||
|
background:#fff;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.card .hd{
|
||||||
|
display:flex;
|
||||||
|
align-items:center;
|
||||||
|
justify-content:space-between;
|
||||||
|
padding: 10px 12px;
|
||||||
|
background: linear-gradient(0deg, var(--soft), #fff);
|
||||||
|
border-bottom: 1px solid var(--line);
|
||||||
|
}
|
||||||
|
.card .hd h2{
|
||||||
|
font-size: 13px;
|
||||||
|
margin:0;
|
||||||
|
letter-spacing:.2px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color:var(--muted);
|
||||||
|
}
|
||||||
|
.card .bd{ padding: 12px; }
|
||||||
|
|
||||||
|
.grid{
|
||||||
|
display:grid;
|
||||||
|
grid-template-columns: 1.2fr .8fr;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Total ===== */
|
||||||
|
.total{
|
||||||
|
display:flex;
|
||||||
|
align-items:baseline;
|
||||||
|
justify-content:space-between;
|
||||||
|
gap:12px;
|
||||||
|
padding: 14px 14px;
|
||||||
|
border-radius: 14px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: linear-gradient(135deg, rgba(14,165,233,.10), rgba(34,197,94,.08));
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
.total .label{
|
||||||
|
color:var(--muted);
|
||||||
|
font-size:12px;
|
||||||
|
text-transform:uppercase;
|
||||||
|
letter-spacing:.25px;
|
||||||
|
margin-bottom:6px;
|
||||||
|
}
|
||||||
|
.total .big{
|
||||||
|
font-size: 28px;
|
||||||
|
font-weight: 900;
|
||||||
|
margin:0;
|
||||||
|
line-height:1.05;
|
||||||
|
}
|
||||||
|
.total .big small{
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 700;
|
||||||
|
color:var(--muted);
|
||||||
|
}
|
||||||
|
.badge{
|
||||||
|
display:inline-block;
|
||||||
|
font-size:11px;
|
||||||
|
padding:4px 8px;
|
||||||
|
border-radius:999px;
|
||||||
|
border:1px solid var(--line);
|
||||||
|
background:var(--soft);
|
||||||
|
color:var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Tables ===== */
|
||||||
|
table{
|
||||||
|
width:100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
th, td{
|
||||||
|
padding: 8px 8px;
|
||||||
|
border-bottom:1px solid var(--line);
|
||||||
|
vertical-align:top;
|
||||||
|
}
|
||||||
|
th{
|
||||||
|
text-align:left;
|
||||||
|
color:var(--muted);
|
||||||
|
font-weight:700;
|
||||||
|
font-size:11px;
|
||||||
|
text-transform:uppercase;
|
||||||
|
letter-spacing:.2px;
|
||||||
|
background: var(--soft);
|
||||||
|
}
|
||||||
|
td.num, th.num{ text-align:right; }
|
||||||
|
tr:last-child td{ border-bottom:none; }
|
||||||
|
|
||||||
|
.note{
|
||||||
|
margin:8px 0 0;
|
||||||
|
color:var(--muted);
|
||||||
|
font-size:11px;
|
||||||
|
line-height:1.35;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Footer ===== */
|
||||||
|
.ftr{
|
||||||
|
margin-top: 10px;
|
||||||
|
padding-top: 10px;
|
||||||
|
border-top:1px solid var(--line);
|
||||||
|
display:flex;
|
||||||
|
justify-content:space-between;
|
||||||
|
gap:12px;
|
||||||
|
font-size: 10.5px;
|
||||||
|
color:var(--muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== Ensure “side 1” content doesn't get split awkwardly ===== */
|
||||||
|
.avoid-break { break-inside: avoid; page-break-inside: avoid; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<!-- ===================== PAGE 1: OVERBLIK ===================== -->
|
||||||
|
<div class="sheet">
|
||||||
|
<div class="hdr">
|
||||||
|
<div class="brand">
|
||||||
|
<p class="title">Lønspecifikation</p>
|
||||||
|
<p class="subtitle">Periode: <b>Januar 2026</b></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meta">
|
||||||
|
<div class="pill">Medarbejdernr.: <b>EMP-001</b></div>
|
||||||
|
<div class="kv">
|
||||||
|
<span>Medarbejder:</span><b>Emma Larsen</b>
|
||||||
|
<span>Afdeling:</span><b>Frisør</b>
|
||||||
|
<span>Ansættelse:</span><b>Fuldtid (37 t/uge)</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="total avoid-break">
|
||||||
|
<div>
|
||||||
|
<div class="label">Bruttoløn (Januar 2026)</div>
|
||||||
|
<p class="big">34.063,50 <small>kr</small></p>
|
||||||
|
</div>
|
||||||
|
<div style="text-align:right">
|
||||||
|
<div><span class="badge">Side 1: Overblik</span></div>
|
||||||
|
<div style="margin-top:6px; color:var(--muted); font-size:12px; line-height:1.35">
|
||||||
|
Kort opsummering til udlevering.<br/>
|
||||||
|
Detaljer findes på side 2.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="grid">
|
||||||
|
<div class="card avoid-break">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Samlet lønopgørelse</h2>
|
||||||
|
<span class="badge">Alle beløb i DKK</span>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Løndel</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Grundløn inkl. overarbejde</td>
|
||||||
|
<td class="num">29.322,50 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Provision i alt</td>
|
||||||
|
<td class="num">3.685,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tillæg i alt</td>
|
||||||
|
<td class="num">1.056,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Bruttoløn</b></td>
|
||||||
|
<td class="num"><b>34.063,50 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">
|
||||||
|
(Hvis du senere vil have skat/AM-bidrag/nettoløn med, kan det tilføjes som ekstra blok her.)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card avoid-break">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Saldi</h2>
|
||||||
|
<span class="badge">Ved periodens slut</span>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Type</th>
|
||||||
|
<th class="num">Optjent</th>
|
||||||
|
<th class="num">Afholdt</th>
|
||||||
|
<th class="num">Rest</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Ferie (dage)</td>
|
||||||
|
<td class="num">18,5</td>
|
||||||
|
<td class="num">6,0</td>
|
||||||
|
<td class="num">12,5</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Afspadsering (timer)</td>
|
||||||
|
<td class="num">12,0</td>
|
||||||
|
<td class="num">4,0</td>
|
||||||
|
<td class="num">8,0</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">Saldi er opgjort som angivet på lønspecifikationen.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card avoid-break">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Hurtigt resumé</h2>
|
||||||
|
<span class="badge">Det vigtigste</span>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Nøglepunkt</th>
|
||||||
|
<th class="num">Værdi</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Normaltimer</td>
|
||||||
|
<td class="num">148,0 t</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Overarbejde</td>
|
||||||
|
<td class="num">7,0 t</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Provision (services + produkter)</td>
|
||||||
|
<td class="num">3.685,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Tillæg (aften + lørdag + søndag)</td>
|
||||||
|
<td class="num">1.056,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="ftr">
|
||||||
|
<div><b>Side 1/2</b> · Overblik</div>
|
||||||
|
<div style="text-align:right">Lønspecifikation · Januar 2026</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="page-break"></div>
|
||||||
|
|
||||||
|
<!-- ===================== PAGE 2: DETALJER ===================== -->
|
||||||
|
<div class="hdr">
|
||||||
|
<div class="brand">
|
||||||
|
<p class="title">Lønspecifikation – Detaljer</p>
|
||||||
|
<p class="subtitle">Periode: <b>Januar 2026</b> · Medarbejder: <b>Emma Larsen</b></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="meta">
|
||||||
|
<div class="pill">Bruttoløn: <b>34.063,50 kr</b></div>
|
||||||
|
<div class="kv">
|
||||||
|
<span>Ansættelse:</span><b>Fuldtid (37 t/uge)</b>
|
||||||
|
<span>Afdeling:</span><b>Frisør</b>
|
||||||
|
<span>Medarb.nr.:</span><b>EMP-001</b>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Arbejdstid pr. uge</h2>
|
||||||
|
<span class="badge">Normal + overtid</span>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Uge</th>
|
||||||
|
<th class="num">Normaltimer</th>
|
||||||
|
<th class="num">Overtid</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 1 (30. dec – 5. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">2,0 t</td>
|
||||||
|
<td class="num">7.400,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 2 (6. – 12. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">3,5 t</td>
|
||||||
|
<td class="num">7.816,25 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 3 (13. – 19. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">0,0 t</td>
|
||||||
|
<td class="num">6.845,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 4 (20. – 26. jan)</td>
|
||||||
|
<td class="num">37,0 t</td>
|
||||||
|
<td class="num">1,5 t</td>
|
||||||
|
<td class="num">7.261,25 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>I alt</b></td>
|
||||||
|
<td class="num"><b>148,0 t</b></td>
|
||||||
|
<td class="num"><b>7,0 t</b></td>
|
||||||
|
<td class="num"><b>29.322,50 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">
|
||||||
|
Satser: Normal 185,00 kr/time. Overtid (50%) 277,50 kr/time.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Provision</h2>
|
||||||
|
<span class="badge">Services & produkter</span>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<p class="note" style="margin-top:0">
|
||||||
|
<b>Services:</b> 15% af omsætning over minimum (220 kr/time).<br/>
|
||||||
|
<b>Produkter:</b> 10% af salg.
|
||||||
|
</p>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Uge</th>
|
||||||
|
<th class="num">Service prov.</th>
|
||||||
|
<th class="num">Produkt prov.</th>
|
||||||
|
<th class="num">I alt</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 1</td>
|
||||||
|
<td class="num">573,00 kr</td>
|
||||||
|
<td class="num">210,00 kr</td>
|
||||||
|
<td class="num">783,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 2</td>
|
||||||
|
<td class="num">883,50 kr</td>
|
||||||
|
<td class="num">320,00 kr</td>
|
||||||
|
<td class="num">1.203,50 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 3</td>
|
||||||
|
<td class="num">459,00 kr</td>
|
||||||
|
<td class="num">180,00 kr</td>
|
||||||
|
<td class="num">639,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Uge 4</td>
|
||||||
|
<td class="num">769,50 kr</td>
|
||||||
|
<td class="num">290,00 kr</td>
|
||||||
|
<td class="num">1.059,50 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>I alt</b></td>
|
||||||
|
<td class="num"><b>2.685,00 kr</b></td>
|
||||||
|
<td class="num"><b>1.000,00 kr</b></td>
|
||||||
|
<td class="num"><b>3.685,00 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="card">
|
||||||
|
<div class="hd">
|
||||||
|
<h2>Tillæg & fravær</h2>
|
||||||
|
<span class="badge">Opsummering</span>
|
||||||
|
</div>
|
||||||
|
<div class="bd">
|
||||||
|
<div class="grid" style="grid-template-columns: 1fr 1fr;">
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Tillæg</th>
|
||||||
|
<th class="num">Timer</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Aftentillæg (hverdage 18–21)</td>
|
||||||
|
<td class="num">12,0</td>
|
||||||
|
<td class="num">336,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Lørdagstillæg (før kl. 14)</td>
|
||||||
|
<td class="num">16,0</td>
|
||||||
|
<td class="num">720,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Søndagstillæg</td>
|
||||||
|
<td class="num">0,0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><b>Tillæg i alt</b></td>
|
||||||
|
<td class="num"></td>
|
||||||
|
<td class="num"><b>1.056,00 kr</b></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Fravær</th>
|
||||||
|
<th class="num">Dage</th>
|
||||||
|
<th class="num">Beløb</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Ferie med løn</td>
|
||||||
|
<td class="num">0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Sygdom</td>
|
||||||
|
<td class="num">0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Barns sygedag</td>
|
||||||
|
<td class="num">0</td>
|
||||||
|
<td class="num">0,00 kr</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<p class="note">Ingen fravær registreret i perioden.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="ftr">
|
||||||
|
<div><b>Side 2/2</b> · Detaljer</div>
|
||||||
|
<div style="text-align:right">Lønspecifikation · Januar 2026</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="no-print" style="margin:12px 0; color:var(--muted); font-size:12px;">
|
||||||
|
Tip: I Chrome/Edge: <b>Ctrl/Cmd + P</b> → Destination: <b>Gem som PDF</b> → slå “Headers and footers” fra.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||