This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Unreleased
|
||||||
|
|
||||||
|
- Place the queue-card date on the left beside the details arrow and the download status on the right below the progress bar.
|
||||||
|
|
||||||
## 1.0.20 - 2026-09-06
|
## 1.0.20 - 2026-09-06
|
||||||
|
|
||||||
- Fix automatic media-tool setup in long Windows paths by using the built-in archive extractor. Report extraction failures instead of accepting incomplete installations.
|
- Fix automatic media-tool setup in long Windows paths by using the built-in archive extractor. Report extraction failures instead of accepting incomplete installations.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Aktueller veröffentlichter Stand: **1.0.20**, Tag `v1.0.20`, veröffentlicht am
|
|||||||
|
|
||||||
## Letzte Änderungen
|
## Letzte Änderungen
|
||||||
|
|
||||||
|
- Nach Release 1.0.20: Datum und Status in der Queue-Card getauscht. Datum steht jetzt links neben dem Detailpfeil, Status rechts unter dem Fortschrittsbalken. Schriftgrößen, gelber Wartepunkt und Aufklappanimation bleiben erhalten. Build, 19 gezielte Tests, Queue-UI-Test in Deutsch/Englisch und Hell/Dunkel sowie vollständiger Workspace-UI-Test erfolgreich; Lint ohne Fehler bei 15 bestehenden Warnungen. Änderung zunächst nur auf `public-v1`/Hot-Dev, noch nicht veröffentlicht.
|
||||||
- Queue-Detailpfeil reagiert seit der Nachbesserung am 6. September 2026 auf jeden Klick, auch während der Animation. Die frühere Sperre für `MouseEvent.detail > 1` hatte schnelle Folge-Klicks verschluckt und wurde entfernt. Doppelklick auf freie Kartenflächen bleibt erhalten; auf dem Pfeil zählen beide Klicks einzeln. Build, gezielte Queue-Tests und isolierte UI-Prüfung inklusive schneller Klickfolgen erfolgreich.
|
- Queue-Detailpfeil reagiert seit der Nachbesserung am 6. September 2026 auf jeden Klick, auch während der Animation. Die frühere Sperre für `MouseEvent.detail > 1` hatte schnelle Folge-Klicks verschluckt und wurde entfernt. Doppelklick auf freie Kartenflächen bleibt erhalten; auf dem Pfeil zählen beide Klicks einzeln. Build, gezielte Queue-Tests und isolierte UI-Prüfung inklusive schneller Klickfolgen erfolgreich.
|
||||||
- Queue-Details fahren seit dem 6. September 2026 beim Auf-/Zuklappen animiert ein und aus: Grid-Höhe und Deckkraft über 220/180 ms, Pfeilrotation über 220 ms. Bei reduzierten Windows-Animationen bleibt eine kurze 160-ms-Transition wie bei den bestehenden Workspace-Steuerelementen erhalten. Eingeklappte Details sind `inert`, damit unsichtbare Dateiaktionen nicht per Tastatur erreichbar sind. Build, 19 gezielte Tests und isolierter Queue-UI-Test einschließlich gemessener Zwischenhöhen in beiden Bewegungsmodi erfolgreich.
|
- Queue-Details fahren seit dem 6. September 2026 beim Auf-/Zuklappen animiert ein und aus: Grid-Höhe und Deckkraft über 220/180 ms, Pfeilrotation über 220 ms. Bei reduzierten Windows-Animationen bleibt eine kurze 160-ms-Transition wie bei den bestehenden Workspace-Steuerelementen erhalten. Eingeklappte Details sind `inert`, damit unsichtbare Dateiaktionen nicht per Tastatur erreichbar sind. Build, 19 gezielte Tests und isolierter Queue-UI-Test einschließlich gemessener Zwischenhöhen in beiden Bewegungsmodi erfolgreich.
|
||||||
- Queue-Card-Nachbesserung am 6. September 2026: Wartestatus ohne sichtbare Umrandung und ohne gelblichen Hintergrund; gelber Statuspunkt und bisherige Abstände bleiben erhalten. In Hell/Dunkel geprüft, Queue-UI- und Stylesheet-Tests erfolgreich.
|
- Queue-Card-Nachbesserung am 6. September 2026: Wartestatus ohne sichtbare Umrandung und ohne gelblichen Hintergrund; gelber Statuspunkt und bisherige Abstände bleiben erhalten. In Hell/Dunkel geprüft, Queue-UI- und Stylesheet-Tests erfolgreich.
|
||||||
|
|||||||
@@ -51,11 +51,14 @@ async function main() {
|
|||||||
const rect = (selector) => item.querySelector(selector).getBoundingClientRect();
|
const rect = (selector) => item.querySelector(selector).getBoundingClientRect();
|
||||||
const date = rect('.queue-date');
|
const date = rect('.queue-date');
|
||||||
const bar = rect('.queue-progress-wrap');
|
const bar = rect('.queue-progress-wrap');
|
||||||
|
const status = rect('.queue-status-badge');
|
||||||
|
const toggle = rect('.queue-details-toggle');
|
||||||
const remove = rect('.remove');
|
const remove = rect('.remove');
|
||||||
return {
|
return {
|
||||||
id: item.dataset.id,
|
id: item.dataset.id,
|
||||||
dateBelow: date.top >= bar.bottom,
|
dateBelow: date.top >= bar.bottom,
|
||||||
dateRight: Math.abs(date.right - bar.right) <= 1,
|
dateLeft: date.left >= toggle.right && date.right < status.left,
|
||||||
|
statusRight: Math.abs(status.right - bar.right) <= 1,
|
||||||
dateSize: parseFloat(getComputedStyle(item.querySelector('.queue-date')).fontSize),
|
dateSize: parseFloat(getComputedStyle(item.querySelector('.queue-date')).fontSize),
|
||||||
removeSize: Math.min(remove.width, remove.height),
|
removeSize: Math.min(remove.width, remove.height),
|
||||||
overflow: item.scrollWidth - item.clientWidth,
|
overflow: item.scrollWidth - item.clientWidth,
|
||||||
@@ -63,7 +66,7 @@ async function main() {
|
|||||||
};
|
};
|
||||||
}));
|
}));
|
||||||
for (const card of layout) {
|
for (const card of layout) {
|
||||||
assert(card.dateBelow && card.dateRight, `Date placement: ${JSON.stringify(card)}`);
|
assert(card.dateBelow && card.dateLeft && card.statusRight, `Footer placement: ${JSON.stringify(card)}`);
|
||||||
assert(card.dateSize >= 12 && card.removeSize >= 32 && card.tinyText === 0, `Readability: ${JSON.stringify(card)}`);
|
assert(card.dateSize >= 12 && card.removeSize >= 32 && card.tinyText === 0, `Readability: ${JSON.stringify(card)}`);
|
||||||
assert(card.overflow <= 1, `Card overflow: ${JSON.stringify(card)}`);
|
assert(card.overflow <= 1, `Card overflow: ${JSON.stringify(card)}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1222,7 +1222,7 @@ async function run() {
|
|||||||
const remove = downloading?.querySelector('.remove');
|
const remove = downloading?.querySelector('.remove');
|
||||||
const statusRect = statusLabel?.getBoundingClientRect();
|
const statusRect = statusLabel?.getBoundingClientRect();
|
||||||
const removeRect = remove?.getBoundingClientRect();
|
const removeRect = remove?.getBoundingClientRect();
|
||||||
const statusLeftEdges = leftEdges('.status');
|
const statusRightEdges = alignedRows.map((row) => row?.querySelector('.queue-status-badge')?.getBoundingClientRect().right || 0);
|
||||||
const titleLeftEdges = leftEdges('.title');
|
const titleLeftEdges = leftEdges('.title');
|
||||||
const dateLeftEdges = leftEdges('.queue-date');
|
const dateLeftEdges = leftEdges('.queue-date');
|
||||||
const successProbe = document.createElement('span');
|
const successProbe = document.createElement('span');
|
||||||
@@ -1258,7 +1258,7 @@ async function run() {
|
|||||||
startingAnimated: starting?.querySelector('.queue-progress-status')?.classList.contains('is-starting') === true,
|
startingAnimated: starting?.querySelector('.queue-progress-status')?.classList.contains('is-starting') === true,
|
||||||
resumedProgress: paused?.querySelector('.queue-progress-wrap')?.getAttribute('aria-valuenow') || '',
|
resumedProgress: paused?.querySelector('.queue-progress-wrap')?.getAttribute('aria-valuenow') || '',
|
||||||
resumedBarWidth: paused?.querySelector('.queue-progress-bar')?.style.width || '',
|
resumedBarWidth: paused?.querySelector('.queue-progress-bar')?.style.width || '',
|
||||||
statusLeftEdges,
|
statusRightEdges,
|
||||||
titleLeftEdges,
|
titleLeftEdges,
|
||||||
dateLeftEdges,
|
dateLeftEdges,
|
||||||
dateText: starting?.querySelector('.queue-date')?.textContent || '',
|
dateText: starting?.querySelector('.queue-date')?.textContent || '',
|
||||||
@@ -1283,8 +1283,8 @@ async function run() {
|
|||||||
check(dynamicQueue.startingStatusCount === 1, `Starting queue status is rendered ${dynamicQueue.startingStatusCount} times instead of once`);
|
check(dynamicQueue.startingStatusCount === 1, `Starting queue status is rendered ${dynamicQueue.startingStatusCount} times instead of once`);
|
||||||
check(dynamicQueue.startingStatusText === dynamicQueue.expectedStartingStatusText && dynamicQueue.startingAnimated, `Queue start state is not visibly active: ${dynamicQueue.startingStatusText}`);
|
check(dynamicQueue.startingStatusText === dynamicQueue.expectedStartingStatusText && dynamicQueue.startingAnimated, `Queue start state is not visibly active: ${dynamicQueue.startingStatusText}`);
|
||||||
check(dynamicQueue.resumedProgress === '42' && dynamicQueue.resumedBarWidth === '42%', `Resuming queue item loses its paused progress: value=${dynamicQueue.resumedProgress}, width=${dynamicQueue.resumedBarWidth}`);
|
check(dynamicQueue.resumedProgress === '42' && dynamicQueue.resumedBarWidth === '42%', `Resuming queue item loses its paused progress: value=${dynamicQueue.resumedProgress}, width=${dynamicQueue.resumedBarWidth}`);
|
||||||
check(dynamicQueue.statusLeftEdges.every((value) => value > 0) && dynamicQueue.titleLeftEdges.every((value) => value > 0) && dynamicQueue.dateLeftEdges.every((value) => value > 0), 'Queue alignment fixture was measured while hidden');
|
check(dynamicQueue.statusRightEdges.every((value) => value > 0) && dynamicQueue.titleLeftEdges.every((value) => value > 0) && dynamicQueue.dateLeftEdges.every((value) => value > 0), 'Queue alignment fixture was measured while hidden');
|
||||||
check(Math.max(...dynamicQueue.statusLeftEdges) - Math.min(...dynamicQueue.statusLeftEdges) <= 1, `Queue status columns are offset: ${dynamicQueue.statusLeftEdges.join(', ')}`);
|
check(Math.max(...dynamicQueue.statusRightEdges) - Math.min(...dynamicQueue.statusRightEdges) <= 1, `Queue status columns are offset: ${dynamicQueue.statusRightEdges.join(', ')}`);
|
||||||
check(Math.max(...dynamicQueue.titleLeftEdges) - Math.min(...dynamicQueue.titleLeftEdges) <= 1, `Queue title columns are offset: ${dynamicQueue.titleLeftEdges.join(', ')}`);
|
check(Math.max(...dynamicQueue.titleLeftEdges) - Math.min(...dynamicQueue.titleLeftEdges) <= 1, `Queue title columns are offset: ${dynamicQueue.titleLeftEdges.join(', ')}`);
|
||||||
check(Math.max(...dynamicQueue.dateLeftEdges) - Math.min(...dynamicQueue.dateLeftEdges) <= 1, `Queue date columns are offset: ${dynamicQueue.dateLeftEdges.join(', ')}`);
|
check(Math.max(...dynamicQueue.dateLeftEdges) - Math.min(...dynamicQueue.dateLeftEdges) <= 1, `Queue date columns are offset: ${dynamicQueue.dateLeftEdges.join(', ')}`);
|
||||||
check(dynamicQueue.dateText === '10.08.2026', `Queue VOD date is missing or incorrectly formatted: ${dynamicQueue.dateText}`);
|
check(dynamicQueue.dateText === '10.08.2026', `Queue VOD date is missing or incorrectly formatted: ${dynamicQueue.dateText}`);
|
||||||
|
|||||||
@@ -718,10 +718,10 @@ function renderQueue(): void {
|
|||||||
<div class="queue-footer">
|
<div class="queue-footer">
|
||||||
<div class="queue-summary">
|
<div class="queue-summary">
|
||||||
<button class="queue-details-toggle" type="button" aria-label="${escapeHtml(UI_TEXT.queue.toggleDetails)}" title="${escapeHtml(UI_TEXT.queue.toggleDetails)}" aria-expanded="${expandedQueueIds.has(item.id) ? 'true' : 'false'}" aria-controls="${detailsId}" data-queue-action="details"><svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m7 10 5 5 5-5"/></svg></button>
|
<button class="queue-details-toggle" type="button" aria-label="${escapeHtml(UI_TEXT.queue.toggleDetails)}" title="${escapeHtml(UI_TEXT.queue.toggleDetails)}" aria-expanded="${expandedQueueIds.has(item.id) ? 'true' : 'false'}" aria-controls="${detailsId}" data-queue-action="details"><svg aria-hidden="true" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m7 10 5 5 5-5"/></svg></button>
|
||||||
<span class="queue-status-badge" title="${safeProgressStatus}"><span class="status ${item.status}" aria-hidden="true"></span><span class="queue-status-label">${safeStatusLabel}</span></span>
|
|
||||||
</div>
|
|
||||||
<span class="queue-date">${safeDate}</span>
|
<span class="queue-date">${safeDate}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="queue-status-badge" title="${safeProgressStatus}"><span class="status ${item.status}" aria-hidden="true"></span><span class="queue-status-label">${safeStatusLabel}</span></span>
|
||||||
|
</div>
|
||||||
<div class="queue-progress-info${item.status === 'pending' || item.status === 'completed' ? ' is-hidden' : ''}">
|
<div class="queue-progress-info${item.status === 'pending' || item.status === 'completed' ? ' is-hidden' : ''}">
|
||||||
<span class="queue-progress-status${progressStatusClass}${item.status === 'paused' ? ' is-hidden' : ''}">${safeProgressStatus}</span>
|
<span class="queue-progress-status${progressStatusClass}${item.status === 'paused' ? ' is-hidden' : ''}">${safeProgressStatus}</span>
|
||||||
<span class="queue-progress-metrics">${safeProgressMetrics}</span>
|
<span class="queue-progress-metrics">${safeProgressMetrics}</span>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ describe('production style modules', () => {
|
|||||||
.replace(/\r\n/g, '\n'));
|
.replace(/\r\n/g, '\n'));
|
||||||
const digest = createHash('sha256').update(content).digest('hex');
|
const digest = createHash('sha256').update(content).digest('hex');
|
||||||
|
|
||||||
expect(digest).toBe('b937d229d00f4a35098f288399331025580a1448f7c7aab7908f12ec826628e9');
|
expect(digest).toBe('eccaa49c879b53f95816408514a741f9aef7701ec9153ef9c8d70173a5b67056');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('derives the Windows hot-development executable version from package metadata', () => {
|
test('derives the Windows hot-development executable version from package metadata', () => {
|
||||||
|
|||||||
@@ -209,16 +209,17 @@
|
|||||||
|
|
||||||
.queue-date {
|
.queue-date {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-left: auto;
|
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 18px;
|
line-height: 18px;
|
||||||
font-variant-numeric: tabular-nums;
|
font-variant-numeric: tabular-nums;
|
||||||
text-align: right;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue-status-badge {
|
.queue-status-badge {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 6px;
|
gap: 6px;
|
||||||
padding: 2px 7px;
|
padding: 2px 7px;
|
||||||
|
|||||||
Reference in New Issue
Block a user