Enhance Phase 1 UI: Layout, Resizer, and Card adjustments
All checks were successful
Docker Build & Push / build-and-push (push) Successful in 12s

- Changed Phase 1 layout to 2/3 (Lager) and 1/3 (Table) split.

- Added an interactive, draggable resizer handle between the two panes.

- Made Lager cards ~10% wider and enforced a strict uniform height (200px).

- Added manufacturer name to cards and applied text-overflow: ellipsis to prevent line breaks.

- Reduced font sizes for metadata to fit compactly.

- Safely removed SortableJS destroy() logic to prevent JS crash.
This commit is contained in:
Gemini Agent
2026-05-12 07:19:52 +00:00
parent 141edbfd61
commit 4418d0ede6

View File

@@ -38,8 +38,8 @@ if ($is_owner || $is_in_same_household) { $can_edit = true; }
if (!$can_edit) { die("Zugriff verweigert."); }
$phase = isset($_GET['phase']) ? intval($_GET['phase']) : 0;
$col_class_lager = ($phase == 1) ? 'col-lg-6' : (($phase == 2) ? 'd-none' : 'col-lg-4');
$col_class_table = ($phase == 1 || $phase == 2) ? 'col-lg-6' : 'col-lg-4';
$col_class_lager = ($phase == 1) ? 'col-phase1-lager' : (($phase == 2) ? 'd-none' : 'col-lg-4');
$col_class_table = ($phase == 1) ? 'col-phase1-table' : (($phase == 2) ? 'col-lg-6' : 'col-lg-4');
$col_class_rucksack = ($phase == 2) ? 'col-lg-6' : (($phase == 1) ? 'd-none' : 'col-lg-4');
$phase_title_suffix = ($phase == 1) ? " - Auswahl (Lager)" : (($phase == 2) ? " - Packen (Rucksack)" : "");
@@ -151,41 +151,65 @@ $conn->close();
/* Lager Grid */
.lager-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
grid-template-columns: repeat(auto-fill, minmax(145px, 1fr));
gap: 12px; padding: 5px;
align-items: start; /* Prevents cards from stretching vertically */
align-items: start;
}
.lager-card {
border: 1px solid #eee; border-radius: 8px; padding: 6px;
text-align: center; background: #fff; display: flex; flex-direction: column;
transition: transform 0.1s, box-shadow 0.1s;
height: 200px;
}
.lager-card:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0,0,0,0.05); }
.lager-img-wrapper {
width: 100%; height: 120px; margin-bottom: 6px; display: flex;
width: 100%; height: 90px; margin-bottom: 6px; display: flex;
align-items: center; justify-content: center; overflow: hidden;
flex-shrink: 0;
}
.lager-img-wrapper img.lager-card-img {
width: 100% !important; height: 100% !important;
max-width: 100% !important; max-height: 120px !important;
max-width: 100% !important; max-height: 90px !important;
object-fit: contain !important; border-radius: 4px;
}
.lager-title {
font-size: 0.85em; font-weight: 600; margin-bottom: 4px;
line-height: 1.1; word-wrap: break-word;
font-size: 0.85em; font-weight: 600; margin-bottom: 2px;
line-height: 1.1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
flex-shrink: 0;
}
.lager-meta {
font-size: 0.7em; color: #6c757d; margin-bottom: 4px;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
line-height: 1.1; flex-shrink: 0;
}
.lager-controls {
display: flex; justify-content: center; align-items: center; gap: 8px; margin-top: 4px;
display: flex; justify-content: center; align-items: center; gap: 8px; margin-top: auto;
}
.table-status-text {
font-size: 0.75em; color: #2e7d32; font-weight: 600;
min-height: 14px; margin-top: 2px; visibility: hidden; line-height: 1;
min-height: 12px; margin-top: 2px; visibility: hidden; line-height: 1;
}
.table-status-text.visible { visibility: visible; }
.editor-pane { display: flex; flex-direction: column; height: 100%; }
.pane-content { flex-grow: 1; overflow-y: auto; padding: 10px; }
/* Layout Phase 1 Split */
.col-phase1-lager { width: calc(66.666% - 5px); flex: 0 0 auto; }
.col-phase1-table { width: calc(33.333% - 5px); flex: 0 0 auto; }
.resizer {
width: 10px;
cursor: col-resize;
background-color: transparent;
transition: background-color 0.2s;
border-radius: 4px;
z-index: 10;
flex: 0 0 auto;
}
.resizer:hover, .resizer.resizing {
background-color: rgba(0,0,0,0.1);
}
/* Remove empty dropzone on the table specifically */
#table-container > .packed-item-container > .nested-sortable:empty {
min-height: 0;
@@ -218,9 +242,9 @@ $conn->close();
</div>
</div>
<div class="row g-3" style="height: 75vh; min-height: 600px;">
<div class="row g-2 flex-nowrap" style="height: 75vh; min-height: 600px; overflow-x: auto;" id="main-panes-container">
<!-- LAGER -->
<div class="<?php echo $col_class_lager; ?> h-100">
<div class="<?php echo $col_class_lager; ?> h-100" id="pane-lager">
<div class="card h-100">
<div class="card-header bg-light">
<h5 class="mb-2"><i class="fas fa-boxes me-2"></i>Lagerbestand</h5>
@@ -236,8 +260,13 @@ $conn->close();
</div>
</div>
<!-- RESIZER -->
<?php if ($phase == 1): ?>
<div class="resizer" id="resizer-1"></div>
<?php endif; ?>
<!-- TISCH -->
<div class="<?php echo $col_class_table; ?> h-100">
<div class="<?php echo $col_class_table; ?> h-100" id="pane-table">
<div class="card h-100 border-info">
<div class="card-header bg-info text-white">
<h5 class="mb-0"><i class="fas fa-table me-2"></i>Auf dem Tisch</h5>
@@ -249,7 +278,7 @@ $conn->close();
</div>
<!-- RUCKSACK -->
<div class="<?php echo $col_class_rucksack; ?> h-100">
<div class="<?php echo $col_class_rucksack; ?> h-100" id="pane-rucksack">
<div class="card h-100 border-success">
<div class="card-header bg-success text-white">
<h5 class="mb-0"><i class="fas fa-backpack me-2"></i>Rucksäcke</h5>
@@ -331,6 +360,37 @@ $conn->close();
document.getElementById('table-container').addEventListener('change', handleQuantityChange);
document.getElementById('carriers-container').addEventListener('change', handleQuantityChange);
const resizer = document.getElementById('resizer-1');
const leftPane = document.getElementById('pane-lager');
const rightPane = document.getElementById('pane-table');
if (resizer && leftPane && rightPane) {
let isResizing = false;
resizer.addEventListener('mousedown', (e) => {
isResizing = true;
document.body.style.cursor = 'col-resize';
document.body.style.userSelect = 'none';
resizer.classList.add('resizing');
});
document.addEventListener('mousemove', (e) => {
if (!isResizing) return;
const container = document.getElementById('main-panes-container');
const containerRect = container.getBoundingClientRect();
const totalWidth = containerRect.width;
const leftWidth = e.clientX - containerRect.left;
const rightWidth = totalWidth - leftWidth - 10;
leftPane.style.width = `calc(${(leftWidth / totalWidth) * 100}%)`;
rightPane.style.width = `calc(${(rightWidth / totalWidth) * 100}%)`;
});
document.addEventListener('mouseup', () => {
if(isResizing) {
isResizing = false;
document.body.style.cursor = 'default';
document.body.style.userSelect = 'auto';
resizer.classList.remove('resizing');
}
});
}
fullRender();
});
@@ -393,14 +453,15 @@ $conn->close();
const imgUrl = article.image_url ? article.image_url : 'assets/images/keinbild.png';
const plusBtnClass = qtyTable > 0 ? 'btn-success' : 'btn-outline-primary';
const metaText = [article.manufacturer_name, article.product_designation].filter(Boolean).join(' - ');
const cardHtml = `
<div class="lager-card">
<div class="lager-card" title="${article.name}${metaText ? ' (' + metaText + ')' : ''}">
<div class="lager-img-wrapper">
<img src="${imgUrl}" class="lager-card-img">
</div>
<div class="lager-title">${article.name}</div>
${article.product_designation ? `<div class="small text-muted mb-1" style="line-height: 1.1;">${article.product_designation}</div>` : ''}
<small class="text-muted d-block mb-1">${article.weight_grams}g</small>
<div class="lager-meta">${metaText}</div>
<small class="text-muted d-block mb-1" style="font-size:0.75em;">${article.weight_grams}g</small>
<div class="lager-controls">
<button class="btn btn-sm btn-outline-secondary" onclick="adjustTable(${aid}, -1)" ${disableMinus ? 'disabled' : ''}><i class="fas fa-minus"></i></button>
<button class="btn btn-sm ${plusBtnClass}" onclick="triggerAddTable(${aid})" ${disablePlus ? 'disabled' : ''}><i class="fas fa-plus"></i></button>