Revert "feat(header): add opt-in auto-hide-on-scroll for the header (#6738)" (#6740)

This reverts commit e58c229664.
This commit is contained in:
Bergasha authored and GitHub committed 2026-08-29 15:19:20 +10:00
1 parent e58c229664
commit ea250d418d
11 files changed
+2 -107

No files matched your search

-11
View File
@@ -77,17 +77,6 @@ Choose the first day of the week for the user. This will affect the calendar wid
Option to show icons for status check instead of colored dots.
#### Header studio
Personal control over what appears in the header and where. Drag controls between the Left, Center, and Right
sections, add optional board shortcuts, and choose how the search and logo controls are displayed.
The header can be hidden entirely with the visibility toggle. While hidden, hovering the top edge of the page
reveals it temporarily; clicking inside it pins it open until the page is refreshed or you click elsewhere.
When the header is visible, the **Auto-hide on scroll** toggle makes it slide away while scrolling down and
reappear on scroll-up or near the top of the page. It has no effect while the header itself is hidden.
#### Delete
This action will permanently delete the user from the database, including any preferences they set.
-4
View File
@@ -4391,10 +4391,6 @@
"type": "string",
"enum": ["logo", "logoAndText"]
},
"autoHideOnScroll": {
"default": false,
"type": "boolean"
},
"zones": {
"type": "object",
"properties": {
@@ -18,7 +18,6 @@ import {
Paper,
SegmentedControl,
Stack,
Switch,
Text,
ThemeIcon,
Tooltip,
@@ -203,16 +202,7 @@ export const HeaderComposer = ({ value, onChange, boards, homeBoardId }: HeaderC
{t("description")}
</Text>
</Stack>
<Group gap="sm">
<Tooltip label={t("action.autoHideOnScrollDescription")} disabled={!value.visible}>
<Switch
size="sm"
label={t("action.autoHideOnScroll")}
checked={value.autoHideOnScroll}
disabled={!value.visible}
onChange={(event) => onChange({ ...value, autoHideOnScroll: event.currentTarget.checked })}
/>
</Tooltip>
<Group gap="xs">
<Tooltip label={value.visible ? t("action.hide") : t("action.show")}>
<ActionIcon
size="lg"
@@ -1,16 +1,11 @@
.header {
overflow: hidden;
transition: transform 220ms ease;
}
.header[data-visible="false"] {
display: none;
}
.header[data-auto-hidden="true"]:not(:focus-within) {
transform: translateY(-100%);
}
.desktopContent {
width: 100%;
height: 100%;
@@ -181,7 +176,6 @@
}
@media (prefers-reduced-motion: reduce) {
.header,
.floatingControls {
transition: none;
}
@@ -7,7 +7,6 @@ import { IconBrandDocker, IconHome, IconReplace, IconRobot, IconSettings, IconSu
import type { RouterOutputs } from "@homarr/api";
import { clientApi } from "@homarr/api/client";
import { useOptionalEditMode } from "@homarr/boards/edit-mode";
import { invariantTechnicalLabels } from "@homarr/definitions";
import { useModalAction } from "@homarr/modals";
import { useSettings } from "@homarr/settings";
@@ -25,7 +24,6 @@ import { HeaderLogo } from "./header-logo";
import { LazySpotlight } from "./lazy-spotlight";
import { DesktopSearchInput, MobileSearchButton } from "./search";
import { TourTarget } from "./tour-target";
import { useHeaderAutoHide } from "./use-header-auto-hide";
import { UserButtonClient } from "./user-client";
import classes from "./configurable-header.module.css";
@@ -71,10 +69,6 @@ export const ConfigurableHeader = ({
staleTime: 60_000,
});
const boardsById = useMemo(() => new Map(boards.map((board) => [board.id, board])), [boards]);
const isEditMode = useOptionalEditMode();
const isAutoHidden = useHeaderAutoHide(
headerPreferences.visible && headerPreferences.autoHideOnScroll && !isEditMode,
);
return (
<BoardSwitcher>
@@ -120,7 +114,6 @@ export const ConfigurableHeader = ({
zIndex="var(--homarr-z-index-board-header)"
className={classes.header}
data-visible={headerPreferences.visible}
data-auto-hidden={isAutoHidden || undefined}
data-advanced-focus-background
data-app-shell-header
>
@@ -1,48 +0,0 @@
"use client";
import { useEffect, useRef, useState } from "react";
const SCROLL_HIDE_THRESHOLD = 24;
const SCROLL_DIRECTION_HYSTERESIS = 6;
export const useHeaderAutoHide = (enabled: boolean) => {
const [isHidden, setIsHidden] = useState(false);
const lastScrollYRef = useRef(0);
useEffect(() => {
if (!enabled) {
setIsHidden(false);
return;
}
lastScrollYRef.current = window.scrollY;
let frame: number | null = null;
const handleScroll = () => {
if (frame !== null) return;
frame = window.requestAnimationFrame(() => {
frame = null;
const currentY = window.scrollY;
const delta = currentY - lastScrollYRef.current;
if (currentY <= SCROLL_HIDE_THRESHOLD) {
setIsHidden(false);
} else if (delta > SCROLL_DIRECTION_HYSTERESIS) {
setIsHidden(true);
} else if (delta < -SCROLL_DIRECTION_HYSTERESIS) {
setIsHidden(false);
}
lastScrollYRef.current = currentY;
});
};
window.addEventListener("scroll", handleScroll, { passive: true });
return () => {
window.removeEventListener("scroll", handleScroll);
if (frame !== null) window.cancelAnimationFrame(frame);
};
}, [enabled]);
return enabled && isHidden;
};
-1
View File
@@ -14,7 +14,6 @@
"check:custom-widgets": "pnpm --filter @homarr/custom-widgets check:architecture",
"check:custom-widget-bundle": "node ./scripts/check-custom-widget-bundle.mjs",
"check:openapi": "tsx ./scripts/check-openapi-schema.mts",
"generate:openapi": "tsx ./scripts/generate-openapi-schema.mts",
"ci:act:all": "bash scripts/ci/act.sh all",
"ci:act:cleanup": "bash scripts/ci/act.sh cleanup",
"ci:act:docker": "bash scripts/ci/act.sh docker",
-5
View File
@@ -26,8 +26,3 @@ export const useEditMode = () => {
return context;
};
export const useOptionalEditMode = (): boolean => {
const context = useContext(EditModeContext);
return context ? context[0] : false;
};
+1 -3
View File
@@ -5725,9 +5725,7 @@
"show": "Show the header",
"configure": "Move or configure {item}",
"remove": "Remove {item}",
"dropIntoZone": "Move into the {zone} section",
"autoHideOnScroll": "Auto-hide on scroll",
"autoHideOnScrollDescription": "Slides the header away while scrolling down and brings it back when scrolling up"
"dropIntoZone": "Move into the {zone} section"
},
"preview": {
"board": "Dashboard preview for {name}",
@@ -105,7 +105,6 @@ export const headerPreferencesSchema = z
visible: z.boolean(),
searchDisplay: z.enum(headerSearchDisplayValues),
logoDisplay: z.enum(headerLogoDisplayValues).default("logoAndText"),
autoHideOnScroll: z.boolean().default(false),
zones: headerZonesSchema,
})
.strict();
@@ -156,7 +155,6 @@ const migrateLegacyItems = (
visible,
searchDisplay: "input",
logoDisplay: "logoAndText",
autoHideOnScroll: false,
zones: {
left: zones.left.map(createBuiltinHeaderItem),
center: zones.center.map(createBuiltinHeaderItem),
@@ -211,7 +209,6 @@ export const defaultHeaderPreferences = {
visible: true,
searchDisplay: "input",
logoDisplay: "logoAndText",
autoHideOnScroll: false,
zones: {
left: [createBuiltinHeaderItem("logo")],
center: [createBuiltinHeaderItem("search")],
-8
View File
@@ -1,8 +0,0 @@
import { writeFile } from "node:fs/promises";
import { openApiDocument } from "../packages/api/src/open-api";
const baseUrl = "http://localhost:3000";
const generated = openApiDocument(baseUrl);
await writeFile("apps/docs/static/api/open-api-schema.json", `${JSON.stringify(generated, null, 2)}\n`, "utf8");