(null);
+ const [large, setLarge] = useState(false);
+
+ useLayoutEffect(() => {
+ const el = containerRef.current;
+ if (!el) {
+ return;
+ }
+
+ const TARGET = 48; // standard bottom-nav touch target (px)
+ const MIN_GAP = 8; // minimum spacing between targets (px)
+
+ const compute = () => {
+ const count = el.children.length;
+ if (count === 0) {
+ return;
+ }
+ const needed = count * TARGET + Math.max(count - 1, 0) * MIN_GAP;
+ setLarge(needed <= el.clientWidth);
+ };
+
+ compute();
+
+ const resize = new ResizeObserver(compute);
+ resize.observe(el);
+ // recompute when items are added/removed (e.g. the status alert appears)
+ const mutation = new MutationObserver(compute);
+ mutation.observe(el, { childList: true });
+
+ return () => {
+ resize.disconnect();
+ mutation.disconnect();
+ };
+ }, [navItems]);
+
return (
{navItems.map((item) => (
-
+
))}
-
-
+
+
);
}
type StatusAlertNavProps = {
className?: string;
+ large?: boolean;
};
-function StatusAlertNav({ className }: StatusAlertNavProps) {
+function StatusAlertNav({ className, large }: StatusAlertNavProps) {
const { t } = useTranslation(["views/system"]);
const { data: initialStats } = useSWR("stats", {
revalidateOnFocus: false,
@@ -105,8 +158,18 @@ function StatusAlertNav({ className }: StatusAlertNavProps) {
return (
-
-
+
+
void;
+ large?: boolean;
};
export default function NavItem({
@@ -34,6 +35,7 @@ export default function NavItem({
item,
Icon,
onClick,
+ large,
}: NavItemProps) {
const { t } = useTranslation(["common"]);
if (item.enabled == false) {
@@ -48,11 +50,12 @@ export default function NavItem({
cn(
"flex flex-col items-center justify-center rounded-lg p-[6px]",
className,
+ large && "size-12",
variants[item.variant ?? "primary"][isActive ? "active" : "inactive"],
)
}
>
-
+
);