feat: add improved search (#1051)
* feat: add improved search * wip: add support for sorting, rename use-options to use-query-options, add use-options for local usage, add pages search group * feat: add help links from manage layout to help search mode * feat: add additional search engines * feat: add group search details * refactor: improve users search group type * feat: add apps search group, add disabled search interaction * feat: add integrations and boards for search * wip: hook issue with react * fix: hook issue regarding actions and interactions * chore: address pull request feedback * fix: format issues * feat: add additional global actions to search * chore: remove unused code * fix: search engine short key * fix: typecheck issues * fix: deepsource issues * fix: eslint issue * fix: lint issues * fix: unordered dependencies * chore: address pull request feedback
This commit is contained in:
65
packages/spotlight/src/modes/command/children/language.tsx
Normal file
65
packages/spotlight/src/modes/command/children/language.tsx
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Group, Stack, Text } from "@mantine/core";
|
||||
import { IconCheck } from "@tabler/icons-react";
|
||||
|
||||
import { localeAttributes, supportedLanguages } from "@homarr/translation";
|
||||
import { useChangeLocale, useCurrentLocale, useI18n } from "@homarr/translation/client";
|
||||
|
||||
import { createChildrenOptions } from "../../../lib/children";
|
||||
|
||||
export const languageChildrenOptions = createChildrenOptions<Record<string, unknown>>({
|
||||
useActions: (_, query) => {
|
||||
const normalizedQuery = query.trim().toLowerCase();
|
||||
const currentLocale = useCurrentLocale();
|
||||
return supportedLanguages
|
||||
.map((localeKey) => ({ localeKey, attributes: localeAttributes[localeKey] }))
|
||||
.filter(
|
||||
({ attributes }) =>
|
||||
attributes.name.toLowerCase().includes(normalizedQuery) ||
|
||||
attributes.translatedName.toLowerCase().includes(normalizedQuery),
|
||||
)
|
||||
.sort(
|
||||
(languageA, languageB) =>
|
||||
Math.min(
|
||||
languageA.attributes.name.toLowerCase().indexOf(normalizedQuery),
|
||||
languageA.attributes.translatedName.toLowerCase().indexOf(normalizedQuery),
|
||||
) -
|
||||
Math.min(
|
||||
languageB.attributes.name.toLowerCase().indexOf(normalizedQuery),
|
||||
languageB.attributes.translatedName.toLowerCase().indexOf(normalizedQuery),
|
||||
),
|
||||
)
|
||||
.map(({ localeKey, attributes }) => ({
|
||||
key: localeKey,
|
||||
component() {
|
||||
return (
|
||||
<Group mx="md" my="sm" wrap="nowrap" justify="space-between" w="100%">
|
||||
<Group wrap="nowrap">
|
||||
<span className={`fi fi-${attributes.flagIcon}`} style={{ borderRadius: 4 }}></span>
|
||||
<Group wrap="nowrap" gap="xs">
|
||||
<Text>{attributes.name}</Text>
|
||||
<Text size="xs" c="dimmed" inherit>
|
||||
({attributes.translatedName})
|
||||
</Text>
|
||||
</Group>
|
||||
</Group>
|
||||
{localeKey === currentLocale && <IconCheck color="currentColor" size={24} />}
|
||||
</Group>
|
||||
);
|
||||
},
|
||||
useInteraction() {
|
||||
const changeLocale = useChangeLocale();
|
||||
|
||||
return { type: "javaScript", onSelect: () => changeLocale(localeKey) };
|
||||
},
|
||||
}));
|
||||
},
|
||||
detailComponent: () => {
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<Stack mx="md" my="sm">
|
||||
<Text>{t("search.mode.command.group.globalCommand.option.language.children.detail.title")}</Text>
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Group, Stack, Text } from "@mantine/core";
|
||||
|
||||
import { objectEntries } from "@homarr/common";
|
||||
import { integrationDefs } from "@homarr/definitions";
|
||||
import { useI18n } from "@homarr/translation/client";
|
||||
import { IntegrationAvatar } from "@homarr/ui";
|
||||
|
||||
import { createChildrenOptions } from "../../../lib/children";
|
||||
import { interaction } from "../../../lib/interaction";
|
||||
|
||||
export const newIntegrationChildrenOptions = createChildrenOptions<Record<string, unknown>>({
|
||||
useActions: (_, query) => {
|
||||
const normalizedQuery = query.trim().toLowerCase();
|
||||
return objectEntries(integrationDefs)
|
||||
.filter(([, integrationDef]) => integrationDef.name.toLowerCase().includes(normalizedQuery))
|
||||
.sort(
|
||||
([, definitionA], [, definitionB]) =>
|
||||
definitionA.name.toLowerCase().indexOf(normalizedQuery) -
|
||||
definitionB.name.toLowerCase().indexOf(normalizedQuery),
|
||||
)
|
||||
.map(([kind, integrationDef]) => ({
|
||||
key: kind,
|
||||
component() {
|
||||
return (
|
||||
<Group mx="md" my="sm" wrap="nowrap" w="100%">
|
||||
<IntegrationAvatar kind={kind} size="sm" />
|
||||
<Text>{integrationDef.name}</Text>
|
||||
</Group>
|
||||
);
|
||||
},
|
||||
useInteraction: interaction.link(() => ({ href: `/manage/integrations/new?kind=${kind}` })),
|
||||
}));
|
||||
},
|
||||
detailComponent() {
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<Stack mx="md" my="sm">
|
||||
<Text>{t("search.mode.command.group.globalCommand.option.newIntegration.children.detail.title")}</Text>
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user