Add mobile nav toggle, responsive admin tables, and menu reordering

- Public site: replace the always-hidden mobile nav with a hamburger
  toggle (index.php, menu.php, main.js, styles.css)
- Admin: render the Menu/Announcements/Users tables as labeled cards
  below ~760px instead of squeezing descriptions into unreadable
  single-word-per-line columns
- Admin menu: replace the manual "Order" number (which allowed
  duplicates and never reflected in real time) with ↑/↓ buttons that
  reorder items and categories immediately and renumber sort_order
  sequentially on every move, self-healing any stale duplicates

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
David DyerandClaude Sonnet 5 committed 2026-08-31 22:12:24 -04:00
1 parent 7c96b952e9
commit 40f4c102b4
10 files changed
+553 -94

No files matched your search

+149
View File
@@ -343,6 +343,10 @@
color: var(--gold-bright);
}
nav.links a.active {
color: var(--gold-bright);
}
.nav-cta {
display: inline-flex;
align-items: center;
@@ -355,9 +359,67 @@
letter-spacing: 0.06em;
}
/* mobile nav toggle: hidden on desktop, shown only under the nav.links
breakpoint below. Icon swap is driven by the button's own
aria-expanded state rather than a second JS-toggled class. */
.nav-toggle {
display: none;
background: transparent;
border: none;
padding: 0.5rem;
margin: -0.5rem;
color: var(--ink);
cursor: pointer;
align-items: center;
justify-content: center;
}
.nav-toggle svg {
width: 1.5rem;
height: 1.5rem;
}
.nav-toggle .icon-close {
display: none;
}
.nav-toggle[aria-expanded="true"] .icon-menu {
display: none;
}
.nav-toggle[aria-expanded="true"] .icon-close {
display: block;
}
@media (max-width: 47.5em) {
.nav-toggle {
display: inline-flex;
}
.nav-cta {
display: none;
}
nav.links {
display: none;
position: absolute;
top: 100%;
left: 0;
right: 0;
flex-direction: column;
align-items: stretch;
gap: 0;
background: var(--ground-2);
border-bottom: 1px solid var(--rule);
padding: 0.5rem 0;
}
nav.links.is-open {
display: flex;
}
nav.links a {
padding: 0.9rem 1.5rem;
}
}
@@ -470,6 +532,12 @@
transform: translateY(-1px);
}
.btn:disabled {
opacity: 0.35;
cursor: not-allowed;
transform: none;
}
/* :where() keeps this native-button reset at zero specificity, so
modifier classes like .btn-primary's background can actually win
instead of losing to button.btn's higher (0,1,1) specificity */
@@ -1124,6 +1192,22 @@
text-decoration: underline;
}
@media (max-width: 47.5em) {
.admin-nav-inner {
flex-direction: column;
align-items: flex-start;
gap: 0.75rem;
}
/* two classes each, so these reliably outrank .admin-nav-links's and
.admin-user's own base-rule gap regardless of source order */
.admin-nav-inner .admin-nav-links,
.admin-nav-inner .admin-user {
flex-wrap: wrap;
gap: 0.5rem 1rem;
}
}
.dashboard-layout {
padding-block: 2.5rem 4rem;
}
@@ -1155,8 +1239,10 @@
.panel-head {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
}
@@ -1279,12 +1365,74 @@
white-space: nowrap;
}
/* 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
data-label attribute, kept in sync with the <th> text in each admin
page (and its matching *.js row template, where rows are rebuilt
client-side). */
@media (max-width: 47.5em) {
.admin-table-wrap {
overflow-x: visible;
}
.admin-table thead {
display: none;
}
.admin-table,
.admin-table tbody,
.admin-table tr,
.admin-table td {
display: block;
width: 100%;
}
.admin-table tr {
border: 1px solid var(--rule);
border-radius: 0.25rem;
padding: 0.9rem 1rem;
margin-bottom: 0.85rem;
}
.admin-table tr:last-child {
margin-bottom: 0;
}
.admin-table td {
padding: 0.4rem 0;
border-bottom: none;
}
.admin-table td[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;
}
.admin-table-actions {
flex-wrap: wrap;
white-space: normal;
}
}
.btn-sm {
padding: 0.4rem 0.8rem;
font-size: 0.75rem;
line-height: 1.2;
}
/* Single-glyph reorder buttons (↑ / ↓) — narrower than .btn-sm's text
padding since there's no label to give it room to breathe. */
.btn-icon {
padding-inline: 0.55rem;
}
.btn-danger {
background: var(--danger-bg);
border: 1px solid rgba(220, 80, 60, 0.5);
@@ -1539,6 +1687,7 @@
.admin-toolbar {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
align-items: center;
margin-bottom: 2rem;