Moving away from Azure Devops #1

Merged
Janus007 merged 113 commits from refac into master 2026-02-03 00:04:27 +01:00
7 changed files with 2565 additions and 35 deletions
Showing only changes of commit 9f46ff8824 - Show all commits

View 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

View 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

View 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

View 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
View 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

View file

@ -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>

File diff suppressed because it is too large Load diff