style: add an icon for each category in the dropdown select

This commit is contained in:
Nicolas Meienberger 2023-04-13 22:36:31 +02:00 committed by Nicolas Meienberger
parent db60483b1c
commit 41863f364a
4 changed files with 80 additions and 20 deletions

View file

@ -1,24 +1,43 @@
import {
Icon,
IconBook,
IconBrain,
IconBroadcast,
IconCamera,
IconCode,
IconDatabase,
IconDeviceGamepad2,
IconMovie,
IconMusic,
IconPigMoney,
IconRobot,
IconShieldLock,
IconStar,
IconTool,
IconUsers,
} from '@tabler/icons-react';
import { AppCategory } from './types';
type AppCategoryEntry = {
name: string;
id: AppCategory;
icon: string;
icon: Icon;
};
export const APP_CATEGORIES: AppCategoryEntry[] = [
{ name: 'Network', id: 'network', icon: 'FaNetworkWired' },
{ name: 'Media', id: 'media', icon: 'FaVideo' },
{ name: 'Development', id: 'development', icon: 'FaCode' },
{ name: 'Automation', id: 'automation', icon: 'FaRobot' },
{ name: 'Social', id: 'social', icon: 'FaUserFriends' },
{ name: 'Utilities', id: 'utilities', icon: 'FaWrench' },
{ name: 'Photography', id: 'photography', icon: 'FaCamera' },
{ name: 'Security', id: 'security', icon: 'FaShieldAlt' },
{ name: 'Featured', id: 'featured', icon: 'FaStar' },
{ name: 'Books', id: 'books', icon: 'FaBook' },
{ name: 'Data', id: 'data', icon: 'FaDatabase' },
{ name: 'Music', id: 'music', icon: 'FaMusic' },
{ name: 'Finance', id: 'finance', icon: 'FaMoneyBillAlt' },
{ name: 'Gaming', id: 'gaming', icon: 'FaGamepad' },
{ name: 'Network', id: 'network', icon: IconBroadcast },
{ name: 'Media', id: 'media', icon: IconMovie },
{ name: 'Development', id: 'development', icon: IconCode },
{ name: 'Automation', id: 'automation', icon: IconRobot },
{ name: 'Social', id: 'social', icon: IconUsers },
{ name: 'Utilities', id: 'utilities', icon: IconTool },
{ name: 'Photography', id: 'photography', icon: IconCamera },
{ name: 'Security', id: 'security', icon: IconShieldLock },
{ name: 'Featured', id: 'featured', icon: IconStar },
{ name: 'Books', id: 'books', icon: IconBook },
{ name: 'Data', id: 'data', icon: IconDatabase },
{ name: 'Music', id: 'music', icon: IconMusic },
{ name: 'Finance', id: 'finance', icon: IconPigMoney },
{ name: 'Gaming', id: 'gaming', icon: IconDeviceGamepad2 },
{ name: 'AI', id: 'ai', icon: IconBrain },
];

View file

@ -1,22 +1,57 @@
import React from 'react';
import Select, { SingleValue } from 'react-select';
import Select, { SingleValue, OptionProps, ControlProps, components } from 'react-select';
import { Icon } from '@tabler/icons-react';
import { APP_CATEGORIES } from '../../../../core/constants';
import { AppCategory } from '../../../../core/types';
import { useUIStore } from '../../../../state/uiStore';
const { Option, Control } = components;
interface IProps {
onSelect: (value?: AppCategory) => void;
className?: string;
initialValue?: AppCategory;
}
type OptionsType = { value: AppCategory; label: string };
type OptionsType = { value: AppCategory; label: string; icon: Icon };
const IconOption = (props: OptionProps<OptionsType>) => {
const { data } = props;
const { icon: CategoryIcon, label } = data;
return (
<Option {...props}>
<>
<CategoryIcon size={20} />
<span style={{ marginLeft: 10 }}>{label}</span>
</>
</Option>
);
};
const ControlComponent = (props: ControlProps<OptionsType>) => {
const { children, ...rest } = props;
const { getValue } = props;
const value = getValue()[0];
if (value?.icon) {
return (
<Control {...rest}>
<value.icon className="ms-2" size={20} />
{children}
</Control>
);
}
return <Control {...rest}> {children}</Control>;
};
const CategorySelector: React.FC<IProps> = ({ onSelect, className, initialValue }) => {
const { darkMode } = useUIStore();
const options: OptionsType[] = APP_CATEGORIES.map((category) => ({
value: category.id,
label: category.name,
icon: category.icon,
}));
const [value, setValue] = React.useState<OptionsType | null>(options.find((o) => o.value === initialValue) || null);
@ -63,6 +98,10 @@ const CategorySelector: React.FC<IProps> = ({ onSelect, className, initialValue
fontSize: '0.8rem',
}),
}}
components={{
Option: IconOption,
Control: ControlComponent,
}}
onChange={handleChange}
defaultValue={[]}
name="categories"

View file

@ -45,4 +45,5 @@ export const colorSchemeForCategory: Record<AppCategory, string> = {
music: 'cyan',
finance: 'dark',
gaming: 'pink',
ai: 'gray',
};

View file

@ -9,7 +9,7 @@ export const APP_STATUS = {
UPDATING: 'updating',
} as const;
export type AppStatus = typeof APP_STATUS[keyof typeof APP_STATUS];
export type AppStatus = (typeof APP_STATUS)[keyof typeof APP_STATUS];
export const APP_CATEGORIES = {
NETWORK: 'network',
@ -26,9 +26,10 @@ export const APP_CATEGORIES = {
MUSIC: 'music',
FINANCE: 'finance',
GAMING: 'gaming',
AI: 'ai',
} as const;
export type AppCategory = typeof APP_CATEGORIES[keyof typeof APP_CATEGORIES];
export type AppCategory = (typeof APP_CATEGORIES)[keyof typeof APP_CATEGORIES];
export const FIELD_TYPES = {
TEXT: 'text',
@ -42,4 +43,4 @@ export const FIELD_TYPES = {
RANDOM: 'random',
} as const;
export type FieldType = typeof FIELD_TYPES[keyof typeof FIELD_TYPES];
export type FieldType = (typeof FIELD_TYPES)[keyof typeof FIELD_TYPES];