Moving away from Azure Devops #1
1 changed files with 273 additions and 77 deletions
|
|
@ -981,35 +981,106 @@
|
||||||
|
|
||||||
swp-availability-time {
|
swp-availability-time {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
swp-availability-time select {
|
swp-time-range {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-time-range-slider {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
height: 20px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-time-range-track {
|
||||||
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 200px;
|
height: 4px;
|
||||||
padding: 6px 10px;
|
background: var(--color-border);
|
||||||
font-size: 13px;
|
border-radius: 2px;
|
||||||
font-family: inherit;
|
}
|
||||||
border: 1px solid var(--color-border);
|
|
||||||
border-radius: 4px;
|
swp-time-range-fill {
|
||||||
background: var(--color-background-alt);
|
position: absolute;
|
||||||
color: var(--color-text);
|
height: 4px;
|
||||||
|
background: var(--color-teal);
|
||||||
|
border-radius: 2px;
|
||||||
|
cursor: grab;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-time-range-fill:active {
|
||||||
|
cursor: grabbing;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-time-range-fill.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-time-range-slider input[type="range"] {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 4px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
background: transparent;
|
||||||
|
pointer-events: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-time-range-slider input[type="range"]::-webkit-slider-thumb {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
appearance: none;
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: var(--color-teal);
|
||||||
|
border: 2px solid white;
|
||||||
|
border-radius: 50%;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 150ms ease;
|
pointer-events: auto;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
swp-availability-time select:hover:not(:disabled) {
|
swp-time-range-slider input[type="range"]::-moz-range-thumb {
|
||||||
background: var(--color-background);
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
background: var(--color-teal);
|
||||||
|
border: 2px solid white;
|
||||||
|
border-radius: 50%;
|
||||||
|
cursor: pointer;
|
||||||
|
pointer-events: auto;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
swp-availability-time select:focus {
|
swp-time-range-label {
|
||||||
outline: none;
|
font-size: 12px;
|
||||||
border-color: var(--color-teal);
|
font-family: var(--font-mono);
|
||||||
background: var(--color-surface);
|
color: var(--color-text);
|
||||||
|
min-width: 90px;
|
||||||
|
text-align: center;
|
||||||
|
background: var(--color-background-alt);
|
||||||
|
padding: 3px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
swp-availability-time select:disabled {
|
swp-availability-row[data-enabled="false"] swp-time-range-slider input[type="range"]::-webkit-slider-thumb {
|
||||||
|
background: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-availability-row[data-enabled="false"] swp-time-range-fill {
|
||||||
|
background: var(--color-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
swp-availability-row[data-enabled="false"] swp-time-range-label {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================
|
/* ==========================================
|
||||||
|
|
@ -1887,108 +1958,129 @@
|
||||||
<swp-availability-list>
|
<swp-availability-list>
|
||||||
<swp-availability-row data-enabled="true">
|
<swp-availability-row data-enabled="true">
|
||||||
<swp-availability-day>Mandag</swp-availability-day>
|
<swp-availability-day>Mandag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select>
|
|
||||||
<option selected>Hele dagen</option>
|
|
||||||
<option>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="yes">
|
<swp-toggle-slider data-value="yes">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 18:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
<swp-availability-row data-enabled="true">
|
<swp-availability-row data-enabled="true">
|
||||||
<swp-availability-day>Tirsdag</swp-availability-day>
|
<swp-availability-day>Tirsdag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select>
|
|
||||||
<option selected>Hele dagen</option>
|
|
||||||
<option>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="yes">
|
<swp-toggle-slider data-value="yes">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 18:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
<swp-availability-row data-enabled="true">
|
<swp-availability-row data-enabled="true">
|
||||||
<swp-availability-day>Onsdag</swp-availability-day>
|
<swp-availability-day>Onsdag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select>
|
|
||||||
<option selected>Hele dagen</option>
|
|
||||||
<option>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="yes">
|
<swp-toggle-slider data-value="yes">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 18:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
<swp-availability-row data-enabled="true">
|
<swp-availability-row data-enabled="true">
|
||||||
<swp-availability-day>Torsdag</swp-availability-day>
|
<swp-availability-day>Torsdag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select>
|
|
||||||
<option>Hele dagen</option>
|
|
||||||
<option selected>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="yes">
|
<swp-toggle-slider data-value="yes">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="24" step="1">
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 12:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
<swp-availability-row data-enabled="true">
|
<swp-availability-row data-enabled="true">
|
||||||
<swp-availability-day>Fredag</swp-availability-day>
|
<swp-availability-day>Fredag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select>
|
|
||||||
<option selected>Hele dagen</option>
|
|
||||||
<option>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="yes">
|
<swp-toggle-slider data-value="yes">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1">
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="48" step="1">
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 18:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
<swp-availability-row data-enabled="false">
|
<swp-availability-row data-enabled="false">
|
||||||
<swp-availability-day>Lørdag</swp-availability-day>
|
<swp-availability-day>Lørdag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select disabled>
|
|
||||||
<option selected>Hele dagen</option>
|
|
||||||
<option>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="no">
|
<swp-toggle-slider data-value="no">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1" disabled>
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="48" step="1" disabled>
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 18:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
<swp-availability-row data-enabled="false">
|
<swp-availability-row data-enabled="false">
|
||||||
<swp-availability-day>Søndag</swp-availability-day>
|
<swp-availability-day>Søndag</swp-availability-day>
|
||||||
<swp-availability-time>
|
|
||||||
<select disabled>
|
|
||||||
<option selected>Hele dagen</option>
|
|
||||||
<option>Formiddag (før 12:00)</option>
|
|
||||||
<option>Eftermiddag (efter 12:00)</option>
|
|
||||||
<option>Brugerdefineret</option>
|
|
||||||
</select>
|
|
||||||
</swp-availability-time>
|
|
||||||
<swp-toggle-slider data-value="no">
|
<swp-toggle-slider data-value="no">
|
||||||
<swp-toggle-option>Ja</swp-toggle-option>
|
<swp-toggle-option>Ja</swp-toggle-option>
|
||||||
<swp-toggle-option>Nej</swp-toggle-option>
|
<swp-toggle-option>Nej</swp-toggle-option>
|
||||||
</swp-toggle-slider>
|
</swp-toggle-slider>
|
||||||
|
<swp-availability-time>
|
||||||
|
<swp-time-range>
|
||||||
|
<swp-time-range-slider>
|
||||||
|
<swp-time-range-track></swp-time-range-track>
|
||||||
|
<swp-time-range-fill></swp-time-range-fill>
|
||||||
|
<input type="range" class="range-start" min="0" max="60" value="8" step="1" disabled>
|
||||||
|
<input type="range" class="range-end" min="0" max="60" value="48" step="1" disabled>
|
||||||
|
</swp-time-range-slider>
|
||||||
|
<swp-time-range-label>08:00 – 18:00</swp-time-range-label>
|
||||||
|
</swp-time-range>
|
||||||
|
</swp-availability-time>
|
||||||
</swp-availability-row>
|
</swp-availability-row>
|
||||||
</swp-availability-list>
|
</swp-availability-list>
|
||||||
</swp-card>
|
</swp-card>
|
||||||
|
|
@ -2094,6 +2186,106 @@
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// TIME RANGE SLIDERS
|
||||||
|
// ==========================================
|
||||||
|
function valueToTime(value) {
|
||||||
|
// value 0-60 represents 06:00-21:00 in 15-min intervals
|
||||||
|
const totalMinutes = (value * 15) + (6 * 60); // Add 6 hour offset
|
||||||
|
const hours = Math.floor(totalMinutes / 60);
|
||||||
|
const minutes = totalMinutes % 60;
|
||||||
|
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TIME_RANGE_MAX = 60; // 15 hours (06:00-21:00) * 4 intervals
|
||||||
|
|
||||||
|
function updateTimeRange(slider) {
|
||||||
|
const startInput = slider.querySelector('.range-start');
|
||||||
|
const endInput = slider.querySelector('.range-end');
|
||||||
|
const fill = slider.querySelector('swp-time-range-fill');
|
||||||
|
const label = slider.closest('swp-time-range').querySelector('swp-time-range-label');
|
||||||
|
|
||||||
|
let startVal = parseInt(startInput.value);
|
||||||
|
let endVal = parseInt(endInput.value);
|
||||||
|
|
||||||
|
// Ensure start doesn't exceed end
|
||||||
|
if (startVal > endVal) {
|
||||||
|
if (startInput === document.activeElement) {
|
||||||
|
startInput.value = endVal;
|
||||||
|
startVal = endVal;
|
||||||
|
} else {
|
||||||
|
endInput.value = startVal;
|
||||||
|
endVal = startVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update fill bar position
|
||||||
|
const startPercent = (startVal / TIME_RANGE_MAX) * 100;
|
||||||
|
const endPercent = (endVal / TIME_RANGE_MAX) * 100;
|
||||||
|
fill.style.left = startPercent + '%';
|
||||||
|
fill.style.width = (endPercent - startPercent) + '%';
|
||||||
|
|
||||||
|
// Update label
|
||||||
|
label.textContent = valueToTime(startVal) + ' – ' + valueToTime(endVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('swp-time-range-slider').forEach(slider => {
|
||||||
|
const startInput = slider.querySelector('.range-start');
|
||||||
|
const endInput = slider.querySelector('.range-end');
|
||||||
|
const fill = slider.querySelector('swp-time-range-fill');
|
||||||
|
const track = slider.querySelector('swp-time-range-track');
|
||||||
|
|
||||||
|
// Initialize
|
||||||
|
updateTimeRange(slider);
|
||||||
|
|
||||||
|
startInput.addEventListener('input', () => updateTimeRange(slider));
|
||||||
|
endInput.addEventListener('input', () => updateTimeRange(slider));
|
||||||
|
|
||||||
|
// Drag fill bar to move entire range
|
||||||
|
let isDragging = false;
|
||||||
|
let dragStartX = 0;
|
||||||
|
let dragStartValues = { start: 0, end: 0 };
|
||||||
|
|
||||||
|
fill.addEventListener('mousedown', (e) => {
|
||||||
|
if (startInput.disabled) return;
|
||||||
|
isDragging = true;
|
||||||
|
dragStartX = e.clientX;
|
||||||
|
dragStartValues.start = parseInt(startInput.value);
|
||||||
|
dragStartValues.end = parseInt(endInput.value);
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', (e) => {
|
||||||
|
if (!isDragging) return;
|
||||||
|
|
||||||
|
const sliderWidth = track.offsetWidth;
|
||||||
|
const deltaX = e.clientX - dragStartX;
|
||||||
|
const deltaValue = Math.round((deltaX / sliderWidth) * TIME_RANGE_MAX);
|
||||||
|
|
||||||
|
const duration = dragStartValues.end - dragStartValues.start;
|
||||||
|
let newStart = dragStartValues.start + deltaValue;
|
||||||
|
let newEnd = dragStartValues.end + deltaValue;
|
||||||
|
|
||||||
|
// Clamp to bounds
|
||||||
|
if (newStart < 0) {
|
||||||
|
newStart = 0;
|
||||||
|
newEnd = duration;
|
||||||
|
}
|
||||||
|
if (newEnd > TIME_RANGE_MAX) {
|
||||||
|
newEnd = TIME_RANGE_MAX;
|
||||||
|
newStart = TIME_RANGE_MAX - duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
startInput.value = newStart;
|
||||||
|
endInput.value = newEnd;
|
||||||
|
updateTimeRange(slider);
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('mouseup', () => {
|
||||||
|
isDragging = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// TOGGLE SLIDERS (Ja/Nej)
|
// TOGGLE SLIDERS (Ja/Nej)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
@ -2109,9 +2301,13 @@
|
||||||
if (availabilityRow) {
|
if (availabilityRow) {
|
||||||
const isEnabled = newValue === 'yes';
|
const isEnabled = newValue === 'yes';
|
||||||
availabilityRow.dataset.enabled = isEnabled;
|
availabilityRow.dataset.enabled = isEnabled;
|
||||||
const select = availabilityRow.querySelector('select');
|
const rangeInputs = availabilityRow.querySelectorAll('input[type="range"]');
|
||||||
if (select) {
|
rangeInputs.forEach(input => {
|
||||||
select.disabled = !isEnabled;
|
input.disabled = !isEnabled;
|
||||||
|
});
|
||||||
|
const fill = availabilityRow.querySelector('swp-time-range-fill');
|
||||||
|
if (fill) {
|
||||||
|
fill.classList.toggle('disabled', !isEnabled);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue