feat(ui): make components responsive across full breakpoint scale#25
Merged
Conversation
The ui_* component suite was built desktop-first with no responsive breakpoints. Tablets and phones got truncated text, overflowing tables, and a sidebar that ate ~224px of viewport with no way to dismiss it. Component fixes: - Sidebar collapses to a daisyUI drawer + hamburger header below lg (1024px), so iPad portrait gets the drawer too. The drawer reuses the same nav slot via extracted sidebar_brand/sidebar_nav/sidebar_footer private components. - ui_table: action_bar wraps; pagination stacks flex-col sm:flex-row; numbered pages hidden on xs, replaced by "Page X of Y". - ui_tabs: overflow-x-auto whitespace-nowrap so 4+ tabs scroll instead of wrapping silently. - ui_page_header: stacks actions below title on xs; action buttons go full-width. - ui_card header: flex-col sm:flex-row so title and wide actions don't cramp on narrow. - ui_modal: max-h-[calc(100vh-2rem)] with overflow-y-auto body region, so tall content scrolls inside the panel instead of the viewport. - ui_kv_table: rows stack label-above-value on xs, side-by-side from sm. - ui_release_card: metric strip flex-col sm:flex-row. - ui_audit_row: timestamp stacks below body on xs, indented to align. - ui_card_title: rewritten to flex-wrap with ml-auto for the meta badge — the old flex-1 spacer cramped both title and meta when the card cell was narrow. - ui_chart_card + line_chart: added min-w-0 + overflow-hidden + a CSS-important w-full override on the canvas, plus a window.resize fallback in the hook. Chart.js was failing to shrink because the canvas's intrinsic width pushed the grid cell open, creating a circular ResizeObserver dependency. New dev-only showcase at /dev/ui: - DevUiLive renders every ui_* component grouped by family. - Viewport-width toggle: 375 / 414 / 768 / 1024 / 1440 / full. - Compiled out in :prod via Mix.env() guard in the router. Tests: - responsive_test.exs: 13 assertions for class hooks on each component. - dev_ui_live_test.exs: smoke test for /dev/ui route + width toggle. - 277/277 passing. Closes #19
Closed
10 tasks
3 tasks
pachev
added a commit
that referenced
this pull request
May 23, 2026
Closes #26. Adopt ui_table where raw <table> still lived in page code (settings SSH keys, application top-processes), add sm breakpoints to page-level 4-stat grids that were stuck at grid-cols-2 (dashboard, server overview, app detail), and adopt ui_kv_table for the server-settings Connection block so labels stack on xs instead of cramping at grid-cols-2. Rework two anti-patterns that still lived in page code after the ui_* library was fixed in #25: the flex-1 spacer in the System snapshot header (now ml-auto on the badge) and the w-44 shrink-0 label column in snapshot_row (now flex-col sm:flex-row). Also flatten the Updates tab so it matches the pen design (PFTPt) and the Releases tab pattern: drop the outer ui_card wrapper, lift 'Available Updates' into a page-level section header, let ui_table be the only card surface. Empty states stay wrapped in ui_card so ui_empty has a frame.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #19.
What changed
The
ui_*component suite was built desktop-first. Tablets and phones got truncated text, overflowing tables, and a sidebar that ate ~224px of viewport with no way to dismiss it. This PR tunes every shared component across Tailwind's fullsm/md/lg/xl/2xlscale, adds a daisyUI drawer for the sidebar belowlg(so iPad portrait works too), and ships a dev-only/dev/uishowcase with a viewport-width toggle to make future responsive work easier to verify.Component-level fixes
ui_sidebar: nowhidden lg:flex; belowlgit collapses and a daisyUI drawer (ui_mobile_drawer) takes over, surfaced via a hamburger header inLayouts.app. The drawer reuses the same nav slot through extractedsidebar_brand/sidebar_nav/sidebar_footerprivate components.ui_table: action bar wraps, pagination stacksflex-col sm:flex-row, numbered page buttons hidden on xs in favor of "Page X of Y".ui_tabs:overflow-x-auto whitespace-nowrapso 4+ tabs scroll instead of wrapping silently.ui_page_header: stacks actions below title on xs; action buttons become full-width.ui_cardheader:flex-col sm:flex-rowso title + wide actions don't cramp.ui_modal:max-h-[calc(100vh-2rem)]+ internaloverflow-y-autobody; tall content scrolls inside the panel.ui_kv_table: rows stack label-above-value on xs, side-by-side from sm.ui_release_card: metric stripflex-col sm:flex-row.ui_audit_row: timestamp drops below the body on xs, indented to align.ui_card_title: rewritten — the oldflex-1spacer cramped title and meta when the card cell was narrow. Nowflex flex-wrapwithml-autofor the meta badge so each can take the space it needs.Chart resize bug
ui_chart_card+line_chartwere not shrinking when the viewport got smaller. Root cause: the canvas's intrinsic width was pushing the grid cell open, creating a circular ResizeObserver dependency — Chart.js never saw a shrink.Fix:
min-w-0+overflow-hiddenon the card/wrapper,!w-full !max-w-fullon the canvas to defeat Chart.js's inlinewidth: NNNpx, plus awindow.resizefallback in the hook that callschart.resize()defensively.Dev showcase
New LiveView at
/dev/ui(compiled out in:prodviaMix.env()guard in the router). Renders everyui_*component grouped by family with a top-bar width toggle: 375 / 414 / 768 / 1024 / 1440 / full. Used it to do the audit pass for this PR; should make future responsive work much faster.Tests
test/mast_web/components/ui/responsive_test.exs— 13 unit assertions for class hooks on each component, including a regression test for theui_card_titleflex-1 spacer fix.test/mast_web/live/dev_ui_live_test.exs— smoke test for the/dev/uiroute and width toggle.mix precommitclean (format,deps.unlock --unused,credo --strict,test).Verified at
Walked the dashboard, server detail, and
/dev/uiat 500px (Chrome's min — phone-ish), 768px (iPad portrait), 1024px (iPad landscape / small laptop), and 1440px (desktop). No horizontal overflow, no clipped content, sidebar drawer works, charts re-render correctly on resize.Out of scope
buttons.ex/feedback.ex/forms.ex— they were fine as-is per the issue audit.