mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-18 03:54:17 +02:00
fix(label-picker): pack templates into a 2x2 grid so all 4 plus Cancel fit on tight viewports (issue #1230)
The earlier `min-h-0` fix on the spool list (61314cf2) made the
shrinkable child shrinkable, but on @elit3ge's 838px viewport the
four stacked templates (~310px) plus footer still blew past
max-h-[90vh] once Brave's browser chrome ate into vh, and
overflow-hidden on the modal clipped Avery 5160 mid-row with the
Cancel button entirely below the clipped bottom edge — no scroll
path. The screenshot showed the spool list at ~5 visible rows with
its own scrollbar still active, confirming the templates section's
natural height was the dominant problem, not the spool list.
Templates now render as a responsive grid (grid-cols-1
sm:grid-cols-2 gap-2) so the four buttons pack into a 2x2 grid
above the sm breakpoint, trimming ~150px of vertical. Per-cell
padding tightens to p-2.5, labels/hints get text-sm + truncate,
and the full strings are reachable via title="<label> — <hint>"
on each button. Footer drops py-3 to py-2 for a few extra pixels.
The min-h-0 on the spool list is kept as a belt-and-braces shrink
for any viewport tighter still. Mobile (<sm) keeps the stacked
layout — no regression there.
This commit is contained in:
@@ -351,32 +351,33 @@ export function LabelTemplatePickerModal({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Templates */}
|
||||
<div className="px-3 pb-3 pt-3 space-y-2 border-t border-bambu-dark-tertiary">
|
||||
{/* Templates — 2x2 grid on >= sm so all 4 plus the Cancel footer fit
|
||||
inside max-h-[90vh] even when browser chrome eats into the viewport
|
||||
(#1230). Stacked single column on mobile widths. */}
|
||||
<div className="px-3 pt-2 pb-2 grid grid-cols-1 sm:grid-cols-2 gap-2 border-t border-bambu-dark-tertiary">
|
||||
{TEMPLATE_OPTIONS.map((opt) => {
|
||||
const isPending = pending === opt.value;
|
||||
const label = t(`inventory.labels.templates.${opt.i18nKey}.label`, opt.fallbackLabel);
|
||||
const hint = t(`inventory.labels.templates.${opt.i18nKey}.hint`, opt.fallbackHint);
|
||||
return (
|
||||
<button
|
||||
key={opt.value}
|
||||
disabled={noSelection || pending !== null}
|
||||
onClick={() => handlePick(opt.value)}
|
||||
className="w-full text-left p-3 rounded-lg border border-bambu-dark-tertiary bg-bambu-dark hover:border-bambu-green hover:bg-bambu-green/10 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:border-bambu-dark-tertiary disabled:hover:bg-bambu-dark transition flex items-center gap-3"
|
||||
title={`${label} — ${hint}`}
|
||||
className="w-full text-left p-2.5 rounded-lg border border-bambu-dark-tertiary bg-bambu-dark hover:border-bambu-green hover:bg-bambu-green/10 disabled:opacity-50 disabled:cursor-not-allowed disabled:hover:border-bambu-dark-tertiary disabled:hover:bg-bambu-dark transition flex items-center gap-3"
|
||||
>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="font-medium text-white">
|
||||
{t(`inventory.labels.templates.${opt.i18nKey}.label`, opt.fallbackLabel)}
|
||||
</div>
|
||||
<div className="text-xs text-bambu-gray mt-0.5">
|
||||
{t(`inventory.labels.templates.${opt.i18nKey}.hint`, opt.fallbackHint)}
|
||||
</div>
|
||||
<div className="font-medium text-white text-sm truncate">{label}</div>
|
||||
<div className="text-xs text-bambu-gray mt-0.5 truncate">{hint}</div>
|
||||
</div>
|
||||
{isPending && <Loader2 className="w-4 h-4 animate-spin text-bambu-green" />}
|
||||
{isPending && <Loader2 className="w-4 h-4 animate-spin text-bambu-green shrink-0" />}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 px-5 py-3 border-t border-bambu-dark-tertiary">
|
||||
<div className="flex justify-end gap-2 px-5 py-2 border-t border-bambu-dark-tertiary">
|
||||
<Button variant="secondary" onClick={onClose} disabled={pending !== null}>
|
||||
{t('common.cancel', 'Cancel')}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user