fix: polish settings and command menu
This commit is contained in:
9 files changed
+37
-68
No files matched your search
@@ -53,7 +53,7 @@ export default async function BoardSettingsPage(props: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Container size="xl">
|
||||
<Stack>
|
||||
<Title>{t("title", { boardName: capitalize(board.name) })}</Title>
|
||||
<BoardSettingsForm
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
"use client";
|
||||
|
||||
import { Anchor } from "@mantine/core";
|
||||
import { IconExternalLink } from "@tabler/icons-react";
|
||||
|
||||
import { createDocumentationLink } from "@homarr/definitions";
|
||||
import type { UseFormReturnType } from "@homarr/form";
|
||||
import { useScopedI18n } from "@homarr/translation/client";
|
||||
|
||||
@@ -12,11 +16,25 @@ interface AnalyticsSettingsProps {
|
||||
}
|
||||
|
||||
export const AnalyticsSettings = ({ form }: AnalyticsSettingsProps) => {
|
||||
const t = useScopedI18n("management.page.settings.section.analytics");
|
||||
const t = useScopedI18n("management.page.settings.section");
|
||||
|
||||
return (
|
||||
<SectionCard title={t("title")}>
|
||||
<SwitchSetting form={form} formKey="enableGeneral" title={t("general.title")} text={t("general.text")} />
|
||||
<SectionCard title={t("analytics.title")}>
|
||||
<SwitchSetting
|
||||
form={form}
|
||||
formKey="enableGeneral"
|
||||
title={t("analytics.general.title")}
|
||||
text={t("analytics.general.text")}
|
||||
/>
|
||||
<Anchor
|
||||
href={createDocumentationLink("/docs/management/settings", "#analytics")}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
size="sm"
|
||||
>
|
||||
{t("analyticsDocumentation")}
|
||||
<IconExternalLink size={14} style={{ marginInlineStart: 4, verticalAlign: "middle" }} />
|
||||
</Anchor>
|
||||
</SectionCard>
|
||||
);
|
||||
};
|
||||
@@ -1,11 +1,10 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { Stack, Title } from "@mantine/core";
|
||||
|
||||
import { api } from "@homarr/api/server";
|
||||
import { auth } from "@homarr/auth/next";
|
||||
import { getScopedI18n } from "@homarr/translation/server";
|
||||
|
||||
import { DynamicBreadcrumb } from "~/components/navigation/dynamic-breadcrumb";
|
||||
import { ManagePageLayout } from "~/components/manage/manage-page-layout";
|
||||
import { SettingsForm } from "./_components/settings-form";
|
||||
|
||||
export async function generateMetadata() {
|
||||
@@ -28,12 +27,8 @@ export default async function SettingsPage() {
|
||||
const tSettings = await getScopedI18n("management.page.settings");
|
||||
|
||||
return (
|
||||
<>
|
||||
<DynamicBreadcrumb />
|
||||
<Stack>
|
||||
<Title order={1}>{tSettings("title")}</Title>
|
||||
<SettingsForm initialData={serverSettings} />
|
||||
</Stack>
|
||||
</>
|
||||
<ManagePageLayout title={tSettings("title")}>
|
||||
<SettingsForm initialData={serverSettings} />
|
||||
</ManagePageLayout>
|
||||
);
|
||||
}
|
||||
@@ -22,7 +22,6 @@ export default async function WorkshopPage() {
|
||||
return (
|
||||
<ManagePageLayout
|
||||
title={t("title")}
|
||||
size="xl"
|
||||
primaryAction={
|
||||
<Button
|
||||
component="a"
|
||||
|
||||
@@ -1,38 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Center, Loader, Paper } from "@mantine/core";
|
||||
import { useHotkeys } from "@mantine/hooks";
|
||||
|
||||
import { hotkeys } from "@homarr/definitions";
|
||||
import { Spotlight } from "@homarr/spotlight/component";
|
||||
import { hasPendingSpotlightOpen, openSpotlight, spotlightOpenEvent } from "@homarr/spotlight/open";
|
||||
|
||||
const loadSpotlight = () => import("@homarr/spotlight/component");
|
||||
const SpotlightLoading = () => (
|
||||
<Center
|
||||
data-homarr-dev-benchmark-spotlight-feedback
|
||||
pos="fixed"
|
||||
inset={0}
|
||||
role="status"
|
||||
aria-label="Loading search"
|
||||
style={{ zIndex: 1000, background: "rgb(0 0 0 / 20%)", backdropFilter: "blur(2px)" }}
|
||||
>
|
||||
<Paper withBorder radius="md" p="xl" shadow="xl">
|
||||
<Loader />
|
||||
</Paper>
|
||||
</Center>
|
||||
);
|
||||
const Spotlight = dynamic(() => loadSpotlight().then(({ Spotlight: Component }) => Component), {
|
||||
ssr: false,
|
||||
loading: SpotlightLoading,
|
||||
});
|
||||
|
||||
export const preloadSpotlight = () => void loadSpotlight().catch(() => undefined);
|
||||
|
||||
export const LazySpotlight = () => {
|
||||
const [isMounted, setIsMounted] = useState(false);
|
||||
const [isPreloaded, setIsPreloaded] = useState(false);
|
||||
|
||||
useHotkeys(
|
||||
isMounted
|
||||
@@ -49,41 +25,27 @@ export const LazySpotlight = () => {
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
let isActive = true;
|
||||
const mount = () => setIsMounted(true);
|
||||
window.addEventListener(spotlightOpenEvent, mount);
|
||||
if (hasPendingSpotlightOpen()) mount();
|
||||
|
||||
const preload = () => {
|
||||
void loadSpotlight().then(
|
||||
() => {
|
||||
if (isActive) setIsPreloaded(true);
|
||||
},
|
||||
() => undefined,
|
||||
);
|
||||
};
|
||||
let idleId: number | undefined;
|
||||
const delayId = window.setTimeout(() => {
|
||||
idleId = window.requestIdleCallback?.(preload, { timeout: 1_000 });
|
||||
if (idleId === undefined) preload();
|
||||
idleId = window.requestIdleCallback?.(mount, { timeout: 1_000 });
|
||||
if (idleId === undefined) mount();
|
||||
}, 1_000);
|
||||
return () => {
|
||||
isActive = false;
|
||||
window.removeEventListener(spotlightOpenEvent, mount);
|
||||
window.clearTimeout(delayId);
|
||||
if (idleId !== undefined) window.cancelIdleCallback?.(idleId);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return isMounted || isPreloaded ? (
|
||||
return isMounted ? (
|
||||
<>
|
||||
{isPreloaded && <span hidden data-homarr-dev-benchmark-spotlight-preloaded />}
|
||||
{isMounted && (
|
||||
<>
|
||||
<span hidden data-homarr-dev-benchmark-spotlight-mounted />
|
||||
<Spotlight />
|
||||
</>
|
||||
)}
|
||||
<span hidden data-homarr-dev-benchmark-spotlight-preloaded />
|
||||
<span hidden data-homarr-dev-benchmark-spotlight-mounted />
|
||||
<Spotlight />
|
||||
</>
|
||||
) : null;
|
||||
};
|
||||
@@ -8,7 +8,6 @@ import { useI18n } from "@homarr/translation/client";
|
||||
|
||||
import { HeaderButton } from "./button";
|
||||
import classes from "./search.module.css";
|
||||
import { preloadSpotlight } from "./lazy-spotlight";
|
||||
|
||||
export const DesktopSearchInput = () => {
|
||||
const t = useI18n();
|
||||
@@ -22,9 +21,6 @@ export const DesktopSearchInput = () => {
|
||||
size="sm"
|
||||
leftSection={<IconSearch size={20} stroke={1.5} />}
|
||||
onClick={openSpotlight}
|
||||
onFocus={preloadSpotlight}
|
||||
onPointerDown={preloadSpotlight}
|
||||
onPointerEnter={preloadSpotlight}
|
||||
radius="xl"
|
||||
>
|
||||
{`${t("search.placeholder")}...`}
|
||||
@@ -37,9 +33,6 @@ export const MobileSearchButton = () => {
|
||||
<HeaderButton
|
||||
data-homarr-dev-benchmark-interaction="search"
|
||||
onClick={openSpotlight}
|
||||
onFocus={preloadSpotlight}
|
||||
onPointerDown={preloadSpotlight}
|
||||
onPointerEnter={preloadSpotlight}
|
||||
className={classes.mobileSearch}
|
||||
>
|
||||
<IconSearch size={20} stroke={1.5} />
|
||||
|
||||
@@ -13,8 +13,8 @@ export const UnsavedChangesBar = ({ children }: UnsavedChangesBarProps) => {
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<div style={{ position: "sticky", bottom: 20 }}>
|
||||
<Card withBorder>
|
||||
<div style={{ position: "sticky", bottom: 20, zIndex: "var(--mantine-z-index-app)" }}>
|
||||
<Card withBorder bg="var(--mantine-color-body)">
|
||||
<Group justify="space-between" wrap="wrap">
|
||||
<Text fw={500}>{t("common.unsavedChanges")}</Text>
|
||||
<Group>{children}</Group>
|
||||
|
||||
@@ -92,6 +92,7 @@ describe("lazy widget application graph", () => {
|
||||
timeout: 15_000,
|
||||
});
|
||||
await page.keyboard.press("Control+K");
|
||||
await expect(page.locator("[data-homarr-dev-benchmark-spotlight-feedback]")).toHaveCount(0);
|
||||
await expect(page.locator("[data-homarr-dev-benchmark-spotlight]")).toBeVisible({ timeout: 15_000 });
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(page.locator("[data-homarr-dev-benchmark-spotlight]")).not.toBeVisible();
|
||||
|
||||
@@ -5199,6 +5199,7 @@
|
||||
}
|
||||
},
|
||||
"section": {
|
||||
"analyticsDocumentation": "See exactly what analytics data Homarr collects",
|
||||
"analytics": {
|
||||
"title": "Analytics",
|
||||
"general": {
|
||||
|
||||
Reference in new issue
Block a user