Calendar/wwwroot/poc-layout.html
Janus C. H. Knudsen 7b2080a7bf Refactors dashboard to use external CSS file
Moves inline styles to dedicated dashboard.css
Updates HTML to reference external stylesheet
Improves code organization and maintainability

Relates to refac branch
2025-12-31 00:36:32 +01:00

2992 lines
90 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

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

<!DOCTYPE html>
<html lang="da">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>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/dashboard.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;
/* Layout */
--side-menu-width: 240px;
--side-menu-width-collapsed: 64px;
--topbar-height: 56px;
}
/* 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;
}
html, body {
height: 100%;
}
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;
}
/* ==========================================
APP LAYOUT
========================================== */
swp-app-layout {
display: grid;
grid-template-columns: var(--side-menu-width) 1fr;
grid-template-rows: var(--topbar-height) 1fr;
height: 100vh;
}
/* ==========================================
SIDE MENU
========================================== */
swp-side-menu {
grid-row: 1 / -1;
display: flex;
flex-direction: column;
background: var(--color-surface);
border-right: 1px solid var(--color-border);
overflow-y: auto;
}
swp-side-menu-header {
display: flex;
align-items: center;
gap: 10px;
height: var(--topbar-height);
padding: 0 16px;
border-bottom: 1px solid var(--color-border);
}
swp-side-menu-header i {
font-size: 26px;
color: var(--color-teal);
}
swp-side-menu-logo {
font-size: 16px;
font-weight: 600;
color: var(--color-text);
}
swp-menu-toggle {
margin-left: auto;
width: 28px;
height: 28px;
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-menu-toggle:hover {
background: var(--color-background-hover);
color: var(--color-text);
}
swp-menu-toggle i {
font-size: 18px;
color: inherit;
transition: transform 200ms ease;
}
swp-side-menu-nav {
flex: 1;
padding: 12px 0;
overflow-y: auto;
}
swp-side-menu-group {
display: block;
margin-bottom: 8px;
}
swp-side-menu-label {
display: block;
padding: 8px 16px 6px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
}
swp-side-menu-item {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 16px;
color: var(--color-text);
cursor: pointer;
transition: all 150ms ease;
border-left: 3px solid transparent;
text-decoration: none;
}
swp-side-menu-item:hover {
background: var(--color-background-hover);
text-decoration: none;
}
swp-side-menu-item[data-active="true"] {
background: color-mix(in srgb, var(--color-teal) 10%, transparent);
border-left-color: var(--color-teal);
color: var(--color-teal);
font-weight: 500;
}
swp-side-menu-item i {
font-size: 20px;
flex-shrink: 0;
}
swp-side-menu-footer {
display: flex;
flex-direction: column;
gap: 8px;
padding: 12px 16px;
border-top: 1px solid var(--color-border);
margin-top: auto;
}
swp-side-menu-action {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 10px;
font-size: 13px;
color: var(--color-text-secondary);
background: transparent;
border: 1px solid var(--color-border);
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
font-family: var(--font-family);
}
swp-side-menu-action:hover {
background: var(--color-background-hover);
}
swp-side-menu-action.lock:hover {
color: var(--color-amber);
border-color: var(--color-amber);
}
swp-side-menu-action.logout:hover {
color: var(--color-red);
border-color: var(--color-red);
}
swp-side-menu-action i {
font-size: 18px;
}
/* ==========================================
SIDE MENU - COLLAPSED STATE
========================================== */
swp-app-layout {
transition: grid-template-columns 200ms ease;
}
swp-app-layout.menu-collapsed {
grid-template-columns: var(--side-menu-width-collapsed) 1fr;
}
swp-app-layout.menu-collapsed swp-side-menu {
overflow: visible;
}
swp-app-layout.menu-collapsed swp-side-menu-logo,
swp-app-layout.menu-collapsed swp-side-menu-label,
swp-app-layout.menu-collapsed swp-side-menu-item span,
swp-app-layout.menu-collapsed swp-side-menu-action span {
display: none;
}
swp-app-layout.menu-collapsed swp-side-menu-header {
justify-content: center;
padding: 0;
}
swp-app-layout.menu-collapsed swp-menu-toggle {
margin-left: 0;
}
swp-app-layout.menu-collapsed swp-menu-toggle i {
transform: rotate(180deg);
}
swp-app-layout.menu-collapsed swp-side-menu-item {
justify-content: center;
padding: 12px;
border-left: none;
position: relative;
}
swp-app-layout.menu-collapsed swp-side-menu-item[data-active="true"] {
border-left: none;
border-radius: 8px;
margin: 0 8px;
}
swp-app-layout.menu-collapsed swp-side-menu-action {
justify-content: center;
padding: 12px;
}
swp-app-layout.menu-collapsed swp-side-menu-footer {
padding: 12px 8px;
}
/* Popover tooltip for collapsed menu */
.swp-menu-tooltip {
position: fixed;
margin: 0;
padding: 6px 12px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 6px;
font-size: 13px;
font-family: var(--font-family);
color: var(--color-text);
white-space: nowrap;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
pointer-events: none;
}
/* ==========================================
TOP BAR
========================================== */
swp-app-topbar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 20px;
background: var(--color-surface);
border-bottom: 1px solid var(--color-border);
}
swp-topbar-search {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 14px;
background: var(--color-background);
border: 1px solid var(--color-border);
border-radius: 6px;
width: 320px;
transition: border-color 150ms ease;
}
swp-topbar-search:focus-within {
border-color: var(--color-teal);
}
swp-topbar-search i {
font-size: 18px;
color: var(--color-text-secondary);
flex-shrink: 0;
}
swp-topbar-search input {
flex: 1;
border: none;
outline: none;
background: transparent;
font-size: 13px;
font-family: var(--font-family);
color: var(--color-text);
}
swp-topbar-search input::placeholder {
color: var(--color-text-secondary);
}
swp-topbar-search kbd {
font-size: 11px;
font-family: var(--font-mono);
padding: 2px 6px;
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: 4px;
color: var(--color-text-secondary);
}
swp-topbar-actions {
display: flex;
align-items: center;
gap: 8px;
}
swp-topbar-btn {
display: flex;
align-items: center;
justify-content: center;
width: 38px;
height: 38px;
border: none;
background: transparent;
border-radius: 6px;
cursor: pointer;
transition: background 150ms ease;
position: relative;
color: var(--color-text-secondary);
}
swp-topbar-btn:hover {
background: var(--color-background-hover);
}
swp-topbar-btn i {
font-size: 22px;
}
swp-notification-badge {
position: absolute;
top: 6px;
right: 6px;
min-width: 16px;
height: 16px;
padding: 0 4px;
font-size: 10px;
font-weight: 600;
background: var(--color-red);
color: white;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
}
swp-topbar-divider {
width: 1px;
height: 24px;
background: var(--color-border);
margin: 0 8px;
}
swp-topbar-profile {
display: flex;
align-items: center;
gap: 10px;
padding: 6px 12px 6px 6px;
background: transparent;
border: 1px solid transparent;
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
position: relative;
}
swp-topbar-profile:hover {
background: var(--color-background-hover);
border-color: var(--color-border);
}
swp-profile-avatar {
width: 32px;
height: 32px;
border-radius: 50%;
background: var(--color-purple);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
font-weight: 600;
}
swp-profile-info {
display: flex;
flex-direction: column;
text-align: left;
}
swp-profile-name {
font-size: 13px;
font-weight: 500;
color: var(--color-text);
}
swp-profile-role {
font-size: 11px;
color: var(--color-text-secondary);
}
/* ==========================================
PROFILE DRAWER
========================================== */
swp-drawer-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.2);
opacity: 0;
visibility: hidden;
transition: opacity 200ms ease, visibility 200ms ease;
z-index: 900;
}
swp-drawer-overlay.open {
opacity: 1;
visibility: visible;
}
swp-profile-drawer {
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 320px;
background: var(--color-surface);
border-left: 1px solid var(--color-border);
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
transform: translateX(100%);
transition: transform 200ms ease;
display: flex;
flex-direction: column;
z-index: 1000;
}
swp-profile-drawer.open {
transform: translateX(0);
}
swp-drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-bottom: 1px solid var(--color-border);
background: var(--color-background-alt);
}
swp-drawer-title {
font-size: 14px;
font-weight: 600;
color: var(--color-text);
}
swp-drawer-close {
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-drawer-close:hover {
background: var(--color-background-hover);
color: var(--color-text);
}
swp-drawer-close i {
font-size: 20px;
}
swp-drawer-content {
flex: 1;
overflow-y: auto;
padding: 20px 16px;
display: flex;
flex-direction: column;
gap: 24px;
}
/* Profile header in drawer */
swp-drawer-profile {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding-bottom: 20px;
border-bottom: 1px solid var(--color-border);
}
swp-drawer-avatar {
width: 72px;
height: 72px;
border-radius: 50%;
background: var(--color-purple);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: 600;
margin-bottom: 12px;
}
swp-drawer-name {
font-size: 18px;
font-weight: 600;
color: var(--color-text);
margin-bottom: 2px;
}
swp-drawer-role {
font-size: 13px;
color: var(--color-text-secondary);
margin-bottom: 8px;
}
swp-drawer-email {
font-size: 13px;
color: var(--color-teal);
}
/* Drawer sections */
swp-drawer-section {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-drawer-section-label {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
margin-bottom: 4px;
}
swp-drawer-item {
display: flex;
align-items: center;
gap: 12px;
padding: 12px;
background: var(--color-background-alt);
border-radius: 8px;
cursor: pointer;
transition: background 150ms ease;
}
swp-drawer-item:hover {
background: var(--color-background-hover);
}
swp-drawer-item i {
font-size: 20px;
color: var(--color-text-secondary);
}
swp-drawer-item-text {
flex: 1;
font-size: 14px;
color: var(--color-text);
}
swp-drawer-item-hint {
font-size: 12px;
color: var(--color-text-secondary);
}
/* Theme toggle in drawer - two icons */
swp-theme-toggle {
display: flex;
border: 1px solid var(--color-border);
border-radius: 8px;
overflow: hidden;
}
swp-theme-option {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 12px;
background: var(--color-background-alt);
cursor: pointer;
transition: all 150ms ease;
}
swp-theme-option:first-child {
border-right: 1px solid var(--color-border);
}
swp-theme-option i {
font-size: 20px;
color: var(--color-text-secondary);
transition: color 150ms ease;
}
swp-theme-option:hover {
background: var(--color-background-hover);
}
swp-theme-option.active {
background: color-mix(in srgb, var(--color-teal) 12%, transparent);
}
swp-theme-option.active i {
color: var(--color-teal);
}
/* Drawer footer */
swp-drawer-footer {
display: flex;
flex-direction: column;
gap: 8px;
padding: 16px;
border-top: 1px solid var(--color-border);
}
swp-drawer-action {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 12px;
font-size: 14px;
font-family: var(--font-family);
border: 1px solid var(--color-border);
border-radius: 8px;
cursor: pointer;
transition: all 150ms ease;
background: transparent;
color: var(--color-text-secondary);
}
swp-drawer-action:hover {
background: var(--color-background-hover);
}
swp-drawer-action.lock:hover {
color: var(--color-amber);
border-color: var(--color-amber);
}
swp-drawer-action.logout:hover {
color: var(--color-red);
border-color: var(--color-red);
}
swp-drawer-action i {
font-size: 18px;
}
/* ==========================================
NOTIFICATION DRAWER
========================================== */
swp-notification-drawer {
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 380px;
background: var(--color-surface);
border-left: 1px solid var(--color-border);
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
transform: translateX(100%);
transition: transform 200ms ease;
display: flex;
flex-direction: column;
z-index: 1000;
}
swp-notification-drawer.open {
transform: translateX(0);
}
swp-notification-drawer swp-drawer-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 16px;
border-bottom: 1px solid var(--color-border);
background: var(--color-background-alt);
}
swp-drawer-header-actions {
display: flex;
align-items: center;
gap: 8px;
}
swp-mark-read-btn {
padding: 6px 12px;
font-size: 12px;
font-family: var(--font-family);
color: var(--color-teal);
background: transparent;
border: 1px solid var(--color-teal);
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
}
swp-mark-read-btn:hover {
background: var(--color-teal);
color: white;
}
swp-notification-drawer swp-drawer-content {
flex: 1;
overflow-y: auto;
padding: 12px;
display: flex;
flex-direction: column;
gap: 8px;
}
swp-notification-item {
display: flex;
gap: 12px;
padding: 12px;
border-radius: 8px;
cursor: pointer;
transition: background 150ms ease;
background: transparent;
}
swp-notification-item:hover {
background: var(--color-background-hover);
}
swp-notification-item[data-unread="true"] {
background: var(--color-background-alt);
}
swp-notification-item[data-unread="true"]::before {
content: '';
position: absolute;
left: 4px;
top: 50%;
transform: translateY(-50%);
width: 6px;
height: 6px;
background: var(--color-teal);
border-radius: 50%;
}
swp-notification-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
swp-notification-icon i {
font-size: 20px;
}
swp-notification-icon.booking {
background: color-mix(in srgb, var(--color-teal) 15%, transparent);
color: var(--color-teal);
}
swp-notification-icon.smiley {
background: color-mix(in srgb, var(--color-amber) 15%, transparent);
color: var(--color-amber);
}
swp-notification-icon.call {
background: color-mix(in srgb, var(--color-blue) 15%, transparent);
color: var(--color-blue);
}
swp-notification-icon.mail {
background: color-mix(in srgb, var(--color-purple) 15%, transparent);
color: var(--color-purple);
}
swp-notification-icon.chat {
background: color-mix(in srgb, var(--color-green) 15%, transparent);
color: var(--color-green);
}
swp-notification-icon.reminder {
background: color-mix(in srgb, var(--color-red) 15%, transparent);
color: var(--color-red);
}
swp-notification-content {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
swp-notification-title {
font-weight: 500;
font-size: 14px;
color: var(--color-text);
}
swp-notification-text {
font-size: 13px;
color: var(--color-text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
swp-notification-time {
font-size: 11px;
color: var(--color-text-secondary);
margin-top: 2px;
}
swp-notification-empty {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 48px 24px;
text-align: center;
color: var(--color-text-secondary);
}
swp-notification-empty i {
font-size: 48px;
margin-bottom: 12px;
opacity: 0.5;
}
/* ==========================================
TODO DRAWER
========================================== */
swp-todo-drawer {
position: fixed;
top: 0;
right: 0;
bottom: 0;
width: 380px;
background: var(--color-surface);
border-left: 1px solid var(--color-border);
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
transform: translateX(100%);
transition: transform 200ms ease;
display: flex;
flex-direction: column;
z-index: 1001;
}
swp-todo-drawer.open {
transform: translateX(0);
}
/* New Todo Drawer - slides from left of todo drawer */
swp-new-todo-drawer {
position: fixed;
top: 0;
right: 380px;
bottom: 0;
width: 340px;
background: var(--color-surface);
border-left: 1px solid var(--color-border);
box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
transform: translateX(100%);
opacity: 0;
pointer-events: none;
transition: transform 250ms cubic-bezier(0.4, 0, 0.2, 1),
opacity 200ms ease;
display: flex;
flex-direction: column;
z-index: 1000;
}
swp-new-todo-drawer.open {
transform: translateX(0);
opacity: 1;
pointer-events: auto;
}
swp-todo-drawer swp-drawer-header {
display: flex;
align-items: center;
gap: 8px;
padding: 14px 16px;
border-bottom: 1px solid var(--color-border);
background: var(--color-background-alt);
}
swp-todo-drawer swp-drawer-title {
flex: 1;
}
swp-drawer-back {
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-drawer-back:hover {
background: var(--color-background-hover);
color: var(--color-text);
}
swp-drawer-back i {
font-size: 20px;
}
swp-add-todo-btn {
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
background: var(--color-teal);
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
}
swp-add-todo-btn:hover {
background: color-mix(in srgb, var(--color-teal) 85%, black);
}
swp-add-todo-btn i {
font-size: 18px;
}
swp-todo-drawer swp-drawer-content {
flex: 1;
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 20px;
}
swp-todo-section {
display: flex;
flex-direction: column;
gap: 8px;
}
swp-todo-section-header {
display: flex;
align-items: center;
gap: 8px;
padding: 4px 0;
cursor: pointer;
}
swp-todo-section-header i {
font-size: 14px;
color: var(--color-text-secondary);
transition: transform 200ms ease;
}
swp-todo-section.collapsed swp-todo-section-header i {
transform: rotate(-90deg);
}
swp-todo-section.collapsed swp-todo-items {
display: none;
}
swp-todo-section-title {
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--color-text-secondary);
}
swp-todo-section-count {
font-size: 11px;
padding: 2px 6px;
background: var(--color-background);
border-radius: 10px;
color: var(--color-text-secondary);
}
swp-todo-items {
display: flex;
flex-direction: column;
gap: 6px;
}
swp-todo-item {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 10px 12px;
background: var(--color-background-alt);
border-radius: 8px;
cursor: pointer;
transition: all 150ms ease;
}
swp-todo-item:hover {
background: var(--color-background-hover);
}
swp-todo-item[data-completed="true"] {
opacity: 0.6;
}
swp-todo-item[data-completed="true"] swp-todo-title {
text-decoration: line-through;
color: var(--color-text-secondary);
}
swp-todo-checkbox {
width: 20px;
height: 20px;
border: 2px solid var(--color-border);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 1px;
transition: all 150ms ease;
}
swp-todo-checkbox i {
font-size: 14px;
color: white;
opacity: 0;
}
swp-todo-item[data-completed="true"] swp-todo-checkbox {
background: var(--color-teal);
border-color: var(--color-teal);
}
swp-todo-item[data-completed="true"] swp-todo-checkbox i {
opacity: 1;
}
swp-todo-content {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
swp-todo-title {
font-size: 14px;
color: var(--color-text);
}
swp-todo-meta {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: var(--color-text-secondary);
}
swp-todo-meta i {
font-size: 14px;
}
swp-todo-time {
display: flex;
align-items: center;
gap: 4px;
}
swp-todo-priority {
display: flex;
align-items: center;
gap: 4px;
}
swp-todo-priority.high {
color: var(--color-red);
}
swp-todo-priority.low {
color: var(--color-text-secondary);
opacity: 0.7;
}
swp-todo-date {
display: flex;
align-items: center;
gap: 4px;
}
/* New Todo Drawer - Header */
swp-new-todo-drawer swp-drawer-header {
display: flex;
align-items: center;
gap: 8px;
padding: 14px 16px;
border-bottom: 1px solid var(--color-border);
background: var(--color-background-alt);
}
swp-new-todo-drawer swp-drawer-title {
flex: 1;
}
swp-new-todo-drawer swp-drawer-content {
flex: 1;
overflow-y: auto;
padding: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
/* Form Elements - matches detail-drawer patterns */
swp-new-todo-drawer swp-section-label {
display: block;
font-size: 11px;
font-weight: 400;
color: var(--color-text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 8px;
}
swp-new-todo-drawer swp-form-field {
display: block;
}
swp-new-todo-drawer swp-form-row {
display: flex;
gap: 12px;
}
swp-new-todo-drawer swp-form-row swp-form-field {
flex: 1;
}
swp-new-todo-drawer input[type="text"],
swp-new-todo-drawer input[type="date"],
swp-new-todo-drawer input[type="time"],
swp-new-todo-drawer select,
swp-new-todo-drawer textarea {
width: 100%;
padding: 10px 12px;
font-size: 14px;
font-family: var(--font-family);
color: var(--color-text);
background: var(--color-background-alt);
border: 1px solid var(--color-border);
border-radius: 4px;
outline: none;
transition: border-color 150ms ease;
}
swp-new-todo-drawer input:focus,
swp-new-todo-drawer select:focus,
swp-new-todo-drawer textarea:focus {
border-color: var(--color-teal);
}
swp-new-todo-drawer input::placeholder,
swp-new-todo-drawer textarea::placeholder {
color: var(--color-text-secondary);
}
swp-new-todo-drawer select {
cursor: pointer;
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 11.32-11.32L128 164.69l74.34-74.35a8 8 0 0 1 11.32 11.32Z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 10px center;
padding-right: 36px;
}
swp-new-todo-drawer textarea {
resize: none;
min-height: 80px;
}
/* Visibility toggle */
swp-visibility-toggle {
display: flex;
border: 1px solid var(--color-border);
border-radius: 4px;
overflow: hidden;
}
swp-visibility-option {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 10px 12px;
font-size: 13px;
color: var(--color-text-secondary);
background: var(--color-background-alt);
cursor: pointer;
transition: all 150ms ease;
border: none;
}
swp-visibility-option:first-child {
border-right: 1px solid var(--color-border);
}
swp-visibility-option i {
font-size: 16px;
}
swp-visibility-option:hover {
background: var(--color-background-hover);
}
swp-visibility-option.active {
background: color-mix(in srgb, var(--color-teal) 12%, transparent);
color: var(--color-teal);
}
/* Footer with buttons */
swp-new-todo-drawer swp-drawer-footer {
padding: 16px;
border-top: 1px solid var(--color-border);
display: flex;
gap: 12px;
}
swp-new-todo-drawer swp-btn {
flex: 1;
padding: 10px 16px;
font-size: 14px;
font-weight: 500;
font-family: var(--font-family);
border-radius: 6px;
cursor: pointer;
transition: all 150ms ease;
text-align: center;
border: none;
}
swp-new-todo-drawer swp-btn.secondary {
background: transparent;
border: 1px solid var(--color-border);
color: var(--color-text-secondary);
}
swp-new-todo-drawer swp-btn.secondary:hover {
background: var(--color-background-hover);
color: var(--color-text);
}
swp-new-todo-drawer swp-btn.primary {
background: var(--color-teal);
color: white;
}
swp-new-todo-drawer swp-btn.primary:hover {
background: color-mix(in srgb, var(--color-teal) 85%, black);
}
/* ==========================================
LOCK SCREEN
========================================== */
swp-lock-screen {
position: fixed;
inset: 0;
background: var(--color-background);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 2000;
opacity: 0;
visibility: hidden;
transition: opacity 300ms ease, visibility 300ms ease;
}
swp-lock-screen.active {
opacity: 1;
visibility: visible;
}
swp-lock-content {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
padding: 40px;
background: var(--color-surface);
border-radius: 16px;
border: 1px solid var(--color-border);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
swp-lock-icon {
width: 80px;
height: 80px;
border-radius: 50%;
background: color-mix(in srgb, var(--color-teal) 12%, transparent);
display: flex;
align-items: center;
justify-content: center;
}
swp-lock-icon i {
font-size: 36px;
color: var(--color-teal);
}
swp-lock-title {
font-size: 20px;
font-weight: 600;
color: var(--color-text);
}
swp-lock-subtitle {
font-size: 14px;
color: var(--color-text-secondary);
margin-top: -16px;
}
swp-pin-input {
display: flex;
gap: 12px;
}
swp-pin-digit {
width: 56px;
height: 64px;
border: 2px solid var(--color-border);
border-radius: 12px;
background: var(--color-surface);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
font-weight: 600;
font-family: var(--font-mono);
color: var(--color-text);
transition: all 150ms ease;
}
swp-pin-digit.filled {
border-color: var(--color-teal);
background: color-mix(in srgb, var(--color-teal) 8%, transparent);
}
swp-pin-digit.error {
border-color: var(--color-red);
background: color-mix(in srgb, var(--color-red) 8%, transparent);
animation: shake 0.4s ease;
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
20%, 60% { transform: translateX(-8px); }
40%, 80% { transform: translateX(8px); }
}
swp-pin-keypad {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 12px;
margin-top: 8px;
}
swp-pin-key {
width: 72px;
height: 56px;
border: 1px solid var(--color-border);
border-radius: 10px;
background: var(--color-surface);
display: flex;
align-items: center;
justify-content: center;
font-size: 22px;
font-weight: 500;
color: var(--color-text);
cursor: pointer;
transition: all 150ms ease;
font-family: var(--font-family);
}
swp-pin-key:hover {
background: var(--color-background-hover);
border-color: var(--color-teal);
}
swp-pin-key:active {
transform: scale(0.95);
}
swp-pin-key.empty {
visibility: hidden;
}
swp-pin-key.backspace {
font-size: 20px;
}
swp-pin-key.backspace i {
font-size: 24px;
}
swp-lock-time {
font-size: 13px;
color: var(--color-text-secondary);
margin-top: -12px;
}
swp-lock-hint {
font-size: 12px;
color: var(--color-text-secondary);
margin-top: -8px;
}
/* ==========================================
MAIN CONTENT
========================================== */
swp-main-content {
display: block;
overflow-y: auto;
padding: 24px;
background: var(--color-background);
}
/* Demo placeholder */
swp-content-placeholder {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
min-height: 400px;
background: var(--color-surface);
border: 2px dashed var(--color-border);
border-radius: 12px;
color: var(--color-text-secondary);
}
swp-content-placeholder i {
font-size: 64px;
color: var(--color-border);
margin-bottom: 16px;
}
swp-content-placeholder-title {
font-size: 18px;
font-weight: 600;
color: var(--color-text);
margin-bottom: 8px;
}
swp-content-placeholder-text {
font-size: 14px;
text-align: center;
max-width: 400px;
}
</style>
</head>
<body>
<swp-app-layout>
<!-- Side Menu -->
<swp-side-menu>
<swp-side-menu-header>
<i class="ph ph-squares-four"></i>
<swp-side-menu-logo>Salon OS</swp-side-menu-logo>
<swp-menu-toggle id="menuToggle">
<i class="ph ph-caret-left"></i>
</swp-menu-toggle>
</swp-side-menu-header>
<swp-side-menu-nav>
<!-- DASHBOARD -->
<swp-side-menu-group>
<swp-side-menu-label>Dashboard</swp-side-menu-label>
<swp-side-menu-item data-active="true" data-tooltip="Dashboard">
<i class="ph ph-squares-four"></i>
<span>Dashboard</span>
</swp-side-menu-item>
<swp-side-menu-item onclick="location.href='poc-calendar.html'" data-tooltip="Kalender">
<i class="ph ph-calendar"></i>
<span>Kalender</span>
</swp-side-menu-item>
<swp-side-menu-item data-tooltip="Kasse">
<i class="ph ph-device-mobile"></i>
<span>Kasse</span>
</swp-side-menu-item>
</swp-side-menu-group>
<!-- DATA -->
<swp-side-menu-group>
<swp-side-menu-label>Data</swp-side-menu-label>
<swp-side-menu-item onclick="location.href='poc-produkter.html'" data-tooltip="Produkter & Lager">
<i class="ph ph-package"></i>
<span>Produkter & Lager</span>
</swp-side-menu-item>
<swp-side-menu-item onclick="location.href='poc-leverandoerer.html'" data-tooltip="Leverandører">
<i class="ph ph-truck"></i>
<span>Leverandører</span>
</swp-side-menu-item>
<swp-side-menu-item data-tooltip="Kunder">
<i class="ph ph-users"></i>
<span>Kunder</span>
</swp-side-menu-item>
<swp-side-menu-item onclick="location.href='poc-employee.html'" data-tooltip="Medarbejdere">
<i class="ph ph-user"></i>
<span>Medarbejdere</span>
</swp-side-menu-item>
</swp-side-menu-group>
<!-- ANALYSE -->
<swp-side-menu-group>
<swp-side-menu-label>Analyse</swp-side-menu-label>
<swp-side-menu-item data-tooltip="Statistik & Rapporter">
<i class="ph ph-chart-bar"></i>
<span>Statistik & Rapporter</span>
</swp-side-menu-item>
</swp-side-menu-group>
<!-- SYSTEM -->
<swp-side-menu-group>
<swp-side-menu-label>System</swp-side-menu-label>
<swp-side-menu-item onclick="location.href='poc-indstillinger.html'" data-tooltip="Indstillinger">
<i class="ph ph-gear"></i>
<span>Indstillinger</span>
</swp-side-menu-item>
<swp-side-menu-item onclick="location.href='poc-konto.html'" data-tooltip="Abonnement & Konto">
<i class="ph ph-credit-card"></i>
<span>Abonnement & Konto</span>
</swp-side-menu-item>
</swp-side-menu-group>
</swp-side-menu-nav>
<swp-side-menu-footer>
<swp-side-menu-action class="lock" title="Lås skærm">
<i class="ph ph-lock"></i>
<span>Lås skærm</span>
</swp-side-menu-action>
</swp-side-menu-footer>
</swp-side-menu>
<!-- Top Bar -->
<swp-app-topbar>
<swp-topbar-search>
<i class="ph ph-magnifying-glass"></i>
<input type="text" placeholder="Søg i Salon OS..." id="globalSearch">
<kbd>⌘K</kbd>
</swp-topbar-search>
<swp-topbar-actions>
<!-- Notifications -->
<swp-topbar-btn id="notificationsBtn" title="Notifikationer">
<i class="ph ph-bell"></i>
<swp-notification-badge>3</swp-notification-badge>
</swp-topbar-btn>
<swp-topbar-divider></swp-topbar-divider>
<!-- Profile (opens drawer) -->
<swp-topbar-profile id="profileTrigger">
<swp-profile-avatar>MJ</swp-profile-avatar>
<swp-profile-info>
<swp-profile-name>Maria Jensen</swp-profile-name>
<swp-profile-role>Administrator</swp-profile-role>
</swp-profile-info>
</swp-topbar-profile>
</swp-topbar-actions>
</swp-app-topbar>
<!-- Main Content -->
<swp-main-content>
<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>4</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-package"></i>
</swp-attention-icon>
<swp-attention-content>
<swp-attention-title>Lav lagerbeholdning på Moroccanoil Balsam</swp-attention-title>
<swp-attention-desc>4 stk tilbage · sidst bestilt for 21 dage siden</swp-attention-desc>
</swp-attention-content>
<swp-attention-action>Opret bestilling</swp-attention-action>
</swp-attention-item>
<swp-attention-item class="warning">
<swp-attention-icon>
<i class="ph ph-calendar-x"></i>
</swp-attention-icon>
<swp-attention-content>
<swp-attention-title>2 kunder uden bekræftet tid i eftermiddag</swp-attention-title>
<swp-attention-desc>Line · Balayage · 13:00 · Cecilie · Klip · 15:00</swp-attention-desc>
</swp-attention-content>
<swp-attention-action>Send SMS-påmindelse</swp-attention-action>
</swp-attention-item>
<swp-attention-item class="info">
<swp-attention-icon>
<i class="ph ph-cash-register"></i>
</swp-attention-icon>
<swp-attention-content>
<swp-attention-title>Kasseafstemning for i går mangler</swp-attention-title>
<swp-attention-desc>9 kontantsalg registreret · forventet differens: 0 kr</swp-attention-desc>
</swp-attention-content>
<swp-attention-action>Afstem kasse</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>
<!-- 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>
</swp-main-content>
</swp-app-layout>
<!-- Profile Drawer -->
<swp-drawer-overlay id="drawerOverlay"></swp-drawer-overlay>
<swp-profile-drawer id="profileDrawer">
<swp-drawer-header>
<swp-drawer-title>Min profil</swp-drawer-title>
<swp-drawer-close id="drawerClose">
<i class="ph ph-x"></i>
</swp-drawer-close>
</swp-drawer-header>
<swp-drawer-content>
<swp-drawer-profile>
<swp-drawer-avatar>MJ</swp-drawer-avatar>
<swp-drawer-name>Maria Jensen</swp-drawer-name>
<swp-drawer-role>Administrator</swp-drawer-role>
<swp-drawer-email>maria@salon.dk</swp-drawer-email>
</swp-drawer-profile>
<swp-drawer-section>
<swp-drawer-section-label>Konto</swp-drawer-section-label>
<swp-drawer-item>
<i class="ph ph-user-circle"></i>
<swp-drawer-item-text>Rediger profil</swp-drawer-item-text>
<i class="ph ph-caret-right"></i>
</swp-drawer-item>
<swp-drawer-item>
<i class="ph ph-key"></i>
<swp-drawer-item-text>Skift adgangskode</swp-drawer-item-text>
<i class="ph ph-caret-right"></i>
</swp-drawer-item>
<swp-drawer-item>
<i class="ph ph-bell"></i>
<swp-drawer-item-text>Notifikationer</swp-drawer-item-text>
<swp-drawer-item-hint>3 ulæste</swp-drawer-item-hint>
</swp-drawer-item>
<swp-drawer-item id="openTodoDrawer">
<i class="ph ph-check-square"></i>
<swp-drawer-item-text>Mine opgaver</swp-drawer-item-text>
<swp-drawer-item-hint>2 i dag</swp-drawer-item-hint>
</swp-drawer-item>
</swp-drawer-section>
<swp-drawer-section>
<swp-drawer-section-label>Udseende</swp-drawer-section-label>
<swp-theme-toggle id="themeToggleDrawer">
<swp-theme-option data-theme="light" title="Lyst tema">
<i class="ph ph-sun"></i>
</swp-theme-option>
<swp-theme-option data-theme="dark" title="Mørkt tema">
<i class="ph ph-moon"></i>
</swp-theme-option>
</swp-theme-toggle>
</swp-drawer-section>
<swp-drawer-section>
<swp-drawer-section-label>Support</swp-drawer-section-label>
<swp-drawer-item>
<i class="ph ph-question"></i>
<swp-drawer-item-text>Hjælp & Support</swp-drawer-item-text>
<i class="ph ph-caret-right"></i>
</swp-drawer-item>
<swp-drawer-item>
<i class="ph ph-info"></i>
<swp-drawer-item-text>Om Salon OS</swp-drawer-item-text>
<swp-drawer-item-hint>v2.1.0</swp-drawer-item-hint>
</swp-drawer-item>
</swp-drawer-section>
</swp-drawer-content>
<swp-drawer-footer>
<swp-drawer-action class="logout">
<i class="ph ph-sign-out"></i>
Log ud
</swp-drawer-action>
</swp-drawer-footer>
</swp-profile-drawer>
<!-- Notification Drawer -->
<swp-notification-drawer id="notificationDrawer">
<swp-drawer-header>
<swp-drawer-title>Notifikationer</swp-drawer-title>
<swp-drawer-header-actions>
<swp-mark-read-btn id="markAllRead">Marker alle læst</swp-mark-read-btn>
<swp-drawer-close id="notificationDrawerClose">
<i class="ph ph-x"></i>
</swp-drawer-close>
</swp-drawer-header-actions>
</swp-drawer-header>
<swp-drawer-content>
<!-- Booking -->
<swp-notification-item data-unread="true">
<swp-notification-icon class="booking">
<i class="ph ph-calendar-check"></i>
</swp-notification-icon>
<swp-notification-content>
<swp-notification-title>Ny booking</swp-notification-title>
<swp-notification-text>Maria Hansen har booket klipning kl. 14:00</swp-notification-text>
<swp-notification-time>For 5 min siden</swp-notification-time>
</swp-notification-content>
</swp-notification-item>
<!-- Smiley/Feedback -->
<swp-notification-item data-unread="true">
<swp-notification-icon class="smiley">
<i class="ph ph-smiley"></i>
</swp-notification-icon>
<swp-notification-content>
<swp-notification-title>Kunde feedback</swp-notification-title>
<swp-notification-text>5 stjerner fra Jonas Petersen</swp-notification-text>
<swp-notification-time>For 15 min siden</swp-notification-time>
</swp-notification-content>
</swp-notification-item>
<!-- Opkald -->
<swp-notification-item data-unread="true">
<swp-notification-icon class="call">
<i class="ph ph-phone"></i>
</swp-notification-icon>
<swp-notification-content>
<swp-notification-title>Misset opkald</swp-notification-title>
<swp-notification-text>+45 12 34 56 78</swp-notification-text>
<swp-notification-time>For 1 time siden</swp-notification-time>
</swp-notification-content>
</swp-notification-item>
<!-- Mail -->
<swp-notification-item>
<swp-notification-icon class="mail">
<i class="ph ph-envelope"></i>
</swp-notification-icon>
<swp-notification-content>
<swp-notification-title>Ny mail</swp-notification-title>
<swp-notification-text>Fra: leverandoer@produkt.dk - Ordrebekræftelse</swp-notification-text>
<swp-notification-time>For 2 timer siden</swp-notification-time>
</swp-notification-content>
</swp-notification-item>
<!-- Chat -->
<swp-notification-item>
<swp-notification-icon class="chat">
<i class="ph ph-chat-circle"></i>
</swp-notification-icon>
<swp-notification-content>
<swp-notification-title>Ny besked i chat</swp-notification-title>
<swp-notification-text>Kunde: "Hej, kan jeg ændre min tid?"</swp-notification-text>
<swp-notification-time>For 3 timer siden</swp-notification-time>
</swp-notification-content>
</swp-notification-item>
<!-- Reminder -->
<swp-notification-item>
<swp-notification-icon class="reminder">
<i class="ph ph-bell-ringing"></i>
</swp-notification-icon>
<swp-notification-content>
<swp-notification-title>Påmindelse</swp-notification-title>
<swp-notification-text>Bestil varer fra Wella inden fredag</swp-notification-text>
<swp-notification-time>I går</swp-notification-time>
</swp-notification-content>
</swp-notification-item>
</swp-drawer-content>
</swp-notification-drawer>
<!-- Todo Drawer -->
<swp-todo-drawer id="todoDrawer">
<swp-drawer-header>
<swp-drawer-back id="todoDrawerBack">
<i class="ph ph-caret-left"></i>
</swp-drawer-back>
<swp-drawer-title>Mine opgaver</swp-drawer-title>
<swp-drawer-header-actions>
<swp-add-todo-btn id="addTodoBtn" title="Tilføj opgave">
<i class="ph ph-plus"></i>
</swp-add-todo-btn>
</swp-drawer-header-actions>
</swp-drawer-header>
<swp-drawer-content>
<!-- I dag -->
<swp-todo-section>
<swp-todo-section-header>
<i class="ph ph-caret-down"></i>
<swp-todo-section-title>I dag</swp-todo-section-title>
<swp-todo-section-count>3</swp-todo-section-count>
</swp-todo-section-header>
<swp-todo-items>
<swp-todo-item>
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Ring til leverandør om ordre</swp-todo-title>
<swp-todo-meta>
<swp-todo-time>
<i class="ph ph-clock"></i>
10:00
</swp-todo-time>
</swp-todo-meta>
</swp-todo-content>
</swp-todo-item>
<swp-todo-item data-completed="true">
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Bestil shampoo fra Wella</swp-todo-title>
</swp-todo-content>
</swp-todo-item>
<swp-todo-item>
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Opdater prisliste for 2025</swp-todo-title>
<swp-todo-meta>
<swp-todo-priority class="high">
<i class="ph ph-flag"></i>
Høj
</swp-todo-priority>
</swp-todo-meta>
</swp-todo-content>
</swp-todo-item>
</swp-todo-items>
</swp-todo-section>
<!-- Denne uge -->
<swp-todo-section>
<swp-todo-section-header>
<i class="ph ph-caret-down"></i>
<swp-todo-section-title>Denne uge</swp-todo-section-title>
<swp-todo-section-count>2</swp-todo-section-count>
</swp-todo-section-header>
<swp-todo-items>
<swp-todo-item>
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Rengør og vedligehold udstyr</swp-todo-title>
<swp-todo-meta>
<swp-todo-date>
<i class="ph ph-calendar"></i>
Onsdag
</swp-todo-date>
</swp-todo-meta>
</swp-todo-content>
</swp-todo-item>
<swp-todo-item>
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Medarbejdersamtale med Jonas</swp-todo-title>
<swp-todo-meta>
<swp-todo-date>
<i class="ph ph-calendar"></i>
Fredag
</swp-todo-date>
<swp-todo-time>
<i class="ph ph-clock"></i>
14:00
</swp-todo-time>
</swp-todo-meta>
</swp-todo-content>
</swp-todo-item>
</swp-todo-items>
</swp-todo-section>
<!-- Udført -->
<swp-todo-section class="collapsed">
<swp-todo-section-header>
<i class="ph ph-caret-down"></i>
<swp-todo-section-title>Udført</swp-todo-section-title>
<swp-todo-section-count>3</swp-todo-section-count>
</swp-todo-section-header>
<swp-todo-items>
<swp-todo-item data-completed="true">
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Send faktura til kunde</swp-todo-title>
</swp-todo-content>
</swp-todo-item>
<swp-todo-item data-completed="true">
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Opdater åbningstider på Google</swp-todo-title>
</swp-todo-content>
</swp-todo-item>
<swp-todo-item data-completed="true">
<swp-todo-checkbox>
<i class="ph ph-check"></i>
</swp-todo-checkbox>
<swp-todo-content>
<swp-todo-title>Bestil nye håndklæder</swp-todo-title>
</swp-todo-content>
</swp-todo-item>
</swp-todo-items>
</swp-todo-section>
</swp-drawer-content>
</swp-todo-drawer>
<!-- New Todo Drawer - slides from left of todo drawer -->
<swp-new-todo-drawer id="newTodoDrawer">
<swp-drawer-header>
<swp-drawer-back id="newTodoDrawerBack">
<i class="ph ph-caret-left"></i>
</swp-drawer-back>
<swp-drawer-title>Ny opgave</swp-drawer-title>
</swp-drawer-header>
<swp-drawer-content>
<!-- Titel -->
<swp-form-field>
<swp-section-label>Opgave</swp-section-label>
<input type="text" placeholder="Hvad skal du huske?" id="newTodoTitle">
</swp-form-field>
<!-- Dato & Tid -->
<swp-form-row>
<swp-form-field>
<swp-section-label>Dato</swp-section-label>
<input type="date" id="newTodoDate">
</swp-form-field>
<swp-form-field>
<swp-section-label>Tid</swp-section-label>
<input type="time" id="newTodoTime">
</swp-form-field>
</swp-form-row>
<!-- Prioritet -->
<swp-form-field>
<swp-section-label>Prioritet</swp-section-label>
<select id="newTodoPriority">
<option value="normal">Normal</option>
<option value="high">Høj prioritet</option>
<option value="low">Lav prioritet</option>
</select>
</swp-form-field>
<!-- Synlighed -->
<swp-form-field>
<swp-section-label>Synlighed</swp-section-label>
<swp-visibility-toggle>
<swp-visibility-option class="active" data-value="personal">
<i class="ph ph-user"></i>
Kun mig
</swp-visibility-option>
<swp-visibility-option data-value="shared">
<i class="ph ph-users"></i>
Alle
</swp-visibility-option>
</swp-visibility-toggle>
</swp-form-field>
<!-- Noter -->
<swp-form-field>
<swp-section-label>Noter</swp-section-label>
<textarea placeholder="Tilføj noter..." id="newTodoNotes"></textarea>
</swp-form-field>
</swp-drawer-content>
<swp-drawer-footer>
<swp-btn class="secondary" id="cancelNewTodo">Annuller</swp-btn>
<swp-btn class="primary" id="saveNewTodo">Gem opgave</swp-btn>
</swp-drawer-footer>
</swp-new-todo-drawer>
<!-- Lock Screen -->
<swp-lock-screen id="lockScreen">
<swp-lock-content>
<swp-lock-icon>
<i class="ph ph-lock"></i>
</swp-lock-icon>
<swp-lock-title>Skærm låst</swp-lock-title>
<swp-lock-subtitle>Indtast PIN for at fortsætte</swp-lock-subtitle>
<swp-lock-time id="lockTime">Låst kl. 14:32</swp-lock-time>
<swp-pin-input id="pinInput">
<swp-pin-digit></swp-pin-digit>
<swp-pin-digit></swp-pin-digit>
<swp-pin-digit></swp-pin-digit>
<swp-pin-digit></swp-pin-digit>
</swp-pin-input>
<swp-pin-keypad id="pinKeypad">
<swp-pin-key data-key="1">1</swp-pin-key>
<swp-pin-key data-key="2">2</swp-pin-key>
<swp-pin-key data-key="3">3</swp-pin-key>
<swp-pin-key data-key="4">4</swp-pin-key>
<swp-pin-key data-key="5">5</swp-pin-key>
<swp-pin-key data-key="6">6</swp-pin-key>
<swp-pin-key data-key="7">7</swp-pin-key>
<swp-pin-key data-key="8">8</swp-pin-key>
<swp-pin-key data-key="9">9</swp-pin-key>
<swp-pin-key class="empty"></swp-pin-key>
<swp-pin-key data-key="0">0</swp-pin-key>
<swp-pin-key class="backspace" data-key="backspace">
<i class="ph ph-backspace"></i>
</swp-pin-key>
</swp-pin-keypad>
<swp-lock-hint>Indtast 4 cifre for at låse op</swp-lock-hint>
</swp-lock-content>
</swp-lock-screen>
<!-- Menu Tooltip (Popover API) -->
<div id="menuTooltip" popover="manual" class="swp-menu-tooltip"></div>
<script>
// Elements
const root = document.documentElement;
const profileTrigger = document.getElementById('profileTrigger');
const profileDrawer = document.getElementById('profileDrawer');
const drawerOverlay = document.getElementById('drawerOverlay');
const drawerClose = document.getElementById('drawerClose');
// ==========================================
// SIDE MENU COLLAPSE
// ==========================================
const menuToggle = document.getElementById('menuToggle');
const appLayout = document.querySelector('swp-app-layout');
menuToggle.addEventListener('click', () => {
appLayout.classList.toggle('menu-collapsed');
});
// ==========================================
// MENU TOOLTIPS (Popover API)
// ==========================================
const menuTooltip = document.getElementById('menuTooltip');
const menuItems = document.querySelectorAll('swp-side-menu-item[data-tooltip]');
menuItems.forEach(item => {
item.addEventListener('mouseenter', () => {
if (!appLayout.classList.contains('menu-collapsed')) return;
const rect = item.getBoundingClientRect();
menuTooltip.textContent = item.dataset.tooltip;
menuTooltip.style.left = `${rect.right + 8}px`;
menuTooltip.style.top = `${rect.top + rect.height / 2}px`;
menuTooltip.style.transform = 'translateY(-50%)';
menuTooltip.showPopover();
});
item.addEventListener('mouseleave', () => {
menuTooltip.hidePopover();
});
});
// ==========================================
// DRAWERS (Profile, Notifications & Todo)
// ==========================================
const notificationDrawer = document.getElementById('notificationDrawer');
const notificationDrawerClose = document.getElementById('notificationDrawerClose');
const notificationsBtn = document.getElementById('notificationsBtn');
const markAllReadBtn = document.getElementById('markAllRead');
const notificationBadge = document.querySelector('swp-notification-badge');
const todoDrawer = document.getElementById('todoDrawer');
const todoDrawerBack = document.getElementById('todoDrawerBack');
const openTodoDrawerBtn = document.getElementById('openTodoDrawer');
const addTodoBtn = document.getElementById('addTodoBtn');
const newTodoDrawer = document.getElementById('newTodoDrawer');
const newTodoDrawerBack = document.getElementById('newTodoDrawerBack');
const cancelNewTodoBtn = document.getElementById('cancelNewTodo');
const saveNewTodoBtn = document.getElementById('saveNewTodo');
// Open profile drawer
function openProfileDrawer() {
closeTodoDrawer();
closeNotificationDrawer();
profileDrawer.classList.add('open');
drawerOverlay.classList.add('open');
document.body.style.overflow = 'hidden';
}
// Close profile drawer
function closeProfileDrawer() {
profileDrawer.classList.remove('open');
drawerOverlay.classList.remove('open');
document.body.style.overflow = '';
}
// Open notification drawer
function openNotificationDrawer() {
closeTodoDrawer();
closeProfileDrawer();
notificationDrawer.classList.add('open');
drawerOverlay.classList.add('open');
document.body.style.overflow = 'hidden';
}
// Close notification drawer
function closeNotificationDrawer() {
notificationDrawer.classList.remove('open');
drawerOverlay.classList.remove('open');
document.body.style.overflow = '';
}
// Open todo drawer (on top of profile drawer)
function openTodoDrawer() {
todoDrawer.classList.add('open');
}
// Close todo drawer
function closeTodoDrawer() {
todoDrawer.classList.remove('open');
closeNewTodoDrawer();
}
// Open new todo drawer (on top of todo drawer)
function openNewTodoDrawer() {
newTodoDrawer.classList.add('open');
}
// Close new todo drawer
function closeNewTodoDrawer() {
newTodoDrawer.classList.remove('open');
}
// Close all drawers
function closeAllDrawers() {
closeProfileDrawer();
closeNotificationDrawer();
closeTodoDrawer();
}
// Profile trigger opens drawer
profileTrigger.addEventListener('click', openProfileDrawer);
// Notifications button opens drawer
notificationsBtn.addEventListener('click', openNotificationDrawer);
// Todo drawer from profile
openTodoDrawerBtn.addEventListener('click', openTodoDrawer);
// Todo drawer back button (returns to profile)
todoDrawerBack.addEventListener('click', closeTodoDrawer);
// Add todo button opens new todo drawer
addTodoBtn.addEventListener('click', openNewTodoDrawer);
// New todo drawer back/cancel buttons
newTodoDrawerBack.addEventListener('click', closeNewTodoDrawer);
cancelNewTodoBtn.addEventListener('click', closeNewTodoDrawer);
// Save new todo (demo - just closes drawer)
saveNewTodoBtn.addEventListener('click', () => {
// In a real app, save the todo here
closeNewTodoDrawer();
});
// Visibility toggle
const visibilityOptions = document.querySelectorAll('swp-visibility-option');
visibilityOptions.forEach(option => {
option.addEventListener('click', () => {
visibilityOptions.forEach(o => o.classList.remove('active'));
option.classList.add('active');
});
});
// Close on overlay click
drawerOverlay.addEventListener('click', closeAllDrawers);
// Close on X buttons
drawerClose.addEventListener('click', closeProfileDrawer);
notificationDrawerClose.addEventListener('click', closeNotificationDrawer);
// Close on Escape
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') closeAllDrawers();
});
// Mark all as read
markAllReadBtn.addEventListener('click', () => {
const unreadItems = notificationDrawer.querySelectorAll('swp-notification-item[data-unread="true"]');
unreadItems.forEach(item => {
item.removeAttribute('data-unread');
});
notificationBadge.style.display = 'none';
});
// ==========================================
// TODO FUNCTIONALITY
// ==========================================
// Toggle todo completion
todoDrawer.addEventListener('click', (e) => {
const todoItem = e.target.closest('swp-todo-item');
const checkbox = e.target.closest('swp-todo-checkbox');
if (checkbox && todoItem) {
const isCompleted = todoItem.dataset.completed === 'true';
if (isCompleted) {
todoItem.removeAttribute('data-completed');
} else {
todoItem.dataset.completed = 'true';
}
}
// Toggle section collapse
const sectionHeader = e.target.closest('swp-todo-section-header');
if (sectionHeader) {
const section = sectionHeader.closest('swp-todo-section');
section.classList.toggle('collapsed');
}
});
// Theme toggle functionality
const themeOptions = document.querySelectorAll('swp-theme-option');
function isDarkMode() {
return root.classList.contains('dark-mode') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches && !root.classList.contains('light-mode'));
}
function updateThemeToggle() {
const darkActive = isDarkMode();
themeOptions.forEach(option => {
const theme = option.dataset.theme;
if ((theme === 'dark' && darkActive) || (theme === 'light' && !darkActive)) {
option.classList.add('active');
} else {
option.classList.remove('active');
}
});
}
function setTheme(theme) {
if (theme === 'dark') {
root.classList.add('dark-mode');
root.classList.remove('light-mode');
} else {
root.classList.add('light-mode');
root.classList.remove('dark-mode');
}
updateThemeToggle();
}
// Initialize theme toggle state
updateThemeToggle();
// Theme option clicks
themeOptions.forEach(option => {
option.addEventListener('click', () => {
setTheme(option.dataset.theme);
});
});
// Keyboard shortcut for search (Cmd/Ctrl + K)
document.addEventListener('keydown', (e) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
document.getElementById('globalSearch').focus();
}
});
// ==========================================
// LOCK SCREEN
// ==========================================
const lockScreen = document.getElementById('lockScreen');
const pinInput = document.getElementById('pinInput');
const pinKeypad = document.getElementById('pinKeypad');
const lockBtn = document.querySelector('swp-side-menu-action.lock');
const pinDigits = pinInput.querySelectorAll('swp-pin-digit');
const lockTimeEl = document.getElementById('lockTime');
let currentPin = '';
// Show lock screen
function showLockScreen() {
closeAllDrawers();
lockScreen.classList.add('active');
document.body.style.overflow = 'hidden';
currentPin = '';
updatePinDisplay();
// Set lock time
const now = new Date();
const hours = now.getHours().toString().padStart(2, '0');
const minutes = now.getMinutes().toString().padStart(2, '0');
lockTimeEl.textContent = `Låst kl. ${hours}:${minutes}`;
}
// Hide lock screen
function hideLockScreen() {
lockScreen.classList.remove('active');
document.body.style.overflow = '';
currentPin = '';
updatePinDisplay();
}
// Update PIN display
function updatePinDisplay() {
pinDigits.forEach((digit, index) => {
digit.classList.remove('filled', 'error');
if (index < currentPin.length) {
digit.textContent = '•';
digit.classList.add('filled');
} else {
digit.textContent = '';
}
});
}
// Show error animation
function showPinError() {
pinDigits.forEach(digit => {
digit.classList.add('error');
});
setTimeout(() => {
currentPin = '';
updatePinDisplay();
}, 400);
}
const correctPin = '3911';
// Handle PIN key press
function handlePinKey(key) {
if (key === 'backspace') {
currentPin = currentPin.slice(0, -1);
updatePinDisplay();
return;
}
if (currentPin.length >= 4) return;
currentPin += key;
updatePinDisplay();
// Check if 4 digits entered
if (currentPin.length === 4) {
setTimeout(() => {
if (currentPin === correctPin) {
hideLockScreen();
} else {
showPinError();
}
}, 200);
}
}
// Lock button click
lockBtn.addEventListener('click', showLockScreen);
// Keypad clicks
pinKeypad.addEventListener('click', (e) => {
const key = e.target.closest('swp-pin-key');
if (!key || key.classList.contains('empty')) return;
handlePinKey(key.dataset.key);
});
// Keyboard support for PIN entry
document.addEventListener('keydown', (e) => {
// Alt+L to lock screen
if (e.altKey && e.key === 'x') {
e.preventDefault();
showLockScreen();
return;
}
if (!lockScreen.classList.contains('active')) return;
if (e.key >= '0' && e.key <= '9') {
handlePinKey(e.key);
} else if (e.key === 'Backspace') {
handlePinKey('backspace');
}
});
// ==========================================
// DASHBOARD FUNCTIONALITY
// ==========================================
// Update current time
function updateDashboardTime() {
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}`;
}
}
updateDashboardTime();
setInterval(updateDashboardTime, 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);
});
});
</script>
</body>
</html>