fix scroll in settings

This commit is contained in:
Eduard Gert
2026-05-22 16:09:55 +02:00
parent 598fcbd817
commit 8f957ff41a
4 changed files with 37 additions and 52 deletions

View File

@@ -5,7 +5,7 @@ import Button from "@/components/Button";
import { HelpText } from "@/components/HelpText";
import { Input } from "@/components/Input";
import { Label } from "@/components/Label";
import { SectionGroup } from "@/modules/settings/SettingsSection.tsx";
import { SectionGroup, SettingsBottomBar } from "@/modules/settings/SettingsSection.tsx";
import { useSettings } from "@/modules/settings/SettingsContext.tsx";
// macOS: the Darwin utun control socket parses the digits after "utun" as the
@@ -139,18 +139,16 @@ export function SettingsAdvanced() {
</div>
</SectionGroup>
<div className={"absolute bottom-0 left-0 w-full"}>
<div className={"w-full flex justify-end px-8 py-5 border-t border-nb-gray-910"}>
<Button
variant={"primary"}
size={"md"}
disabled={!hasChanges || saving || hasErrors}
onClick={handleSave}
>
{t("common.saveChanges")}
</Button>
</div>
</div>
<SettingsBottomBar>
<Button
variant={"primary"}
size={"md"}
disabled={!hasChanges || saving || hasErrors}
onClick={handleSave}
>
{t("common.saveChanges")}
</Button>
</SettingsBottomBar>
</>
);
}

View File

@@ -1,4 +1,4 @@
import { useLayoutEffect, useRef, useState, type ReactNode } from "react";
import { useLayoutEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { Dialogs } from "@wailsio/runtime";
import { CircleMinus, PlusCircle, Trash2, UserCircle } from "lucide-react";
@@ -11,7 +11,7 @@ import { pickProfileIcon } from "@/components/ProfileAvatar";
import { Tooltip } from "@/components/Tooltip";
import i18next from "@/lib/i18n";
import { useProfile } from "@/modules/profile/ProfileContext";
import { SectionGroup } from "@/modules/settings/SettingsSection.tsx";
import { SectionGroup, SettingsBottomBar } from "@/modules/settings/SettingsSection.tsx";
import { cn } from "@/lib/cn";
import { formatErrorMessage } from "@/lib/errors";
@@ -104,10 +104,6 @@ export function SettingsProfiles() {
<div
className={cn(
"bg-nb-gray-930/60 border border-nb-gray-900 rounded-xl overflow-hidden",
// Leave room for the absolutely positioned BottomBar
// (~76px) so the last row isn't hidden behind it when
// the list fills the scroll area.
"mb-20",
)}
>
<table className={"w-full text-sm"}>
@@ -141,12 +137,12 @@ export function SettingsProfiles() {
)}
</div>
<BottomBar>
<SettingsBottomBar>
<Button variant={"primary"} size={"md"} onClick={() => setNewOpen(true)}>
<PlusCircle size={14} />
{t("settings.profiles.addProfile")}
</Button>
</BottomBar>
</SettingsBottomBar>
</SectionGroup>
<NewProfileModal open={newOpen} onOpenChange={setNewOpen} onCreate={handleCreate} />
@@ -154,20 +150,6 @@ export function SettingsProfiles() {
);
}
function BottomBar({ children }: { children: ReactNode }) {
return (
<div className={"absolute bottom-0 left-0 w-full"}>
<div
className={
"w-full flex justify-end gap-3 px-8 py-5 border-t border-nb-gray-900 bg-nb-gray-935"
}
>
{children}
</div>
</div>
);
}
type ProfileRowProps = {
profile: Profile;
isActive: boolean;

View File

@@ -17,3 +17,22 @@ export const SectionGroup = ({
<div className={"flex flex-col gap-5"}>{children}</div>
</section>
);
// SettingsBottomBar renders the floating action bar at the bottom of a
// settings tab (Save Changes / Add Profile / Create Bundle). It pairs the
// absolutely positioned bar with an in-flow spacer of the same height so
// scrollable content above doesn't end up hidden behind the bar.
export const SettingsBottomBar = ({ children }: { children: ReactNode }) => (
<>
<div className={"h-[4.5rem] shrink-0"} aria-hidden />
<div className={"absolute bottom-0 left-0 w-full"}>
<div
className={
"w-full flex justify-end gap-3 px-8 py-5 border-t border-nb-gray-900 bg-nb-gray-935"
}
>
{children}
</div>
</div>
</>
);

View File

@@ -15,7 +15,7 @@ import { SquareIcon } from "@/components/SquareIcon";
import { cn } from "@/lib/cn";
import type { DebugStage } from "@/modules/debug-bundle/useDebugBundle.ts";
import { useDebugBundleContext } from "@/modules/debug-bundle/useDebugBundleContext.ts";
import { SectionGroup } from "@/modules/settings/SettingsSection.tsx";
import { SectionGroup, SettingsBottomBar } from "@/modules/settings/SettingsSection.tsx";
export function SettingsTroubleshooting() {
const { t } = useTranslation();
@@ -106,11 +106,11 @@ export function SettingsTroubleshooting() {
</div>
</div>
<BottomBar>
<SettingsBottomBar>
<Button variant={"primary"} size={"md"} onClick={run}>
{t("settings.troubleshooting.create")}
</Button>
</BottomBar>
</SettingsBottomBar>
</SectionGroup>
);
}
@@ -265,20 +265,6 @@ function DoneResult({
);
}
function BottomBar({ children }: { children: ReactNode }) {
return (
<div className={"absolute bottom-0 left-0 w-full"}>
<div
className={
"w-full flex justify-end gap-3 px-8 py-5 border-t border-nb-gray-900 bg-nb-gray-935"
}
>
{children}
</div>
</div>
);
}
const stageLabel = (stage: DebugStage, t: (key: string, options?: Record<string, unknown>) => string): string => {
switch (stage.kind) {
case "preparing-trace":