From f059a23ecc26388cc32e001d8842427604625746 Mon Sep 17 00:00:00 2001 From: Nico <47644445+nicotsx@users.noreply.github.com> Date: Tue, 17 Feb 2026 18:44:22 +0100 Subject: [PATCH] fix: multiple mobile and responsiveness issues (#537) * fix: multiple mobile and responsiveness issues fix(mobile): scroll reset on snapshot selection fix(mobile): layout improvements refactor(volume-details): improve layout refactor: better card breakpoints layouts in backps list fix(ui): keep sidebar in the state it was before reloading refactor(ui): keep the same grid size in all breakpoints refactor: manual hotkey devpanel to tanstack hotkeys * chore: pr feedback --- AGENTS.md | 1 + app/app.css | 17 +- app/client/components/app-sidebar.tsx | 4 +- app/client/components/dev-panel-listener.tsx | 41 +---- app/client/components/grid-background.tsx | 2 +- app/client/components/layout.tsx | 8 +- app/client/components/ui/sidebar.tsx | 2 +- .../components/snapshot-file-browser.tsx | 10 +- .../modules/backups/routes/backup-details.tsx | 1 + app/client/modules/backups/routes/backups.tsx | 4 +- .../modules/backups/routes/create-backup.tsx | 2 +- app/client/modules/repositories/tabs/info.tsx | 12 +- .../modules/volumes/routes/volume-details.tsx | 145 +----------------- app/client/modules/volumes/tabs/info.tsx | 116 +++++++++++++- app/context.ts | 1 + app/routes/(dashboard)/route.tsx | 8 +- app/routes/__root.tsx | 4 - bun.lock | 5 + package.json | 1 + 19 files changed, 175 insertions(+), 209 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index d54b9a50..a1ce055b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,6 +4,7 @@ - Never create migration files manually. Always use the provided command to generate migrations - If you realize an automated migration is incorrect, make sure to remove all the associated entries from the `_journal.json` and the newly created files located in `app/drizzle/` before re-generating the migration +- The dev server is running at http://localhost:3000. Username is `admin` and password is `password` ## Project Overview diff --git a/app/app.css b/app/app.css index db5fb356..15a1e65c 100644 --- a/app/app.css +++ b/app/app.css @@ -5,7 +5,16 @@ @custom-variant dark (&:is(.dark *)); +@custom-variant @narrow (@container (min-width: 28rem)); +@custom-variant @medium (@container (min-width: 40rem)); +@custom-variant @wide (@container (min-width: 60rem)); +@custom-variant @xwide (@container (min-width: 80rem)); + @theme { + --container-narrow: 28rem; + --container-medium: 40rem; + --container-wide: 60rem; + --container-xwide: 80rem; --breakpoint-xs: 32rem; --font-sans: "Google Sans Code", ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", @@ -17,10 +26,16 @@ body { overflow-x: hidden; width: 100%; position: relative; - overscroll-behavior: none; scrollbar-width: thin; } +@media (min-width: 48rem) { + html, + body { + overscroll-behavior: none; + } +} + body { @apply bg-[#131313]; min-height: 100dvh; diff --git a/app/client/components/app-sidebar.tsx b/app/client/components/app-sidebar.tsx index 9081013e..317e5cea 100644 --- a/app/client/components/app-sidebar.tsx +++ b/app/client/components/app-sidebar.tsx @@ -49,7 +49,7 @@ const items = [ ]; export function AppSidebar() { - const { state } = useSidebar(); + const { state, isMobile, setOpenMobile } = useSidebar(); const { updates, hasUpdate } = useUpdates(); const [showReleaseNotes, setShowReleaseNotes] = useState(false); @@ -83,7 +83,7 @@ export function AppSidebar() { - + isMobile && setOpenMobile(false)}> {({ isActive }) => ( <> diff --git a/app/client/components/dev-panel-listener.tsx b/app/client/components/dev-panel-listener.tsx index 9acad0de..d14d3e67 100644 --- a/app/client/components/dev-panel-listener.tsx +++ b/app/client/components/dev-panel-listener.tsx @@ -1,51 +1,18 @@ -import { useEffect, useState, useCallback, useRef } from "react"; +import { useState } from "react"; import { useQuery } from "@tanstack/react-query"; +import { useHotkey } from "@tanstack/react-hotkeys"; import { getDevPanelOptions } from "~/client/api-client/@tanstack/react-query.gen"; import { DevPanel } from "./dev-panel"; export function DevPanelListener() { const [isOpen, setIsOpen] = useState(false); - const pressedKeysRef = useRef>(new Set()); - const { data: devPanelStatus } = useQuery({ ...getDevPanelOptions(), }); - const isEnabled = devPanelStatus?.enabled ?? false; + useHotkey("Mod+Shift+D", () => setIsOpen(true), { enabled: !!devPanelStatus?.enabled, preventDefault: true }); - const handleKeyDown = useCallback( - (e: KeyboardEvent) => { - if (!isEnabled) return; - pressedKeysRef.current.add(e.key.toLowerCase()); - - const keys = pressedKeysRef.current; - if (keys.has("d") && keys.has("e") && keys.has("v")) { - setIsOpen(true); - pressedKeysRef.current.clear(); - } - }, - [isEnabled], - ); - - const handleKeyUp = useCallback( - (e: KeyboardEvent) => { - if (!isEnabled) return; - pressedKeysRef.current.delete(e.key.toLowerCase()); - }, - [isEnabled], - ); - - useEffect(() => { - window.addEventListener("keydown", handleKeyDown); - window.addEventListener("keyup", handleKeyUp); - - return () => { - window.removeEventListener("keydown", handleKeyDown); - window.removeEventListener("keyup", handleKeyUp); - }; - }, [handleKeyDown, handleKeyUp]); - - if (!isEnabled) { + if (!devPanelStatus?.enabled) { return null; } diff --git a/app/client/components/grid-background.tsx b/app/client/components/grid-background.tsx index 78c14aa7..649ddffd 100644 --- a/app/client/components/grid-background.tsx +++ b/app/client/components/grid-background.tsx @@ -12,7 +12,7 @@ export function GridBackground({ children, className, containerClassName }: Grid
+ -
+
@@ -66,9 +66,9 @@ export function Layout({ loaderData }: Props) { )}
-
+
-
+
diff --git a/app/client/components/ui/sidebar.tsx b/app/client/components/ui/sidebar.tsx index 910df642..82402e17 100644 --- a/app/client/components/ui/sidebar.tsx +++ b/app/client/components/ui/sidebar.tsx @@ -14,7 +14,7 @@ import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from " import { Skeleton } from "~/client/components/ui/skeleton"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "~/client/components/ui/tooltip"; -const SIDEBAR_COOKIE_NAME = "sidebar_state"; +export const SIDEBAR_COOKIE_NAME = "sidebar_state"; const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; const SIDEBAR_WIDTH = "14rem"; const SIDEBAR_WIDTH_MOBILE = "18rem"; diff --git a/app/client/modules/backups/components/snapshot-file-browser.tsx b/app/client/modules/backups/components/snapshot-file-browser.tsx index a12942bf..2fd534bc 100644 --- a/app/client/modules/backups/components/snapshot-file-browser.tsx +++ b/app/client/modules/backups/components/snapshot-file-browser.tsx @@ -86,16 +86,20 @@ export const SnapshotFileBrowser = (props: Props) => {
-
+
File Browser {`Viewing snapshot from ${formatDateTime(snapshot?.time)}`}
-
+
({ ...searchParams, snapshot: snapshotId }), + resetScroll: false, }); }; diff --git a/app/client/modules/backups/routes/backups.tsx b/app/client/modules/backups/routes/backups.tsx index 6524a85c..21ea8a42 100644 --- a/app/client/modules/backups/routes/backups.tsx +++ b/app/client/modules/backups/routes/backups.tsx @@ -97,10 +97,10 @@ export function BackupsPage() { const scheduleMap = new Map(schedules.map((s) => [s.id, s])); return ( -
+
-
+
{items.map((id) => { const schedule = scheduleMap.get(id); if (!schedule) return null; diff --git a/app/client/modules/backups/routes/create-backup.tsx b/app/client/modules/backups/routes/create-backup.tsx index a5ffb1a6..3a6be4a0 100644 --- a/app/client/modules/backups/routes/create-backup.tsx +++ b/app/client/modules/backups/routes/create-backup.tsx @@ -110,7 +110,7 @@ export function CreateBackupPage() { } return ( -
+