Rebuild menu admin item/category rows on CSS Grid, refine actions UI
- Replace the <table>-based item and category-header rows with CSS Grid containers using named grid-template-areas, so desktop and mobile each get their own independent arrangement of the same fields instead of mobile being a display:block hack forced onto table markup - Make the status badge itself the availability toggle (no separate "Mark Sold Out" button), fixed-width so toggling never shifts the Status column, and shorten its label to "Sold Out" - Merge the item Tag into the name line as an inline badge instead of giving it its own column - Group the move/edit/delete controls into two stacked button columns (was 4-5 buttons wide) and right-align them on mobile Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
40f4c102b4
commit
fd928a24cf
3 files changed
+329
-156
No files matched your search
+188
-5
@@ -1320,6 +1320,32 @@
|
||||
color: var(--ink-muted);
|
||||
}
|
||||
|
||||
/* The menu admin's status badge doubles as its own availability toggle
|
||||
(see .btn-toggle-item) — a plain <button> would otherwise pick up the
|
||||
browser's default chrome underneath the badge's own background/border.
|
||||
Scoped to the element type so the read-only status badges elsewhere
|
||||
(e.g. the announcements table) aren't affected. */
|
||||
/* Fixed to fit its longest possible label ("● Available", ~6.7rem
|
||||
measured) so toggling doesn't change the badge's — and therefore the
|
||||
Status column's — width and shove every other column sideways. */
|
||||
button.status-badge {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
cursor: pointer;
|
||||
justify-content: center;
|
||||
width: 7rem;
|
||||
transition: opacity .15s ease;
|
||||
}
|
||||
|
||||
button.status-badge:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
button.status-badge:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
/* admin table & list actions */
|
||||
.admin-table-wrap {
|
||||
overflow-x: auto;
|
||||
@@ -1365,6 +1391,15 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* Groups the item row's move (↑/↓) and edit/delete controls into two
|
||||
narrow vertical stacks instead of four buttons side by side — keeps
|
||||
the Actions column (and the table as a whole) from running wide. */
|
||||
.action-stack {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
}
|
||||
|
||||
/* Below ~760px a plain <table> forces long text (item descriptions,
|
||||
headlines) into a column so narrow it wraps one word per line. Recast
|
||||
each row as a labeled card instead — the label comes from the td's
|
||||
@@ -1419,6 +1454,19 @@
|
||||
flex-wrap: wrap;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* Right-align the action buttons instead of leaving them stranded at
|
||||
the card's left edge — item rows (an inline-flex box in a
|
||||
full-width block <td>, so text-align positions it) and category
|
||||
headers (a flex item in .panel-head, so margin-left:auto pushes it
|
||||
to the end of its line) need different techniques to get there. */
|
||||
.admin-table td[data-label="Actions"] {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.panel-head .admin-table-actions {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
@@ -1575,10 +1623,15 @@
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
/* admin menu table: category panel header + item cell formatting.
|
||||
/* admin menu grid: category panel header + item row formatting.
|
||||
Shared between admin/menu.php's server render and admin/menu.js's
|
||||
client-side row/panel templates, so it lives here once instead of
|
||||
being duplicated as inline styles in both places. */
|
||||
being duplicated as inline styles in both places.
|
||||
|
||||
This — not <table>/<tr>/<td> — is the item list's actual layout.
|
||||
Desktop and mobile each get their own grid-template-areas map (see the
|
||||
mobile override below), so the two can be redesigned independently
|
||||
instead of one being a display:block hack forced onto the other. */
|
||||
.font-mono {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
@@ -1586,17 +1639,96 @@
|
||||
/* two classes to reliably outrank .panel h2's margin-bottom above */
|
||||
.category-panel .cat-name-heading {
|
||||
margin-bottom: 0.25rem;
|
||||
grid-area: name;
|
||||
}
|
||||
|
||||
.cat-desc-text {
|
||||
font-size: 0.88rem;
|
||||
}
|
||||
|
||||
.no-items-row td {
|
||||
.category-panel .cat-desc-text {
|
||||
grid-area: desc;
|
||||
}
|
||||
|
||||
/* Category panel-head as a grid: title on its own top row, description
|
||||
and the move/edit/delete buttons sharing the row below with the
|
||||
buttons pinned to the far end (matches the desktop arrangement this
|
||||
replaced — see the mobile override for how that changes below 760px). */
|
||||
.category-panel .panel-head {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
grid-template-areas:
|
||||
"name actions"
|
||||
"desc actions";
|
||||
align-items: center;
|
||||
column-gap: 0.75rem;
|
||||
}
|
||||
|
||||
.category-panel .panel-head .admin-table-actions {
|
||||
grid-area: actions;
|
||||
}
|
||||
|
||||
/* Each category's item list: a header row of column labels (desktop
|
||||
only — hidden on mobile below) plus one grid per item row, all
|
||||
sharing the same column template so they line up. */
|
||||
.item-grid-wrap {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.item-grid-head,
|
||||
.item-row {
|
||||
display: grid;
|
||||
grid-template-columns: auto minmax(0, 1fr) auto auto;
|
||||
grid-template-areas: "status item price actions";
|
||||
column-gap: 0.75rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-grid-head {
|
||||
padding: 0 0.75rem 0.85rem;
|
||||
border-bottom: 1px solid var(--rule);
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.72rem;
|
||||
letter-spacing: 0.12em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gold);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
padding: 0.85rem 0.75rem;
|
||||
border-bottom: 1px solid var(--rule);
|
||||
}
|
||||
|
||||
.item-rows .item-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.col-status { grid-area: status; }
|
||||
.col-item { grid-area: item; }
|
||||
.col-price { grid-area: price; }
|
||||
.col-actions { grid-area: actions; }
|
||||
|
||||
.item-row [data-label="Status"] { grid-area: status; }
|
||||
.item-row [data-label="Item"] { grid-area: item; }
|
||||
.item-row [data-label="Price"] { grid-area: price; }
|
||||
.item-row [data-label="Actions"] { grid-area: actions; }
|
||||
|
||||
.item-grid-empty {
|
||||
text-align: center;
|
||||
padding: 1.5rem 0;
|
||||
}
|
||||
|
||||
/* Wraps the item name and its optional badge (reusing the public menu's
|
||||
.menu-item-badge pill) so they sit on one inline-flowing line instead
|
||||
of giving the badge its own column. */
|
||||
.item-name-row {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.item-desc-cell {
|
||||
font-size: 0.82rem;
|
||||
margin-top: 0.2rem;
|
||||
@@ -1612,8 +1744,59 @@
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.item-badge-cell .eyebrow {
|
||||
font-size: 0.68rem;
|
||||
/* Menu admin grid: its own mobile arrangement, independent of the
|
||||
desktop one above — this is the whole point of grid-template-areas
|
||||
over the <table> hack. Same fields, different map. Placed after the
|
||||
desktop rules above (rather than in the earlier shared .admin-table
|
||||
mobile block) so it wins the cascade at equal specificity — a rule's
|
||||
source position still matters once a media query lets both compete. */
|
||||
@media (max-width: 47.5em) {
|
||||
.item-grid-head {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.item-row {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
"status"
|
||||
"item"
|
||||
"price"
|
||||
"actions";
|
||||
row-gap: 0.4rem;
|
||||
border: 1px solid var(--rule);
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.9rem 1rem;
|
||||
margin-bottom: 0.85rem;
|
||||
}
|
||||
|
||||
.item-rows .item-row:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.item-row [data-label]::before {
|
||||
content: attr(data-label);
|
||||
display: block;
|
||||
font-family: var(--font-mono);
|
||||
font-size: 0.68rem;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--gold);
|
||||
margin-bottom: 0.3rem;
|
||||
}
|
||||
|
||||
.item-row [data-label="Actions"] {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.category-panel .panel-head {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas:
|
||||
"name"
|
||||
"desc"
|
||||
"actions";
|
||||
row-gap: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- admin modal dialogs ---------- */
|
||||
|
||||
Reference in new issue
Block a user