Enhances UI with drag-and-drop card functionality
Adds drag and drop interaction for rearranging cards on the customer and service detail pages Improves user experience by allowing flexible card positioning Implements dynamic drop indicators and column management Supports intuitive card movement between columns
This commit is contained in:
parent
7965e8e753
commit
9f46ff8824
7 changed files with 2565 additions and 35 deletions
4
wwwroot/icons/booking.svg
Normal file
4
wwwroot/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
wwwroot/icons/check-in-calendar.svg
Normal file
4
wwwroot/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
wwwroot/icons/comment-sms.svg
Normal file
2
wwwroot/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
wwwroot/icons/created.svg
Normal file
1
wwwroot/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
wwwroot/icons/unlock.svg
Normal file
2
wwwroot/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 |
|
|
@ -1633,6 +1633,16 @@
|
|||
font-size: 11px;
|
||||
}
|
||||
|
||||
swp-activity-filter .filter-icon img {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
filter: invert(45%) sepia(0%) saturate(0%) brightness(90%);
|
||||
}
|
||||
|
||||
swp-activity-filter.active .filter-icon img {
|
||||
filter: brightness(0) invert(1);
|
||||
}
|
||||
|
||||
/* Activity Timeline */
|
||||
swp-activity-timeline {
|
||||
display: block;
|
||||
|
|
@ -1687,39 +1697,65 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
swp-activity-icon img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
swp-activity-icon.system {
|
||||
background: var(--color-background);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
swp-activity-icon.system img {
|
||||
filter: invert(45%) sepia(0%) saturate(0%) brightness(90%);
|
||||
}
|
||||
|
||||
swp-activity-icon.customer {
|
||||
background: color-mix(in srgb, var(--color-blue) 15%, white);
|
||||
color: var(--color-blue);
|
||||
}
|
||||
|
||||
swp-activity-icon.customer img {
|
||||
filter: invert(32%) sepia(98%) saturate(1234%) hue-rotate(196deg) brightness(93%) contrast(92%);
|
||||
}
|
||||
|
||||
swp-activity-icon.employee {
|
||||
background: color-mix(in srgb, var(--color-teal) 15%, white);
|
||||
color: var(--color-teal);
|
||||
}
|
||||
|
||||
swp-activity-icon.employee img {
|
||||
filter: invert(32%) sepia(98%) saturate(1234%) hue-rotate(152deg) brightness(93%) contrast(92%);
|
||||
}
|
||||
|
||||
swp-activity-icon.booking {
|
||||
background: color-mix(in srgb, var(--color-purple) 15%, white);
|
||||
color: var(--color-purple);
|
||||
}
|
||||
|
||||
swp-activity-icon.booking img {
|
||||
filter: invert(45%) sepia(70%) saturate(2000%) hue-rotate(235deg) brightness(90%) contrast(95%);
|
||||
}
|
||||
|
||||
swp-activity-icon.communication {
|
||||
background: color-mix(in srgb, var(--color-amber) 15%, white);
|
||||
color: #b8860b;
|
||||
}
|
||||
|
||||
swp-activity-icon.communication img {
|
||||
filter: invert(55%) sepia(80%) saturate(500%) hue-rotate(10deg) brightness(95%) contrast(95%);
|
||||
}
|
||||
|
||||
swp-activity-icon.payment {
|
||||
background: color-mix(in srgb, var(--color-green) 15%, white);
|
||||
color: var(--color-green);
|
||||
}
|
||||
|
||||
swp-activity-icon.payment img {
|
||||
filter: invert(45%) sepia(70%) saturate(500%) hue-rotate(90deg) brightness(95%) contrast(90%);
|
||||
}
|
||||
|
||||
swp-activity-icon.warning {
|
||||
background: color-mix(in srgb, var(--color-red) 15%, white);
|
||||
color: var(--color-red);
|
||||
}
|
||||
|
||||
swp-activity-icon.warning img {
|
||||
filter: invert(30%) sepia(90%) saturate(2000%) hue-rotate(340deg) brightness(90%) contrast(95%);
|
||||
}
|
||||
|
||||
swp-activity-content {
|
||||
|
|
@ -1834,6 +1870,94 @@
|
|||
swp-activity-load-more:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ==========================================
|
||||
DRAG & DROP CARDS
|
||||
========================================== */
|
||||
|
||||
/* Draggable Card */
|
||||
swp-card[draggable="true"] {
|
||||
position: relative;
|
||||
transition: transform 200ms ease, box-shadow 200ms ease, opacity 200ms ease;
|
||||
}
|
||||
|
||||
swp-card[draggable="true"]:hover {
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
swp-card[draggable="true"].dragging {
|
||||
opacity: 0.5;
|
||||
transform: scale(0.98);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Drag Handle */
|
||||
swp-drag-handle {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
color: var(--color-text-secondary);
|
||||
opacity: 0;
|
||||
transition: opacity 150ms ease, background 150ms ease;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
swp-drag-handle svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
swp-card[draggable="true"]:hover swp-drag-handle {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
swp-drag-handle:hover {
|
||||
opacity: 1 !important;
|
||||
background: var(--color-background);
|
||||
}
|
||||
|
||||
/* Column Drop Zones */
|
||||
swp-card-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 200px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Drop zone indicator element - dynamically inserted */
|
||||
swp-drop-indicator {
|
||||
display: block;
|
||||
height: 60px;
|
||||
background: color-mix(in srgb, var(--color-teal) 8%, transparent);
|
||||
border: 2px dashed var(--color-teal);
|
||||
border-radius: 8px;
|
||||
margin: 8px 0;
|
||||
transition: opacity 150ms ease;
|
||||
}
|
||||
|
||||
/* Column empty state drop zone */
|
||||
swp-card-column.drag-over-empty {
|
||||
background: color-mix(in srgb, var(--color-teal) 5%, white);
|
||||
border: 2px dashed var(--color-teal);
|
||||
border-radius: 8px;
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
/* Cards have no gap by default */
|
||||
swp-card-column swp-card {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
swp-card-column swp-card:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -1912,8 +2036,9 @@
|
|||
<swp-tab-content class="active" data-tab="overview">
|
||||
<div class="grid-2">
|
||||
<!-- Left Column -->
|
||||
<div>
|
||||
<swp-card>
|
||||
<swp-card-column data-column="left">
|
||||
<swp-card draggable="true" data-card-id="kontakt">
|
||||
<swp-drag-handle><svg viewBox="0 0 24 24"><path d="M13 6v5h5V8l4 4-4 4v-3h-5v5h3l-4 4-4-4h3v-5H6v3l-4-4 4-4v3h5V6H8l4-4 4 4h-3z"/></svg></swp-drag-handle>
|
||||
<swp-section-label>Kontaktoplysninger</swp-section-label>
|
||||
<swp-edit-section>
|
||||
<swp-edit-row>
|
||||
|
|
@ -1935,7 +2060,8 @@
|
|||
</swp-edit-section>
|
||||
</swp-card>
|
||||
|
||||
<swp-card>
|
||||
<swp-card draggable="true" data-card-id="profil">
|
||||
<swp-drag-handle><svg viewBox="0 0 24 24"><path d="M13 6v5h5V8l4 4-4 4v-3h-5v5h3l-4 4-4-4h3v-5H6v3l-4-4 4-4v3h5V6H8l4-4 4 4h-3z"/></svg></swp-drag-handle>
|
||||
<swp-section-label>Profil</swp-section-label>
|
||||
<swp-profile-boxes>
|
||||
<swp-profile-box>
|
||||
|
|
@ -1956,11 +2082,12 @@
|
|||
</swp-profile-box>
|
||||
</swp-profile-boxes>
|
||||
</swp-card>
|
||||
</div>
|
||||
</swp-card-column>
|
||||
|
||||
<!-- Right Column -->
|
||||
<div>
|
||||
<swp-card>
|
||||
<swp-card-column data-column="right">
|
||||
<swp-card draggable="true" data-card-id="marketing">
|
||||
<swp-drag-handle><svg viewBox="0 0 24 24"><path d="M13 6v5h5V8l4 4-4 4v-3h-5v5h3l-4 4-4-4h3v-5H6v3l-4-4 4-4v3h5V6H8l4-4 4 4h-3z"/></svg></swp-drag-handle>
|
||||
<swp-section-label>Marketing</swp-section-label>
|
||||
<swp-toggle-row>
|
||||
<swp-toggle-label>Email marketing</swp-toggle-label>
|
||||
|
|
@ -1978,7 +2105,8 @@
|
|||
</swp-toggle-row>
|
||||
</swp-card>
|
||||
|
||||
<swp-card>
|
||||
<swp-card draggable="true" data-card-id="praeferencer">
|
||||
<swp-drag-handle><svg viewBox="0 0 24 24"><path d="M13 6v5h5V8l4 4-4 4v-3h-5v5h3l-4 4-4-4h3v-5H6v3l-4-4 4-4v3h5V6H8l4-4 4 4h-3z"/></svg></swp-drag-handle>
|
||||
<swp-section-label>Præferencer</swp-section-label>
|
||||
<swp-profile-boxes>
|
||||
<swp-profile-box>
|
||||
|
|
@ -1996,7 +2124,8 @@
|
|||
</swp-profile-boxes>
|
||||
</swp-card>
|
||||
|
||||
<swp-card>
|
||||
<swp-card draggable="true" data-card-id="advarsler">
|
||||
<swp-drag-handle><svg viewBox="0 0 24 24"><path d="M13 6v5h5V8l4 4-4 4v-3h-5v5h3l-4 4-4-4h3v-5H6v3l-4-4 4-4v3h5V6H8l4-4 4 4h-3z"/></svg></swp-drag-handle>
|
||||
<swp-section-label>Advarsler</swp-section-label>
|
||||
<swp-profile-boxes>
|
||||
<swp-profile-box class="warning full-width">
|
||||
|
|
@ -2006,7 +2135,8 @@
|
|||
</swp-profile-boxes>
|
||||
</swp-card>
|
||||
|
||||
<swp-card>
|
||||
<swp-card draggable="true" data-card-id="relationer">
|
||||
<swp-drag-handle><svg viewBox="0 0 24 24"><path d="M13 6v5h5V8l4 4-4 4v-3h-5v5h3l-4 4-4-4h3v-5H6v3l-4-4 4-4v3h5V6H8l4-4 4 4h-3z"/></svg></swp-drag-handle>
|
||||
<swp-section-label>Kundegruppe & Relationer</swp-section-label>
|
||||
|
||||
<swp-customer-group-row>
|
||||
|
|
@ -2056,7 +2186,7 @@
|
|||
</swp-add-relation>
|
||||
</swp-relations-list>
|
||||
</swp-card>
|
||||
</div>
|
||||
</swp-card-column>
|
||||
</div>
|
||||
</swp-tab-content>
|
||||
|
||||
|
|
@ -2621,11 +2751,11 @@
|
|||
<!-- Filters -->
|
||||
<swp-activity-filters>
|
||||
<swp-activity-filter class="active">Alle</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon">📅</span> Bookinger</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon">💬</span> Kommunikation</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon">✏️</span> Ændringer</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon">💳</span> Betalinger</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon">🔐</span> Login</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon"><img src="icons/booking.svg" alt=""></span> Bookinger</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon"><img src="icons/envelope.svg" alt=""></span> Kommunikation</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon"><img src="icons/journal-alt.svg" alt=""></span> Ændringer</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon"><img src="icons/credit-card.svg" alt=""></span> Betalinger</swp-activity-filter>
|
||||
<swp-activity-filter><span class="filter-icon"><img src="icons/unlock.svg" alt=""></span> Login</swp-activity-filter>
|
||||
</swp-activity-filters>
|
||||
|
||||
<swp-card>
|
||||
|
|
@ -2636,7 +2766,7 @@
|
|||
<swp-activity-date-header>I dag</swp-activity-date-header>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="communication">💬</swp-activity-icon>
|
||||
<swp-activity-icon class="communication"><img src="icons/comment-sms.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>SMS påmindelse</strong> sendt om aftale i morgen
|
||||
|
|
@ -2650,7 +2780,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="customer">👤</swp-activity-icon>
|
||||
<swp-activity-icon class="customer"><img src="icons/unlock.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
Kunde <strong>loggede ind</strong> via online booking
|
||||
|
|
@ -2669,7 +2799,7 @@
|
|||
<swp-activity-date-header>9. december 2025</swp-activity-date-header>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="payment">💳</swp-activity-icon>
|
||||
<swp-activity-icon class="payment"><img src="icons/credit-card.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Betaling modtaget</strong> — <span class="highlight">1.799 kr</span> (Dankort)
|
||||
|
|
@ -2682,7 +2812,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="booking">📅</swp-activity-icon>
|
||||
<swp-activity-icon class="booking"><img src="icons/booking.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Aftale gennemført</strong> — Klip + Farve hos Emma L.
|
||||
|
|
@ -2695,7 +2825,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="booking">📅</swp-activity-icon>
|
||||
<swp-activity-icon class="booking"><img src="icons/check-in-calendar.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Check-in</strong> — Kunden er ankommet
|
||||
|
|
@ -2708,7 +2838,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="employee">✏️</swp-activity-icon>
|
||||
<swp-activity-icon class="employee"><img src="icons/journal-alt.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Journal opdateret</strong> — Ny farveformel tilføjet
|
||||
|
|
@ -2726,7 +2856,7 @@
|
|||
<swp-activity-date-header>5. december 2025</swp-activity-date-header>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="booking">📅</swp-activity-icon>
|
||||
<swp-activity-icon class="booking"><img src="icons/created.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Ny booking</strong> oprettet — 9. dec kl. 10:00, Klip + Farve
|
||||
|
|
@ -2740,7 +2870,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="customer">👤</swp-activity-icon>
|
||||
<swp-activity-icon class="customer"><img src="icons/unlock.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
Kunde <strong>loggede ind</strong> via online booking
|
||||
|
|
@ -2759,7 +2889,7 @@
|
|||
<swp-activity-date-header>28. november 2025</swp-activity-date-header>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="employee">✏️</swp-activity-icon>
|
||||
<swp-activity-icon class="employee"><img src="icons/journal-alt.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Telefon ændret</strong> — <span class="old-value">+45 12 34 56 78</span> → <span class="new-value">+45 23 45 67 89</span>
|
||||
|
|
@ -2775,7 +2905,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="employee">✏️</swp-activity-icon>
|
||||
<swp-activity-icon class="employee"><img src="icons/journal-alt.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Tag tilføjet</strong> — <span class="highlight">VIP</span>
|
||||
|
|
@ -2793,7 +2923,7 @@
|
|||
<swp-activity-date-header>12. november 2025</swp-activity-date-header>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="warning">⚠️</swp-activity-icon>
|
||||
<swp-activity-icon class="warning"><img src="icons/warning.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Booking aflyst</strong> — Af kunden med 2 dages varsel
|
||||
|
|
@ -2809,7 +2939,7 @@
|
|||
</swp-activity-item>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="communication">💬</swp-activity-icon>
|
||||
<swp-activity-icon class="communication"><img src="icons/envelope.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Email sendt</strong> — Booking bekræftelse
|
||||
|
|
@ -2828,7 +2958,7 @@
|
|||
<swp-activity-date-header>15. marts 2024</swp-activity-date-header>
|
||||
|
||||
<swp-activity-item>
|
||||
<swp-activity-icon class="system">✨</swp-activity-icon>
|
||||
<swp-activity-icon class="system"><img src="icons/created.svg" alt=""></swp-activity-icon>
|
||||
<swp-activity-content>
|
||||
<swp-activity-title>
|
||||
<strong>Kunde oprettet</strong>
|
||||
|
|
@ -3048,6 +3178,149 @@
|
|||
// In a real app, this would filter the activity items
|
||||
});
|
||||
});
|
||||
|
||||
// ==========================================
|
||||
// CARD DRAG & DROP
|
||||
// ==========================================
|
||||
let draggedCard = null;
|
||||
let dropIndicator = null;
|
||||
|
||||
// Create drop indicator element
|
||||
function createDropIndicator() {
|
||||
if (!dropIndicator) {
|
||||
dropIndicator = document.createElement('swp-drop-indicator');
|
||||
}
|
||||
return dropIndicator;
|
||||
}
|
||||
|
||||
function removeDropIndicator() {
|
||||
if (dropIndicator && dropIndicator.parentNode) {
|
||||
dropIndicator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
function clearDropIndicators() {
|
||||
removeDropIndicator();
|
||||
document.querySelectorAll('.drag-over-empty').forEach(el => {
|
||||
el.classList.remove('drag-over-empty');
|
||||
});
|
||||
}
|
||||
|
||||
// Find the closest card and position based on mouse Y
|
||||
function findDropPosition(column, mouseY) {
|
||||
const cards = Array.from(column.querySelectorAll('swp-card[draggable="true"]:not(.dragging)'));
|
||||
if (cards.length === 0) return { card: null, position: null };
|
||||
|
||||
for (let i = 0; i < cards.length; i++) {
|
||||
const card = cards[i];
|
||||
const rect = card.getBoundingClientRect();
|
||||
const cardMiddle = rect.top + rect.height / 2;
|
||||
|
||||
// If mouse is above the middle of this card, insert before it
|
||||
if (mouseY < cardMiddle) {
|
||||
return { card, position: 'before' };
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse is below all cards, insert after the last one
|
||||
return { card: cards[cards.length - 1], position: 'after' };
|
||||
}
|
||||
|
||||
// Setup draggable cards
|
||||
document.querySelectorAll('swp-card[draggable="true"]').forEach(card => {
|
||||
card.addEventListener('dragstart', (e) => {
|
||||
draggedCard = card;
|
||||
card.classList.add('dragging');
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData('text/plain', card.dataset.cardId);
|
||||
|
||||
setTimeout(() => {
|
||||
card.style.opacity = '0.4';
|
||||
}, 0);
|
||||
});
|
||||
|
||||
card.addEventListener('dragend', () => {
|
||||
card.classList.remove('dragging');
|
||||
card.style.opacity = '';
|
||||
draggedCard = null;
|
||||
clearDropIndicators();
|
||||
});
|
||||
});
|
||||
|
||||
// Handle all dragover at column level for seamless detection
|
||||
document.querySelectorAll('swp-card-column').forEach(column => {
|
||||
column.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
if (!draggedCard) return;
|
||||
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
|
||||
const cards = column.querySelectorAll('swp-card[draggable="true"]:not(.dragging)');
|
||||
|
||||
if (cards.length === 0) {
|
||||
// Empty column
|
||||
column.classList.add('drag-over-empty');
|
||||
removeDropIndicator();
|
||||
return;
|
||||
}
|
||||
|
||||
column.classList.remove('drag-over-empty');
|
||||
|
||||
// Find where to show the indicator
|
||||
const { card, position } = findDropPosition(column, e.clientY);
|
||||
|
||||
if (card) {
|
||||
const indicator = createDropIndicator();
|
||||
|
||||
if (position === 'before') {
|
||||
if (indicator.nextElementSibling !== card) {
|
||||
card.before(indicator);
|
||||
}
|
||||
} else {
|
||||
if (indicator.previousElementSibling !== card) {
|
||||
card.after(indicator);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
column.addEventListener('dragleave', (e) => {
|
||||
if (!column.contains(e.relatedTarget)) {
|
||||
column.classList.remove('drag-over-empty');
|
||||
removeDropIndicator();
|
||||
}
|
||||
});
|
||||
|
||||
column.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
if (!draggedCard) return;
|
||||
|
||||
// Insert dragged card where the indicator is, or at end of empty column
|
||||
if (dropIndicator && dropIndicator.parentNode) {
|
||||
dropIndicator.before(draggedCard);
|
||||
} else if (column.classList.contains('drag-over-empty')) {
|
||||
column.appendChild(draggedCard);
|
||||
}
|
||||
|
||||
clearDropIndicators();
|
||||
});
|
||||
});
|
||||
|
||||
// Also handle drop on the indicator itself
|
||||
document.addEventListener('dragover', (e) => {
|
||||
if (e.target.tagName === 'SWP-DROP-INDICATOR') {
|
||||
e.preventDefault();
|
||||
e.dataTransfer.dropEffect = 'move';
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener('drop', (e) => {
|
||||
if (e.target.tagName === 'SWP-DROP-INDICATOR' && draggedCard) {
|
||||
e.preventDefault();
|
||||
dropIndicator.before(draggedCard);
|
||||
clearDropIndicators();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
|||
2244
wwwroot/poc-service-detail.html
Normal file
2244
wwwroot/poc-service-detail.html
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue