feat: improve consistency and design (#1867)

Co-authored-by: Meier Lukas <meierschlumpf@gmail.com>
This commit is contained in:
Manuel
2025-01-31 23:32:08 +01:00
committed by GitHub
parent 6a9b65f219
commit 5f36d8b125
21 changed files with 216 additions and 99 deletions

View File

@@ -1,5 +1,5 @@
import type { FocusEventHandler } from "react";
import { startTransition, useState } from "react";
import { startTransition } from "react";
import {
ActionIcon,
Box,
@@ -17,7 +17,7 @@ import {
UnstyledButton,
useCombobox,
} from "@mantine/core";
import { useDebouncedValue } from "@mantine/hooks";
import { useDebouncedValue, useUncontrolled } from "@mantine/hooks";
import { IconUpload } from "@tabler/icons-react";
import { clientApi } from "@homarr/api/client";
@@ -28,17 +28,27 @@ import { UploadMedia } from "~/app/[locale]/manage/medias/_actions/upload-media"
import classes from "./icon-picker.module.css";
interface IconPickerProps {
initialValue?: string;
value?: string;
onChange: (iconUrl: string) => void;
error?: string | null;
onFocus?: FocusEventHandler;
onBlur?: FocusEventHandler;
}
export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: IconPickerProps) => {
const [value, setValue] = useState<string>(initialValue ?? "");
const [search, setSearch] = useState(initialValue ?? "");
const [previewUrl, setPreviewUrl] = useState<string | null>(initialValue ?? null);
export const IconPicker = ({ value: propsValue, onChange, error, onFocus, onBlur }: IconPickerProps) => {
const [value, setValue] = useUncontrolled({
value: propsValue,
onChange,
});
const [search, setSearch] = useUncontrolled({
value,
onChange: (value) => {
setValue(value);
},
});
const [previewUrl, setPreviewUrl] = useUncontrolled({
value: propsValue ?? null,
});
const { data: session } = useSession();
const tCommon = useScopedI18n("common");
@@ -68,10 +78,9 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I
onClick={() => {
const value = item.url;
startTransition(() => {
setValue(value);
setPreviewUrl(value);
setSearch(value);
onChange(value);
setValue(value);
combobox.closeDropdown();
});
}}
@@ -128,7 +137,6 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I
setSearch(event.currentTarget.value);
setValue(event.currentTarget.value);
setPreviewUrl(null);
onChange(event.currentTarget.value);
}}
onClick={() => combobox.openDropdown()}
onFocus={(event) => {
@@ -154,7 +162,6 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I
setValue(url);
setPreviewUrl(url);
setSearch(url);
onChange(url);
});
}}
>

View File

@@ -20,6 +20,7 @@ export const DesktopSearchInput = () => {
size="sm"
leftSection={<IconSearch size={20} stroke={1.5} />}
onClick={openSpotlight}
radius="xl"
>
{`${t("search.placeholder")}...`}
</TextInput>

View File

@@ -1,7 +1,7 @@
import type { JSX } from "react";
import { AppShellNavbar, AppShellSection, ScrollArea } from "@mantine/core";
import { AppShellNavbar, AppShellSection, Image, ScrollArea } from "@mantine/core";
import type { TablerIcon } from "@homarr/ui";
import type { TablerIcon, TablerIconProps } from "@homarr/ui";
import type { ClientNavigationLink } from "./navigation-link";
import { CommonNavLink } from "./navigation-link";
@@ -27,8 +27,13 @@ export const MainNavigation = ({ headerSection, footerSection, links }: MainNavi
return null;
}
const { icon: TablerIcon, ...props } = link;
const Icon = <TablerIcon size={20} stroke={1.5} />;
const { icon: TablerIcon, iconProps, ...props } = link;
const Icon =
typeof TablerIcon === "string" ? (
<Image src={TablerIcon} w={20} h={20} />
) : (
<TablerIcon size={20} stroke={1.5} {...iconProps} />
);
let clientLink: ClientNavigationLink;
if ("items" in props) {
clientLink = {
@@ -38,7 +43,7 @@ export const MainNavigation = ({ headerSection, footerSection, links }: MainNavi
.map((item) => {
return {
...item,
icon: <item.icon size={20} stroke={1.5} />,
icon: <item.icon size={20} stroke={1.5} {...iconProps} />,
};
}),
} as ClientNavigationLink;
@@ -55,7 +60,8 @@ export const MainNavigation = ({ headerSection, footerSection, links }: MainNavi
interface CommonNavigationLinkProps {
label: string;
icon: TablerIcon;
icon: TablerIcon | string;
iconProps?: TablerIconProps;
hidden?: boolean;
}