fix: simplify settings layout

This commit is contained in:
ajnart committed 2026-08-20 12:21:35 +02:00
1 parent 62b3c0aa5e
commit 5b41d169c0
3 files changed
+9 -145

No files matched your search

+1 -1
View File
@@ -13,7 +13,7 @@ tags:
The settings page applies options to the whole Homarr application.
Some changes need a full page reload before they take effect.
Use the settings navigation to jump to a section. The highlighted entry follows the section currently in view, and all sections remain visible in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes.
All settings sections remain visible in a single form. Click the **Save changes** button in the save bar at the bottom of the page to apply them. The save bar only appears when you have unsaved changes, and the **Discard** button reverts your changes.
## Analytics
@@ -1,53 +0,0 @@
.layout {
align-items: start;
display: grid;
gap: var(--mantine-spacing-xl);
grid-template-columns: minmax(12rem, 15rem) minmax(0, 1fr);
}
.navigation {
max-height: calc(100vh - var(--app-shell-header-height) - var(--mantine-spacing-xl));
overflow-y: auto;
position: sticky;
top: calc(var(--app-shell-header-height) + var(--mantine-spacing-md));
}
.tableOfContents {
gap: var(--mantine-spacing-xs);
}
.control {
text-align: start;
}
.sections {
min-width: 0;
}
.section {
scroll-margin-top: calc(var(--app-shell-header-height) + var(--mantine-spacing-md));
}
@mixin smaller-than $mantine-breakpoint-sm {
.layout {
gap: var(--mantine-spacing-lg);
grid-template-columns: minmax(0, 1fr);
}
.navigation {
max-height: none;
overflow: hidden;
position: static;
}
.tableOfContents {
flex-direction: row;
overflow-x: auto;
padding-block-end: var(--mantine-spacing-xs);
}
.control {
flex: 0 0 auto;
white-space: nowrap;
}
}
@@ -1,7 +1,7 @@
"use client";
import { useEffect, useRef, useState } from "react";
import { Button, Stack, TableOfContents } from "@mantine/core";
import { Button, Stack } from "@mantine/core";
import { z } from "zod/v4";
import type { RouterOutputs } from "@homarr/api";
@@ -21,7 +21,6 @@ import { BoardSettingsForm } from "./board-settings-form";
import { CrawlingAndIndexingSettings } from "./crawling-and-indexing.settings";
import { CultureSettingsForm } from "./culture-settings-form";
import { SearchSettingsForm } from "./search-settings-form";
import classes from "./settings-form.module.css";
import { UserSettingsForm } from "./user-settings-form";
const settingsFormSchema = z.object({
@@ -170,98 +169,16 @@ export const SettingsForm = ({ initialData, selectableBoards, selectableSearchEn
form.resetDirty();
};
const tableOfContentsData = [
{ id: "settings-board", value: tSettings("section.board.title"), depth: 1 },
{ id: "settings-user", value: tSettings("section.user.title"), depth: 1 },
{ id: "settings-search", value: tSettings("section.search.title"), depth: 1 },
{ id: "settings-appearance", value: tSettings("section.appearance.title"), depth: 1 },
{ id: "settings-culture", value: tSettings("section.culture.title"), depth: 1 },
{ id: "settings-analytics", value: tSettings("section.analytics.title"), depth: 1 },
{ id: "settings-crawling", value: tSettings("section.crawlingAndIndexing.title"), depth: 1 },
];
return (
<form onSubmit={form.onSubmit((values) => void handleSubmitAsync(values))}>
<Stack gap="xl">
<div className={classes.layout}>
<nav className={classes.navigation} aria-label={tSettings("title")}>
<TableOfContents
classNames={{ root: classes.tableOfContents, control: classes.control }}
initialData={tableOfContentsData}
minDepthToOffset={1}
scrollSpyOptions={{
selector: "[data-settings-section]",
getDepth: () => 1,
getValue: (element) => element.getAttribute("data-label") ?? "",
offset: 80,
}}
getControlProps={({ data }) => ({
onClick: () => data.getNode().scrollIntoView({ block: "start" }),
children: data.value,
})}
variant="light"
/>
</nav>
<Stack className={classes.sections} gap="xl">
<section
id="settings-board"
className={classes.section}
data-settings-section
data-label={tSettings("section.board.title")}
>
<BoardSettingsForm form={form} selectableBoards={selectableBoards} />
</section>
<section
id="settings-user"
className={classes.section}
data-settings-section
data-label={tSettings("section.user.title")}
>
<UserSettingsForm form={form} />
</section>
<section
id="settings-search"
className={classes.section}
data-settings-section
data-label={tSettings("section.search.title")}
>
<SearchSettingsForm form={form} selectableSearchEngines={selectableSearchEngines} />
</section>
<section
id="settings-appearance"
className={classes.section}
data-settings-section
data-label={tSettings("section.appearance.title")}
>
<AppearanceSettingsForm form={form} />
</section>
<section
id="settings-culture"
className={classes.section}
data-settings-section
data-label={tSettings("section.culture.title")}
>
<CultureSettingsForm form={form} />
</section>
<section
id="settings-analytics"
className={classes.section}
data-settings-section
data-label={tSettings("section.analytics.title")}
>
<AnalyticsSettings form={form} />
</section>
<section
id="settings-crawling"
className={classes.section}
data-settings-section
data-label={tSettings("section.crawlingAndIndexing.title")}
>
<CrawlingAndIndexingSettings form={form} />
</section>
</Stack>
</div>
<BoardSettingsForm form={form} selectableBoards={selectableBoards} />
<UserSettingsForm form={form} />
<SearchSettingsForm form={form} selectableSearchEngines={selectableSearchEngines} />
<AppearanceSettingsForm form={form} />
<CultureSettingsForm form={form} />
<AnalyticsSettings form={form} />
<CrawlingAndIndexingSettings form={form} />
{form.isDirty() && (
<UnsavedChangesBar>