Make the management app responsive on mobile
Replace the mobile nav's horizontal scroll strip (which wrapped into an unreadable jumble because daisyUI's .menu sets flex-wrap: wrap and .menu-horizontal never resets it) with a hamburger button that opens a proper left-side drawer, mirrored in controlpanel for the same bug. Move the theme toggle, "Management", and "Django admin" controls into that drawer below `lg`, leaving only the account icon in the navbar, so the club name has room to render in full instead of truncating to initials. Add a reusable `.table-cards` CSS pattern (app.css) that turns a list table into a stack of labelled cards below `md`, and apply it to every list/detail table in the management app -- members, families, teams, memberships, events, groups, locations, opponents, positions, referee levels/list, roles, sponsors, news, parent claims, team roster/staff, and the shared family-members table. Tables revert to normal desktop layout at `md` and up. Member list gets extra passes: search submits icon-only below `sm` so it fits next to the input, the Members/Guardians/Both tabs go full-width, and last/first name merge into one column. Action-button rows across every page stack full-width on mobile instead of wrapping mid-button (shared fix in base.html). Home dashboard's upcoming-events and news mini-tables become simple lists instead of overflowing tables. Also: brand truncates instead of overflowing on a long club name, a stray invalid xmlns attribute removed, a wrapping UUID badge hidden below `sm` on team detail. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -32,8 +32,28 @@
|
||||
input.placeholder = select.dataset.searchPlaceholder || "";
|
||||
input.autocomplete = "off";
|
||||
|
||||
// `fixed`, not `absolute`: an absolutely positioned dropdown is clipped by
|
||||
// the nearest scrolling ancestor (e.g. the overflow-x-auto wrapper the
|
||||
// bulk-add tables would otherwise need on mobile), which is exactly what
|
||||
// stopped those tables from getting one. Fixed positioning is relative to
|
||||
// the viewport regardless of ancestors, so it's never clipped that way --
|
||||
// position and size are computed in JS instead of via CSS, see positionList().
|
||||
const list = document.createElement("ul");
|
||||
list.className = "menu absolute z-10 mt-1 w-full rounded-box bg-base-100 shadow max-h-60 overflow-y-auto flex-nowrap hidden";
|
||||
list.className = "menu fixed z-50 rounded-box bg-base-100 shadow max-h-60 overflow-y-auto flex-nowrap hidden";
|
||||
|
||||
const positionList = () => {
|
||||
const rect = input.getBoundingClientRect();
|
||||
list.style.left = `${rect.left}px`;
|
||||
list.style.top = `${rect.bottom + 4}px`;
|
||||
list.style.width = `${rect.width}px`;
|
||||
};
|
||||
|
||||
// Capture phase: a "scroll" event on an inner scroll container (the
|
||||
// overflow-x-auto table wrapper) doesn't bubble up to window in the
|
||||
// normal (bubbling) phase, but every scroll is seen on the way down in
|
||||
// the capture phase, so this still fires no matter which ancestor moved.
|
||||
window.addEventListener("scroll", () => { if (!list.classList.contains("hidden")) positionList(); }, true);
|
||||
window.addEventListener("resize", () => { if (!list.classList.contains("hidden")) positionList(); });
|
||||
|
||||
select.parentNode.insertBefore(wrapper, select);
|
||||
if (isMultiple) {
|
||||
@@ -115,7 +135,12 @@
|
||||
});
|
||||
|
||||
highlighted = -1;
|
||||
list.classList.toggle("hidden", matches.length === 0);
|
||||
if (matches.length === 0) {
|
||||
list.classList.add("hidden");
|
||||
} else {
|
||||
positionList();
|
||||
list.classList.remove("hidden");
|
||||
}
|
||||
return matches;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user