mirror of
https://github.com/netbirdio/netbird.git
synced 2026-05-31 13:09:55 +00:00
fix scroll in settings
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -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":
|
||||
|
||||
Reference in New Issue
Block a user