mirror of
https://github.com/ajnart/homarr.git
synced 2025-11-11 07:55:52 +01:00
🔀 Merge pull request #368 from ajnart/ajnart/issue349
✨ Search and open services with the search bar
This commit is contained in:
18
src/components/AppShelf/SmallServiceItem.tsx
Normal file
18
src/components/AppShelf/SmallServiceItem.tsx
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Anchor, Avatar, Group, Text } from '@mantine/core';
|
||||||
|
|
||||||
|
interface smallServiceItem {
|
||||||
|
label: string;
|
||||||
|
icon?: string;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SmallServiceItem(props: any) {
|
||||||
|
const { service }: { service: smallServiceItem } = props;
|
||||||
|
// TODO : Use Next/link
|
||||||
|
return (
|
||||||
|
<Group>
|
||||||
|
{service.icon && <Avatar src={service.icon} />}
|
||||||
|
<Text>{service.label}</Text>
|
||||||
|
</Group>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Kbd, createStyles, Autocomplete, Popover, ScrollArea, Divider } from '@mantine/core';
|
import { Kbd, createStyles, Autocomplete, Popover, ScrollArea, Divider } from '@mantine/core';
|
||||||
import { useClickOutside, useDebouncedValue, useHotkeys } from '@mantine/hooks';
|
import { useClickOutside, useDebouncedValue, useHotkeys } from '@mantine/hooks';
|
||||||
import { useForm } from '@mantine/form';
|
import { useForm } from '@mantine/form';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { forwardRef, useEffect, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
IconSearch as Search,
|
IconSearch as Search,
|
||||||
IconBrandYoutube as BrandYoutube,
|
IconBrandYoutube as BrandYoutube,
|
||||||
@@ -15,6 +15,7 @@ import { useConfig } from '../../tools/state';
|
|||||||
import { IModule } from '../ModuleTypes';
|
import { IModule } from '../ModuleTypes';
|
||||||
import { OverseerrModule } from '../overseerr';
|
import { OverseerrModule } from '../overseerr';
|
||||||
import { OverseerrMediaDisplay } from '../common';
|
import { OverseerrMediaDisplay } from '../common';
|
||||||
|
import SmallServiceItem from '../../components/AppShelf/SmallServiceItem';
|
||||||
|
|
||||||
const useStyles = createStyles((theme) => ({
|
const useStyles = createStyles((theme) => ({
|
||||||
hide: {
|
hide: {
|
||||||
@@ -100,11 +101,36 @@ export default function SearchBar(props: any) {
|
|||||||
if (!isModuleEnabled) {
|
if (!isModuleEnabled) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// Match all the services that contain the query in their name if the query is not empty
|
||||||
const autocompleteData = results.map((result) => ({
|
const matchingServices = config.services.filter((service) => {
|
||||||
|
if (form.values.query === '' || form.values.query === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return service.name.toLowerCase().includes(form.values.query.toLowerCase());
|
||||||
|
});
|
||||||
|
const autocompleteData = matchingServices.map((service) => ({
|
||||||
|
label: service.name,
|
||||||
|
value: service.name,
|
||||||
|
icon: service.icon,
|
||||||
|
url: service.openedUrl ?? service.url,
|
||||||
|
}));
|
||||||
|
// Append the matching results to the autocomplete data
|
||||||
|
const autoCompleteResults = results.map((result) => ({
|
||||||
label: result.phrase,
|
label: result.phrase,
|
||||||
value: result.phrase,
|
value: result.phrase,
|
||||||
|
icon: result.icon,
|
||||||
|
url: result.url,
|
||||||
}));
|
}));
|
||||||
|
autocompleteData.push(...autoCompleteResults);
|
||||||
|
|
||||||
|
const AutoCompleteItem = forwardRef<HTMLDivElement, any>(
|
||||||
|
({ label, value, icon, url, ...others }: any, ref) => (
|
||||||
|
<div ref={ref} {...others}>
|
||||||
|
<SmallServiceItem service={{ label, value, icon, url }} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
@@ -163,6 +189,15 @@ export default function SearchBar(props: any) {
|
|||||||
onFocusCapture={() => setOpened(true)}
|
onFocusCapture={() => setOpened(true)}
|
||||||
autoFocus
|
autoFocus
|
||||||
variant="filled"
|
variant="filled"
|
||||||
|
itemComponent={AutoCompleteItem}
|
||||||
|
onItemSubmit={(item) => {
|
||||||
|
setOpened(false);
|
||||||
|
if (item.url) {
|
||||||
|
results.splice(0, autocompleteData.length);
|
||||||
|
form.reset();
|
||||||
|
window.open(item.url);
|
||||||
|
}
|
||||||
|
}}
|
||||||
data={autocompleteData}
|
data={autocompleteData}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
ref={textInput}
|
ref={textInput}
|
||||||
|
|||||||
Reference in New Issue
Block a user