import clsx from 'clsx'; import { motion } from 'motion/react'; import { type ComponentType, forwardRef } from 'react'; import { IconBaseProps } from 'react-icons'; import { FaLastfmSquare } from 'react-icons/fa'; import { LuAlignCenter, LuAlignLeft, LuAlignRight, LuAppWindow, LuArrowDown, LuArrowDownToLine, LuArrowDownWideNarrow, LuArrowLeft, LuArrowLeftRight, LuArrowLeftToLine, LuArrowRight, LuArrowRightToLine, LuArrowUp, LuArrowUpDown, LuArrowUpNarrowWide, LuArrowUpToLine, LuBookOpen, LuCheck, LuChevronDown, LuChevronLast, LuChevronLeft, LuChevronRight, LuChevronUp, LuCircleCheck, LuCircleX, LuClipboardCopy, LuClock3, LuCloudDownload, LuCornerUpRight, LuDelete, LuDisc, LuDisc3, LuDownload, LuEllipsis, LuEllipsisVertical, LuExternalLink, LuFileJson, LuFlag, LuFolderOpen, LuGauge, LuGithub, LuGripHorizontal, LuGripVertical, LuHardDrive, LuHash, LuHeart, LuHeartCrack, LuImage, LuInfinity, LuInfo, LuKeyboard, LuLayoutGrid, LuLibrary, LuList, LuListFilter, LuListMinus, LuListMusic, LuListPlus, LuLoader, LuLock, LuLockOpen, LuLogIn, LuLogOut, LuMenu, LuMicVocal, LuMinus, LuMoon, LuMusic, LuMusic2, LuPanelRightClose, LuPanelRightOpen, LuPause, LuPencilLine, LuPlay, LuPlus, LuRadio, LuRotateCw, LuSave, LuSearch, LuSettings, LuSettings2, LuShare2, LuShieldAlert, LuShuffle, LuSkipBack, LuSkipForward, LuSlidersHorizontal, LuSquare, LuSquareCheck, LuSquareMenu, LuStar, LuStepBack, LuStepForward, LuSun, LuTable, LuTriangleAlert, LuUser, LuUserPen, LuUserRoundCog, LuVolume1, LuVolume2, LuVolumeX, LuX, } from 'react-icons/lu'; import { MdOutlineVisibility, MdOutlineVisibilityOff } from 'react-icons/md'; import { RiPlayListAddLine, RiRepeat2Line, RiRepeatOneLine } from 'react-icons/ri'; import { SiMusicbrainz } from 'react-icons/si'; import styles from './icon.module.css'; export type AppIconSelection = keyof typeof AppIcon; export const AppIcon = { add: LuPlus, album: LuDisc3, alignCenter: LuAlignCenter, alignLeft: LuAlignLeft, alignRight: LuAlignRight, appWindow: LuAppWindow, arrowDown: LuArrowDown, arrowDownS: LuChevronDown, arrowDownToLine: LuArrowDownToLine, arrowLeft: LuArrowLeft, arrowLeftRight: LuArrowLeftRight, arrowLeftS: LuChevronLeft, arrowLeftToLine: LuArrowLeftToLine, arrowRight: LuArrowRight, arrowRightLast: LuChevronLast, arrowRightS: LuChevronRight, arrowRightToLine: LuArrowRightToLine, arrowUp: LuArrowUp, arrowUpS: LuChevronUp, arrowUpToLine: LuArrowUpToLine, artist: LuUserPen, brandGitHub: LuGithub, brandLastfm: FaLastfmSquare, brandMusicBrainz: SiMusicbrainz, cache: LuCloudDownload, check: LuCheck, clipboardCopy: LuClipboardCopy, delete: LuDelete, disc: LuDisc, download: LuDownload, dragHorizontal: LuGripHorizontal, dragVertical: LuGripVertical, dropdown: LuChevronDown, duration: LuClock3, edit: LuPencilLine, ellipsisHorizontal: LuEllipsis, ellipsisVertical: LuEllipsisVertical, emptyImage: LuDisc3, error: LuShieldAlert, externalLink: LuExternalLink, favorite: LuHeart, fileJson: LuFileJson, filter: LuListFilter, folder: LuFolderOpen, genre: LuFlag, hash: LuHash, home: LuSquareMenu, image: LuImage, info: LuInfo, itemAlbum: LuDisc3, itemSong: LuMusic, keyboard: LuKeyboard, layoutGrid: LuLayoutGrid, layoutList: LuList, layoutTable: LuTable, library: LuLibrary, list: LuList, listInfinite: LuInfinity, listPaginated: LuArrowRightToLine, lock: LuLock, lockOpen: LuLockOpen, mediaNext: LuSkipForward, mediaPause: LuPause, mediaPlay: LuPlay, mediaPlayLast: LuChevronLast, mediaPlayNext: LuCornerUpRight, mediaPrevious: LuSkipBack, mediaRandom: RiPlayListAddLine, mediaRepeat: RiRepeat2Line, mediaRepeatOne: RiRepeatOneLine, mediaSettings: LuSlidersHorizontal, mediaShuffle: LuShuffle, mediaSpeed: LuGauge, mediaStepBackward: LuStepBack, mediaStepForward: LuStepForward, mediaStop: LuSquare, menu: LuMenu, metadata: LuBookOpen, microphone: LuMicVocal, minus: LuMinus, panelRightClose: LuPanelRightClose, panelRightOpen: LuPanelRightOpen, playlist: LuListMusic, playlistAdd: LuListPlus, playlistDelete: LuListMinus, plus: LuPlus, queue: LuList, radio: LuRadio, refresh: LuRotateCw, remove: LuMinus, save: LuSave, search: LuSearch, server: LuHardDrive, settings: LuSettings2, settings2: LuSettings, share: LuShare2, signIn: LuLogIn, signOut: LuLogOut, sort: LuArrowUpDown, sortAsc: LuArrowUpNarrowWide, sortDesc: LuArrowDownWideNarrow, spinner: LuLoader, square: LuSquare, squareCheck: LuSquareCheck, star: LuStar, success: LuCircleCheck, themeDark: LuMoon, themeLight: LuSun, track: LuMusic2, unfavorite: LuHeartCrack, user: LuUser, userManage: LuUserRoundCog, visibility: MdOutlineVisibility, visibilityOff: MdOutlineVisibilityOff, volumeMax: LuVolume2, volumeMute: LuVolumeX, volumeNormal: LuVolume1, warn: LuTriangleAlert, x: LuX, xCircle: LuCircleX, } as const; export interface IconProps extends Omit { animate?: 'pulse' | 'spin'; color?: IconColor; fill?: IconColor; icon: keyof typeof AppIcon; size?: '2xl' | '3xl' | '4xl' | '5xl' | 'lg' | 'md' | 'sm' | 'xl' | 'xs' | number | string; } type IconColor = | 'contrast' | 'default' | 'error' | 'favorite' | 'info' | 'inherit' | 'muted' | 'primary' | 'success' | 'warn'; export const Icon = forwardRef((props, ref) => { const { animate, className, color, fill, icon, size = 'md' } = props; const IconComponent: ComponentType = AppIcon[icon]; const classNames = clsx(className, { [styles.fill]: true, [styles.pulse]: animate === 'pulse', [styles.spin]: animate === 'spin', [styles[`color-${color || fill}`]]: color || fill, [styles[`fill-${fill}`]]: fill, [styles[`size-${size}`]]: true, }); return ( ); }); Icon.displayName = 'Icon'; export const MotionIcon: ComponentType = motion.create(Icon); function isPredefinedSize(size: IconProps['size']) { return ( size === '2xl' || size === '3xl' || size === '4xl' || size === '5xl' || size === 'lg' || size === 'md' || size === 'sm' || size === 'xl' || size === 'xs' ); }