Compare commits
10 commits
4d7e1ecbd5
...
dcd6ddcdeb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dcd6ddcdeb | ||
|
|
ea3ecdfb68 | ||
|
|
51f3b92d69 | ||
|
|
435d9f11b7 | ||
|
|
eba6bd646d | ||
|
|
33804d002e | ||
|
|
1b25978d9b | ||
|
|
38e9243bcd | ||
|
|
dc2bab5702 | ||
|
|
7aaa475a14 |
184
.gitignore
vendored
|
|
@ -1,7 +1,4 @@
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
## .NET / Visual Studio gitignore
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
|
||||||
|
|
||||||
# User-specific files
|
# User-specific files
|
||||||
*.rsuser
|
*.rsuser
|
||||||
|
|
@ -10,12 +7,6 @@
|
||||||
*.userosscache
|
*.userosscache
|
||||||
*.sln.docstates
|
*.sln.docstates
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
# Build results
|
||||||
[Dd]ebug/
|
[Dd]ebug/
|
||||||
[Dd]ebugPublic/
|
[Dd]ebugPublic/
|
||||||
|
|
@ -32,13 +23,8 @@ bld/
|
||||||
[Ll]og/
|
[Ll]og/
|
||||||
[Ll]ogs/
|
[Ll]ogs/
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
# Visual Studio cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
|
|
@ -49,11 +35,6 @@ Generated\ Files/
|
||||||
TestResult.xml
|
TestResult.xml
|
||||||
nunit-*.xml
|
nunit-*.xml
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
# Benchmark Results
|
||||||
BenchmarkDotNet.Artifacts/
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
|
@ -62,16 +43,10 @@ project.lock.json
|
||||||
project.fragment.lock.json
|
project.fragment.lock.json
|
||||||
artifacts/
|
artifacts/
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
# StyleCop
|
||||||
StyleCopReport.xml
|
StyleCopReport.xml
|
||||||
|
|
||||||
# Files built by Visual Studio
|
# Files built by Visual Studio
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
*.ilk
|
||||||
*.meta
|
*.meta
|
||||||
*.obj
|
*.obj
|
||||||
|
|
@ -97,9 +72,6 @@ StyleCopReport.xml
|
||||||
*.svclog
|
*.svclog
|
||||||
*.scc
|
*.scc
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
# Visual C++ cache files
|
||||||
ipch/
|
ipch/
|
||||||
*.aps
|
*.aps
|
||||||
|
|
@ -123,25 +95,22 @@ ipch/
|
||||||
# TFS 2012 Local Workspace
|
# TFS 2012 Local Workspace
|
||||||
$tf/
|
$tf/
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
# ReSharper
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
_ReSharper*/
|
||||||
*.[Rr]e[Ss]harper
|
*.[Rr]e[Ss]harper
|
||||||
*.DotSettings.user
|
*.DotSettings.user
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
# TeamCity
|
||||||
_TeamCity*
|
_TeamCity*
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
# DotCover
|
||||||
*.dotCover
|
*.dotCover
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
# AxoCover
|
||||||
.axoCover/*
|
.axoCover/*
|
||||||
!.axoCover/settings.json
|
!.axoCover/settings.json
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
# Coverlet
|
||||||
coverage*.json
|
coverage*.json
|
||||||
coverage*.xml
|
coverage*.xml
|
||||||
coverage*.info
|
coverage*.info
|
||||||
|
|
@ -155,53 +124,23 @@ _NCrunch_*
|
||||||
.*crunch*.local.xml
|
.*crunch*.local.xml
|
||||||
nCrunchTemp_*
|
nCrunchTemp_*
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
# Click-Once directory
|
||||||
publish/
|
publish/
|
||||||
|
|
||||||
# Publish Web Output
|
# Publish Web Output
|
||||||
*.[Pp]ublish.xml
|
*.[Pp]ublish.xml
|
||||||
*.azurePubxml
|
*.azurePubxml
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
*.pubxml
|
||||||
*.publishproj
|
*.publishproj
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
# Microsoft Azure Web App publish settings
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
PublishScripts/
|
||||||
|
|
||||||
# NuGet Packages
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
*.snupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
**/[Pp]ackages/*
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
!**/[Pp]ackages/build/
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
*.nuget.props
|
||||||
*.nuget.targets
|
*.nuget.targets
|
||||||
|
|
||||||
|
|
@ -213,19 +152,8 @@ csx/
|
||||||
ecf/
|
ecf/
|
||||||
rcf/
|
rcf/
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
# Visual Studio cache files
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
*.[Cc]ache
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
# Others
|
# Others
|
||||||
|
|
@ -237,22 +165,8 @@ ClientBin/
|
||||||
*.jfm
|
*.jfm
|
||||||
*.pfx
|
*.pfx
|
||||||
*.publishsettings
|
*.publishsettings
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
# Backup & report files from converting an old project file
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
_UpgradeReport_Files/
|
||||||
Backup*/
|
Backup*/
|
||||||
UpgradeLog*.XML
|
UpgradeLog*.XML
|
||||||
|
|
@ -265,87 +179,15 @@ ServiceFabricBackup/
|
||||||
*.ldf
|
*.ldf
|
||||||
*.ndf
|
*.ndf
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
# Microsoft Fakes
|
||||||
FakesAssemblies/
|
FakesAssemblies/
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
# Node.js (for TypeScript frontend)
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
node_modules/
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
# MSBuild Binary and Structured Log
|
||||||
*.binlog
|
*.binlog
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
# Local History for Visual Studio
|
||||||
.localhistory/
|
.localhistory/
|
||||||
|
|
||||||
|
|
@ -355,20 +197,14 @@ healthchecksdb
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
MigrationBackup/
|
MigrationBackup/
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
# Fody - auto-generated XML schema
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
|
|
||||||
nul
|
nul
|
||||||
|
|
||||||
|
# Project-specific
|
||||||
tmpclaude*
|
tmpclaude*
|
||||||
PlanTempus.Application/tmpclaude*
|
PlanTempus.Application/tmpclaude*
|
||||||
|
|
||||||
|
|
||||||
PlanTempus.Application/wwwroot/js/app.js
|
PlanTempus.Application/wwwroot/js/app.js
|
||||||
|
|
||||||
PlanTempus.Application/wwwroot/js/app.js.map
|
PlanTempus.Application/wwwroot/js/app.js.map
|
||||||
|
|
||||||
PlanTempus.Application/wwwroot/lib/*
|
PlanTempus.Application/wwwroot/lib/*
|
||||||
|
|
|
||||||
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>
|
||||||
|
|
@ -2,7 +2,16 @@
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"allow": [
|
"allow": [
|
||||||
"WebSearch",
|
"WebSearch",
|
||||||
"Bash(npm run build:*)"
|
"Bash(npm run build:*)",
|
||||||
|
"Bash(node -e:*)",
|
||||||
|
"Bash(dir /s /b \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\")",
|
||||||
|
"Bash(findstr:*)",
|
||||||
|
"Bash(dir \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\wwwroot\\\\*.html\")",
|
||||||
|
"Bash(dir /s /b \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\Features\\\\OnlineBooking\\\\*.cs\" \"C:\\\\Users\\\\Janus Knudsen\\\\source\\\\swp-repos\\\\PlanTempus\\\\PlanTempus.Application\\\\Features\\\\OnlineBooking\\\\*.cshtml\")",
|
||||||
|
"Bash(npm view:*)",
|
||||||
|
"Bash(tar:*)",
|
||||||
|
"Bash(find:*)",
|
||||||
|
"Bash(npm install:*)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
2
PlanTempus.Application/.npmrc
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
@novadi:registry=http://npm.jarjarbinks:4873
|
||||||
|
registry=http://npm.jarjarbinks:4873
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@model PlanTempus.Application.Features.Accounts.Pages.PaymentModel
|
@model PlanTempus.Application.Features.Accounts.Pages.PaymentModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Betaling";
|
ViewData["Title"] = "Betaling";
|
||||||
Layout = "/Features/_Shared/Pages/_AuthLayout.cshtml";
|
Layout = "/Features/Shared/Pages/_AuthLayout.cshtml";
|
||||||
|
|
||||||
var plan = Model.SelectedPlan;
|
var plan = Model.SelectedPlan;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@model PlanTempus.Application.Features.Accounts.Pages.PricingModel
|
@model PlanTempus.Application.Features.Accounts.Pages.PricingModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = "Vælg abonnement";
|
ViewData["Title"] = "Vælg abonnement";
|
||||||
Layout = "/Features/_Shared/Pages/_AuthLayout.cshtml";
|
Layout = "/Features/Shared/Pages/_AuthLayout.cshtml";
|
||||||
}
|
}
|
||||||
|
|
||||||
<swp-pricing-page>
|
<swp-pricing-page>
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@model PlanTempus.Application.Features.Accounts.Pages.SignupModel
|
@model PlanTempus.Application.Features.Accounts.Pages.SignupModel
|
||||||
@{
|
@{
|
||||||
ViewData["Title"] = Model.SelectedPlan.IsContactSales ? "Kontakt salg" : "Opret konto";
|
ViewData["Title"] = Model.SelectedPlan.IsContactSales ? "Kontakt salg" : "Opret konto";
|
||||||
Layout = "/Features/_Shared/Pages/_AuthLayout.cshtml";
|
Layout = "/Features/Shared/Pages/_AuthLayout.cshtml";
|
||||||
|
|
||||||
var plan = Model.SelectedPlan;
|
var plan = Model.SelectedPlan;
|
||||||
var badgeClass = plan.IsContactSales ? plan.BadgeClass : (plan.IsFree ? plan.BadgeClass : "selected");
|
var badgeClass = plan.IsContactSales ? plan.BadgeClass : (plan.IsFree ? plan.BadgeClass : "selected");
|
||||||
|
|
|
||||||
37
PlanTempus.Application/Features/Calendar/Pages/Index.cshtml
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
@page "/kalender"
|
||||||
|
@using PlanTempus.Application.Features.Calendar.Pages
|
||||||
|
@model PlanTempus.Application.Features.Calendar.Pages.IndexModel
|
||||||
|
@{
|
||||||
|
ViewData["Title"] = "Kalender";
|
||||||
|
}
|
||||||
|
|
||||||
|
@section Styles {
|
||||||
|
<link rel="stylesheet" href="~/lib/calendar/dist/css/calendar.css" />
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="calendar-wrapper">
|
||||||
|
<swp-calendar-container>
|
||||||
|
<swp-time-axis>
|
||||||
|
<swp-header-spacer></swp-header-spacer>
|
||||||
|
<swp-time-axis-content id="time-axis"></swp-time-axis-content>
|
||||||
|
</swp-time-axis>
|
||||||
|
<swp-grid-container>
|
||||||
|
<swp-header-viewport>
|
||||||
|
<swp-header-track>
|
||||||
|
<swp-calendar-header></swp-calendar-header>
|
||||||
|
</swp-header-track>
|
||||||
|
<swp-header-drawer></swp-header-drawer>
|
||||||
|
</swp-header-viewport>
|
||||||
|
<swp-content-viewport>
|
||||||
|
<swp-content-track>
|
||||||
|
<swp-scrollable-content>
|
||||||
|
<swp-time-grid>
|
||||||
|
<swp-grid-lines></swp-grid-lines>
|
||||||
|
<swp-day-columns></swp-day-columns>
|
||||||
|
</swp-time-grid>
|
||||||
|
</swp-scrollable-content>
|
||||||
|
</swp-content-track>
|
||||||
|
</swp-content-viewport>
|
||||||
|
</swp-grid-container>
|
||||||
|
</swp-calendar-container>
|
||||||
|
</div>
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
|
|
||||||
|
namespace PlanTempus.Application.Features.Calendar.Pages;
|
||||||
|
|
||||||
|
public class IndexModel : PageModel
|
||||||
|
{
|
||||||
|
public void OnGet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
<swp-row-detail-actions>
|
<swp-row-detail-actions>
|
||||||
<swp-btn class="secondary" data-zreport="043">
|
<swp-btn class="secondary" data-zreport="043">
|
||||||
<i class="ph ph-file-pdf"></i>
|
<i class="ph ph-file-pdf"></i>
|
||||||
<span localize="cash.table.downloadPdf">Download PDF</span>
|
<span localize="cash.table.downloadPdf">Download Z-Rapport</span>
|
||||||
</swp-btn>
|
</swp-btn>
|
||||||
<swp-btn class="primary">
|
<swp-btn class="primary">
|
||||||
<i class="ph ph-list-bullets"></i>
|
<i class="ph ph-list-bullets"></i>
|
||||||
|
|
@ -95,7 +95,7 @@
|
||||||
<swp-row-detail-actions>
|
<swp-row-detail-actions>
|
||||||
<swp-btn class="secondary" data-zreport="042">
|
<swp-btn class="secondary" data-zreport="042">
|
||||||
<i class="ph ph-file-pdf"></i>
|
<i class="ph ph-file-pdf"></i>
|
||||||
<span localize="cash.table.downloadPdf">Download PDF</span>
|
<span localize="cash.table.downloadPdf">Download Z-Rapport</span>
|
||||||
</swp-btn>
|
</swp-btn>
|
||||||
<swp-btn class="primary">
|
<swp-btn class="primary">
|
||||||
<i class="ph ph-list-bullets"></i>
|
<i class="ph ph-list-bullets"></i>
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
<swp-row-detail-actions>
|
<swp-row-detail-actions>
|
||||||
<swp-btn class="secondary" data-zreport="041">
|
<swp-btn class="secondary" data-zreport="041">
|
||||||
<i class="ph ph-file-pdf"></i>
|
<i class="ph ph-file-pdf"></i>
|
||||||
<span localize="cash.table.downloadPdf">Download PDF</span>
|
<span localize="cash.table.downloadPdf">Download Z-Rapport</span>
|
||||||
</swp-btn>
|
</swp-btn>
|
||||||
<swp-btn class="primary">
|
<swp-btn class="primary">
|
||||||
<i class="ph ph-list-bullets"></i>
|
<i class="ph ph-list-bullets"></i>
|
||||||
|
|
@ -157,7 +157,7 @@
|
||||||
<swp-row-detail-actions>
|
<swp-row-detail-actions>
|
||||||
<swp-btn class="secondary" data-zreport="040">
|
<swp-btn class="secondary" data-zreport="040">
|
||||||
<i class="ph ph-file-pdf"></i>
|
<i class="ph ph-file-pdf"></i>
|
||||||
<span localize="cash.table.downloadPdf">Download PDF</span>
|
<span localize="cash.table.downloadPdf">Download Z_Rapport</span>
|
||||||
</swp-btn>
|
</swp-btn>
|
||||||
<swp-btn class="primary">
|
<swp-btn class="primary">
|
||||||
<i class="ph ph-list-bullets"></i>
|
<i class="ph ph-list-bullets"></i>
|
||||||
|
|
|
||||||