diff --git a/apps/nextjs/public/images/apps/imdb.png b/apps/nextjs/public/images/apps/imdb.png
deleted file mode 100644
index 9565159a4..000000000
Binary files a/apps/nextjs/public/images/apps/imdb.png and /dev/null differ
diff --git a/apps/nextjs/public/images/apps/imdb.svg b/apps/nextjs/public/images/apps/imdb.svg
new file mode 100644
index 000000000..b2a908bcb
--- /dev/null
+++ b/apps/nextjs/public/images/apps/imdb.svg
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/apps/nextjs/public/images/apps/tmdb.png b/apps/nextjs/public/images/apps/tmdb.png
deleted file mode 100644
index 9f983b883..000000000
Binary files a/apps/nextjs/public/images/apps/tmdb.png and /dev/null differ
diff --git a/apps/nextjs/public/images/apps/tmdb.svg b/apps/nextjs/public/images/apps/tmdb.svg
new file mode 100644
index 000000000..42f31f154
--- /dev/null
+++ b/apps/nextjs/public/images/apps/tmdb.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/apps/nextjs/src/components/icons/picker/icon-picker.tsx b/apps/nextjs/src/components/icons/picker/icon-picker.tsx
index 91983ff7c..bd77a27d5 100644
--- a/apps/nextjs/src/components/icons/picker/icon-picker.tsx
+++ b/apps/nextjs/src/components/icons/picker/icon-picker.tsx
@@ -1,9 +1,23 @@
import type { FocusEventHandler } from "react";
-import { useState } from "react";
-import { Combobox, Group, Image, InputBase, Skeleton, Text, useCombobox } from "@mantine/core";
+import { startTransition, useState } from "react";
+import {
+ Box,
+ Card,
+ Combobox,
+ Flex,
+ Image,
+ Indicator,
+ InputBase,
+ Paper,
+ Skeleton,
+ Stack,
+ Text,
+ UnstyledButton,
+ useCombobox,
+} from "@mantine/core";
import { clientApi } from "@homarr/api/client";
-import { useI18n, useScopedI18n } from "@homarr/translation/client";
+import { useScopedI18n } from "@homarr/translation/client";
interface IconPickerProps {
initialValue?: string;
@@ -18,10 +32,9 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I
const [search, setSearch] = useState(initialValue ?? "");
const [previewUrl, setPreviewUrl] = useState(initialValue ?? null);
- const t = useI18n();
const tCommon = useScopedI18n("common");
- const { data, isFetching } = clientApi.icon.findIcons.useQuery({
+ const [data] = clientApi.icon.findIcons.useSuspenseQuery({
searchText: search,
});
@@ -29,39 +42,53 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I
onDropdownClose: () => combobox.resetSelectedOption(),
});
- const notNullableData = data?.icons ?? [];
-
- const totalOptions = notNullableData.reduce((acc, group) => acc + group.icons.length, 0);
-
- const groups = notNullableData.map((group) => {
+ const totalOptions = data.icons.reduce((acc, group) => acc + group.icons.length, 0);
+ const groups = data.icons.map((group) => {
const options = group.icons.map((item) => (
-
-
-
- {item.name}
-
-
+ {
+ const value = item.url;
+ startTransition(() => {
+ setValue(value);
+ setPreviewUrl(value);
+ setSearch(value);
+ onChange(value);
+ combobox.closeDropdown();
+ });
+ }}
+ key={item.id}
+ >
+
+
+
+
+
+
+
+
));
return (
-
- {options}
-
+
+
+ {group.slug}
+
+
+ {options}
+
+
);
});
return (
- {
- setValue(value);
- setPreviewUrl(value);
- setSearch(value);
- onChange(value);
- combobox.closeDropdown();
- }}
- store={combobox}
- withinPortal
- >
+
}
@@ -91,18 +118,14 @@ export const IconPicker = ({ initialValue, onChange, error, onFocus, onBlur }: I
withAsterisk
error={error}
label={tCommon("iconPicker.label")}
+ placeholder={tCommon("iconPicker.header", { countIcons: data.countIcons })}
/>
-
- {tCommon("iconPicker.header", { countIcons: data?.countIcons })}
-
{totalOptions > 0 ? (
- groups
- ) : !isFetching ? (
- {t("search.nothingFound")}
+ {groups}
) : (
Array(15)
.fill(0)
diff --git a/packages/api/src/router/icons.ts b/packages/api/src/router/icons.ts
index e99918da3..7b7c2f52b 100644
--- a/packages/api/src/router/icons.ts
+++ b/packages/api/src/router/icons.ts
@@ -16,7 +16,7 @@ export const iconsRouter = createTRPCRouter({
url: true,
},
where: (input.searchText?.length ?? 0) > 0 ? like(icons.name, `%${input.searchText}%`) : undefined,
- limit: 5,
+ limit: input.limitPerGroup,
},
},
}),
diff --git a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts
index a562ce2d0..bee8b1d63 100644
--- a/packages/integrations/src/media-organizer/radarr/radarr-integration.ts
+++ b/packages/integrations/src/media-organizer/radarr/radarr-integration.ts
@@ -76,7 +76,7 @@ export class RadarrIntegration extends Integration {
name: "IMDb",
color: "#f5c518",
isDark: false,
- logo: "/images/apps/imdb.png",
+ logo: "/images/apps/imdb.svg",
});
}
diff --git a/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts b/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts
index 0b18e2b0a..faa789b1b 100644
--- a/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts
+++ b/packages/integrations/src/media-organizer/sonarr/sonarr-integration.ts
@@ -75,7 +75,7 @@ export class SonarrIntegration extends Integration {
name: "IMDb",
color: "#f5c518",
isDark: false,
- logo: "/images/apps/imdb.png",
+ logo: "/images/apps/imdb.svg",
});
}
diff --git a/packages/validation/src/icons.ts b/packages/validation/src/icons.ts
index 031878b99..c621ecea5 100644
--- a/packages/validation/src/icons.ts
+++ b/packages/validation/src/icons.ts
@@ -2,6 +2,7 @@ import { z } from "zod";
const findIconsSchema = z.object({
searchText: z.string().optional(),
+ limitPerGroup: z.number().min(1).max(500).default(12),
});
export const iconsSchemas = {