From dfb3da4e10edc33783ce180e48de4ba5ed912fd1 Mon Sep 17 00:00:00 2001 From: mbrucedogs Date: Sun, 20 Jul 2025 18:26:51 -0500 Subject: [PATCH] Signed-off-by: mbrucedogs --- .firebase/hosting.ZGlzdA.cache | 20 +++---- src/components/Layout/Layout.tsx | 15 ++--- src/components/common/ActionButton.tsx | 40 +++++++++---- src/components/common/PlayerControls.tsx | 34 ++++++----- src/components/common/SelectSinger.tsx | 18 +++--- src/components/common/SongInfo.tsx | 25 +++++--- src/components/common/SongItem.tsx | 55 ++++++++--------- src/constants/index.ts | 76 +++++++++++++++++++++++- src/features/Queue/Queue.tsx | 41 +++++++------ src/features/Settings/Settings.tsx | 14 +++-- src/features/Singers/Singers.tsx | 43 ++++++++------ src/features/TopPlayed/Top100.tsx | 18 ++++-- src/types/index.ts | 42 ++++++++++++- 13 files changed, 302 insertions(+), 139 deletions(-) diff --git a/.firebase/hosting.ZGlzdA.cache b/.firebase/hosting.ZGlzdA.cache index 1fb2ce7..773e32e 100644 --- a/.firebase/hosting.ZGlzdA.cache +++ b/.firebase/hosting.ZGlzdA.cache @@ -1,11 +1,11 @@ vite.svg,499162500000,699a02e0e68a579f687d364bbbe7633161244f35af068220aee37b1b33dfb3c7 -index.html,1753036974325,d4ec7269769afa4794c9b3bc4382b8bb4ca2a9cc11d47522053a62b9c1dbd99b -assets/swipe-back-0ASdaLec.js,1753036974325,dfdb4ccfc65b5ddd1d04306a2cbc650f7f2be8d659bb029d32c75fd5041b6f5e -assets/status-tap-DKvxsyfd.js,1753036974325,1bbe8dd5487685ce491d40b73bc1bbbc1a3fdeac4e485438c55484248ca69fff -assets/md.transition-CWuowIQj.js,1753036974325,b5d793bffc7672549acba90697be0b704a7b39d8f4ff21faaf05ddba2951dcb0 -assets/ios.transition-BPJsV1yP.js,1753036974325,e401e6df1d7c900f8f54e717308a57abfcf913ee17b2eb56846b4ba3049d94cf -assets/input-shims-BtXJpb0t.js,1753036974325,1f111da7ba4ae84995311f07a6d41c62ca179213cd8123623048af9ccee533f9 -assets/index7-_QrtZLKR.js,1753036974325,fac87389bb8d2e7850fef07b4fd01132a49206e2b5ddd40feff932d041e1874e -assets/focus-visible-supuXXMI.js,1753036974325,df9266429356671847fa2c8123e1564bae645f75df3094f0055c365fa2beae28 -assets/index-CzY-nILz.css,1753036974324,c68362f490f176fbe950e6cc313da199ed6e08c67058d82b833a2026a0be75c9 -assets/index-DxnqBJhb.js,1753036974326,143303c7b9c04d8a450f75b956258ba32195e518861db9a8c07e4cbbab3d6c0d +index.html,1753039071822,289c705921beda96f6c4b135228e50d878a006af729bda9ea798c308ba8e28d2 +assets/status-tap-CEY3QyNR.js,1753039071809,6c19db5130690d358a896ae78fec5e08f22b1cfd20385bb51eb8b346ee1b9e04 +assets/swipe-back-d2lW66aK.js,1753039071809,e420e33827964afc4fbe53b029bbfa7f23b0c1260900677c7ca4eab979e16c02 +assets/md.transition-MdrV1caB.js,1753039071823,59c5b55c8425c0d65b4a6116578e6b7dd98e70bffbbc3781413f312f17635c60 +assets/index7-C6G0api_.js,1753039071809,57b89d09c14fbac6c16a22825f7bdb81c92de6f5df1bae8fe148908f5d2812ef +assets/ios.transition-DXsH9Qpm.js,1753039071823,758b15c7838ba462b05f15fb7b4ac68e1dd489bda3d25a5e2a12bf1c3a1f5b97 +assets/focus-visible-supuXXMI.js,1753039071811,df9266429356671847fa2c8123e1564bae645f75df3094f0055c365fa2beae28 +assets/input-shims-DA6_iXWm.js,1753039071811,3394836233f6eb8c423038c9a190ae5e1b0ef552dc27e0c73287275573e79088 +assets/index-CzY-nILz.css,1753039071808,c68362f490f176fbe950e6cc313da199ed6e08c67058d82b833a2026a0be75c9 +assets/index-BlzLgABC.js,1753039071823,cd8075e0b94a4d73bcdfc453f3276398223974fa2cb193599229a82aa2ccba6c diff --git a/src/components/Layout/Layout.tsx b/src/components/Layout/Layout.tsx index 71a1091..b1040f0 100644 --- a/src/components/Layout/Layout.tsx +++ b/src/components/Layout/Layout.tsx @@ -1,10 +1,11 @@ import React, { useState, useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { useLocation } from 'react-router-dom'; -import { IonApp, IonHeader, IonToolbar, IonTitle, IonContent, IonMenuButton, IonIcon } from '@ionic/react'; -import { logOut } from 'ionicons/icons'; +import { IonApp, IonHeader, IonToolbar, IonTitle, IonContent, IonMenuButton } from '@ionic/react'; import { logout } from '../../redux/authSlice'; import { ActionButton } from '../common'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import Navigation from '../Navigation/Navigation'; import { getPageTitle } from '../../utils/routeUtils'; import type { LayoutProps } from '../../types'; @@ -65,11 +66,11 @@ const Layout: React.FC = ({ children }) => {
- - + variant={ActionButtonVariant.SECONDARY} + size={ActionButtonSize.SMALL} + icon={Icons.LOGOUT} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + />
diff --git a/src/components/common/ActionButton.tsx b/src/components/common/ActionButton.tsx index 76dd45f..837762a 100644 --- a/src/components/common/ActionButton.tsx +++ b/src/components/common/ActionButton.tsx @@ -1,22 +1,27 @@ import React from 'react'; -import { IonButton } from '@ionic/react'; +import { IonButton, IonIcon } from '@ionic/react'; import type { ActionButtonProps } from '../../types'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot, ActionButtonIconSize } from '../../types'; const ActionButton: React.FC = ({ onClick, children, - variant = 'primary', - size = 'md', + variant = ActionButtonVariant.PRIMARY, + size = ActionButtonSize.MEDIUM, disabled = false, - className = '' + className = '', + icon, + iconSlot = ActionButtonIconSlot.START, + iconSize = ActionButtonIconSize.LARGE, + fill = 'solid' }) => { const getVariant = () => { switch (variant) { - case 'primary': + case ActionButtonVariant.PRIMARY: return 'primary'; - case 'secondary': + case ActionButtonVariant.SECONDARY: return 'medium'; - case 'danger': + case ActionButtonVariant.DANGER: return 'danger'; default: return 'primary'; @@ -25,11 +30,11 @@ const ActionButton: React.FC = ({ const getSize = () => { switch (size) { - case 'sm': + case ActionButtonSize.SMALL: return 'small'; - case 'md': + case ActionButtonSize.MEDIUM: return 'default'; - case 'lg': + case ActionButtonSize.LARGE: return 'large'; default: return 'default'; @@ -40,11 +45,24 @@ const ActionButton: React.FC = ({ + {icon && } {children} ); diff --git a/src/components/common/PlayerControls.tsx b/src/components/common/PlayerControls.tsx index 90a4f55..7c46215 100644 --- a/src/components/common/PlayerControls.tsx +++ b/src/components/common/PlayerControls.tsx @@ -1,7 +1,9 @@ import React from 'react'; import { IonCard, IonCardContent, IonChip, IonIcon } from '@ionic/react'; -import { play, pause, stop, pauseOutline, playOutline, stopOutline } from 'ionicons/icons'; +import { pauseOutline, playOutline, stopOutline } from 'ionicons/icons'; import ActionButton from './ActionButton'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import { useAppSelector } from '../../redux'; import { selectPlayerState, selectIsAdmin, selectQueueLength, selectControllerName } from '../../redux'; import { playerService } from '../../firebase/services'; @@ -190,30 +192,30 @@ const PlayerControls: React.FC = ({ className = '', variant {currentState === PlayerState.playing ? ( - - + variant={ActionButtonVariant.PRIMARY} + size={ActionButtonSize.SMALL} + icon={Icons.PAUSE} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> ) : ( - - + /> )} {currentState !== PlayerState.stopped && ( - - + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.STOP} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> )} diff --git a/src/components/common/SelectSinger.tsx b/src/components/common/SelectSinger.tsx index 53bbd7e..1ffe674 100644 --- a/src/components/common/SelectSinger.tsx +++ b/src/components/common/SelectSinger.tsx @@ -7,15 +7,15 @@ import { IonContent, IonList, IonItem, - IonLabel, - IonButton, - IonIcon + IonLabel } from '@ionic/react'; -import { close } from 'ionicons/icons'; import { useAppSelector } from '../../redux'; import { selectSingersArray, selectControllerName, selectQueueObject } from '../../redux'; import { queueService } from '../../firebase/services'; import { useToast } from '../../hooks/useToast'; +import { ActionButton } from './index'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import type { Song, Singer, QueueItem } from '../../types'; interface SelectSingerProps { @@ -76,9 +76,13 @@ const SelectSinger: React.FC = ({ isOpen, onClose, song }) => Select Singer - - - + diff --git a/src/components/common/SongInfo.tsx b/src/components/common/SongInfo.tsx index 9a5a116..171c009 100644 --- a/src/components/common/SongInfo.tsx +++ b/src/components/common/SongInfo.tsx @@ -4,7 +4,7 @@ import { IonButton, IonIcon, IonList, IonItem, IonLabel } from '@ionic/react'; import { - add, heart, heartOutline, ban, checkmark, close, people + add, heart, heartOutline, ban, checkmark, people } from 'ionicons/icons'; import { useAppSelector } from '../../redux'; import { selectIsAdmin, selectFavorites, selectSongs, selectQueue } from '../../redux'; @@ -13,6 +13,9 @@ import { useDisabledSongs } from '../../hooks/useDisabledSongs'; import { useSelectSinger } from '../../hooks/useSelectSinger'; import { useToast } from '../../hooks/useToast'; import SelectSinger from './SelectSinger'; +import { ActionButton } from './index'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import { SongInfoDisplay } from './SongItem'; import type { Song, QueueItem } from '../../types'; @@ -90,9 +93,13 @@ const SongInfo: React.FC = ({ isOpen, onClose, song }) => { Song Info - - - + @@ -186,9 +193,13 @@ const SongInfo: React.FC = ({ isOpen, onClose, song }) => { Songs by {song.artist} - setShowArtistSongs(false)}> - - + setShowArtistSongs(false)} + variant={ActionButtonVariant.SECONDARY} + size={ActionButtonSize.SMALL} + icon={Icons.CLOSE} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> diff --git a/src/components/common/SongItem.tsx b/src/components/common/SongItem.tsx index 0db5749..9ad7494 100644 --- a/src/components/common/SongItem.tsx +++ b/src/components/common/SongItem.tsx @@ -1,11 +1,12 @@ import React from 'react'; -import { IonItem, IonLabel, IonIcon } from '@ionic/react'; -import { add, heart, heartOutline, trash, informationCircle } from 'ionicons/icons'; +import { IonItem, IonLabel } from '@ionic/react'; import ActionButton from './ActionButton'; import { useAppSelector } from '../../redux'; import { selectQueue, selectFavorites } from '../../redux'; import { debugLog } from '../../utils/logger'; import type { SongItemProps, QueueItem, Song } from '../../types'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; // Utility function to extract filename from path const extractFilename = (path: string): string => { @@ -119,11 +120,11 @@ export const SongActionButtons: React.FC<{ - - + variant={ActionButtonVariant.SECONDARY} + size={ActionButtonSize.SMALL} + icon={Icons.INFORMATION_CIRCLE} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> ); } @@ -133,11 +134,11 @@ export const SongActionButtons: React.FC<{ {})} - variant="primary" - size="sm" - > - - + variant={ActionButtonVariant.PRIMARY} + size={ActionButtonSize.SMALL} + icon={Icons.ADD} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> ); } @@ -147,11 +148,11 @@ export const SongActionButtons: React.FC<{ - - + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.TRASH} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> ); } @@ -161,11 +162,11 @@ export const SongActionButtons: React.FC<{ - - + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.TRASH} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> ); } @@ -175,11 +176,11 @@ export const SongActionButtons: React.FC<{ {})} - variant={isInFavorites ? 'danger' : 'secondary'} - size="sm" - > - - + variant={isInFavorites ? ActionButtonVariant.DANGER : ActionButtonVariant.SECONDARY} + size={ActionButtonSize.SMALL} + icon={isInFavorites ? Icons.HEART : Icons.HEART_OUTLINE} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + /> ); } diff --git a/src/constants/index.ts b/src/constants/index.ts index 3f011e3..f0e42f9 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -80,4 +80,78 @@ export const FEATURES = { ENABLE_HISTORY: true, ENABLE_TOP_PLAYED: true, ENABLE_ADMIN_CONTROLS: true, -} as const; \ No newline at end of file +} as const; + +import { + add, + trash, + close, + ban, + checkmark, + searchOutline, + musicalNotesOutline, + peopleCircleOutline, + peopleOutline, + starOutline, + heart, + heartOutline, + timeOutline, + listOutline, + settingsOutline, + play, + playOutline, + pause, + pauseOutline, + stop, + stopOutline, + reorderThreeOutline, + reorderTwoOutline, + informationCircle, + logOut, + micOutline, + time, + list +} from 'ionicons/icons'; + +// Icon constants for better type safety and autocomplete +export const Icons = { + // Action icons + ADD: add, + TRASH: trash, + CLOSE: close, + BAN: ban, + CHECKMARK: checkmark, + + // Navigation icons + SEARCH: searchOutline, + MUSIC_NOTES: musicalNotesOutline, + PEOPLE: peopleCircleOutline, + PEOPLE_OUTLINE: peopleOutline, + STAR: starOutline, + HEART: heart, + HEART_OUTLINE: heartOutline, + TIME: timeOutline, + LIST: listOutline, + SETTINGS: settingsOutline, + + // Player controls + PLAY: play, + PLAY_OUTLINE: playOutline, + PAUSE: pause, + PAUSE_OUTLINE: pauseOutline, + STOP: stop, + STOP_OUTLINE: stopOutline, + + // UI icons + REORDER_THREE: reorderThreeOutline, + REORDER_TWO: reorderTwoOutline, + INFORMATION_CIRCLE: informationCircle, + LOGOUT: logOut, + MIC: micOutline, + + // Status icons + TIME_SIMPLE: time, + LIST_SIMPLE: list +} as const; + +export type IconType = typeof Icons[keyof typeof Icons]; \ No newline at end of file diff --git a/src/features/Queue/Queue.tsx b/src/features/Queue/Queue.tsx index 7072b89..186c0cc 100644 --- a/src/features/Queue/Queue.tsx +++ b/src/features/Queue/Queue.tsx @@ -1,10 +1,12 @@ import React, { useState, useEffect } from 'react'; -import { IonItem, IonLabel, IonItemSliding, IonItemOptions, IonItemOption, IonButton, IonIcon, IonReorderGroup, IonReorder } from '@ionic/react'; -import { trash, reorderThreeOutline, reorderTwoOutline, list } from 'ionicons/icons'; +import { IonItem, IonLabel, IonItemSliding, IonItemOptions, IonItemOption, IonIcon, IonReorderGroup, IonReorder } from '@ionic/react'; +import { reorderThreeOutline, reorderTwoOutline, list } from 'ionicons/icons'; import { useQueue } from '../../hooks'; import { useAppSelector } from '../../redux'; import { selectQueueLength, selectPlayerStateMemoized, selectIsAdmin, selectControllerName } from '../../redux'; import { ActionButton, NumberDisplay, EmptyState } from '../../components/common'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import { SongInfoDisplay } from '../../components/common/SongItem'; import { queueService } from '../../firebase/services'; import { debugLog } from '../../utils/logger'; @@ -130,11 +132,11 @@ const Queue: React.FC = () => {
e.stopPropagation()}> handleRemoveFromQueue(queueItem)} - variant="danger" - size="sm" - > - - + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.TRASH} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + />
)} {canReorder && queueMode === 'reorder' && ( @@ -152,7 +154,7 @@ const Queue: React.FC = () => { color="danger" onClick={() => handleRemoveFromQueue(queueItem)} > - + )} @@ -194,11 +196,11 @@ const Queue: React.FC = () => {
e.stopPropagation()}> handleRemoveFromQueue(firstItem)} - variant="danger" - size="sm" - > - - + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.TRASH} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + />
)} @@ -211,7 +213,7 @@ const Queue: React.FC = () => { color="danger" onClick={() => handleRemoveFromQueue(firstItem)} > - + )} @@ -234,13 +236,14 @@ const Queue: React.FC = () => { <>
{isAdmin && ( - - - + /> )}
diff --git a/src/features/Settings/Settings.tsx b/src/features/Settings/Settings.tsx index 8fb8a94..9bf3a11 100644 --- a/src/features/Settings/Settings.tsx +++ b/src/features/Settings/Settings.tsx @@ -1,10 +1,12 @@ import React, { useState } from 'react'; import { IonContent, IonHeader, IonTitle, IonToolbar, IonList, IonItem, IonLabel, IonToggle, IonButton, IonIcon, IonModal, IonSearchbar } from '@ionic/react'; -import { ban, trash } from 'ionicons/icons'; +import { ban } from 'ionicons/icons'; import { useAppSelector } from '../../redux'; import { selectIsAdmin, selectSettings } from '../../redux'; import { useDisabledSongs } from '../../hooks'; import { InfiniteScrollList, ActionButton } from '../../components/common'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import { filterSongs } from '../../utils/dataProcessing'; import { setDebugEnabled, isDebugEnabled, debugLog } from '../../utils/logger'; import type { Song, DisabledSong } from '../../types'; @@ -181,11 +183,11 @@ const Settings: React.FC = () => {
e.stopPropagation()}> handleRemoveDisabledSong(song)} - variant="danger" - size="sm" - > - - + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.TRASH} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + />
diff --git a/src/features/Singers/Singers.tsx b/src/features/Singers/Singers.tsx index 428c55f..baebff4 100644 --- a/src/features/Singers/Singers.tsx +++ b/src/features/Singers/Singers.tsx @@ -1,12 +1,13 @@ import React, { useState } from 'react'; -import { IonItem, IonLabel, IonIcon, IonModal, IonHeader, IonToolbar, IonTitle, IonButton, IonContent, IonInput, IonLabel as IonInputLabel } from '@ionic/react'; -import { trash, add, close } from 'ionicons/icons'; +import { IonItem, IonLabel, IonModal, IonHeader, IonToolbar, IonTitle, IonButton, IonContent, IonInput, IonLabel as IonInputLabel } from '@ionic/react'; import { InfiniteScrollList, ActionButton, NumberDisplay } from '../../components/common'; import { useSingers } from '../../hooks'; import { useAppSelector } from '../../redux'; import { selectSingers } from '../../redux'; import { debugLog } from '../../utils/logger'; import type { Singer } from '../../types'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; const Singers: React.FC = () => { const { @@ -59,15 +60,13 @@ const Singers: React.FC = () => { {/* Delete Button (Admin Only) */} {isAdmin && (
-
e.stopPropagation()}> - handleRemoveSinger(singer)} - variant="danger" - size="sm" - > - - -
+ handleRemoveSinger(singer)} + variant={ActionButtonVariant.DANGER} + size={ActionButtonSize.SMALL} + icon={Icons.TRASH} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + />
)} @@ -77,12 +76,14 @@ const Singers: React.FC = () => { <>
{isAdmin && ( - - - + variant={ActionButtonVariant.PRIMARY} + size={ActionButtonSize.SMALL} + icon={Icons.ADD} + iconSlot={ActionButtonIconSlot.ICON_ONLY} + fill="clear" + /> )}
@@ -111,9 +112,13 @@ const Singers: React.FC = () => { Add New Singer - - - + diff --git a/src/features/TopPlayed/Top100.tsx b/src/features/TopPlayed/Top100.tsx index 7a30102..978291d 100644 --- a/src/features/TopPlayed/Top100.tsx +++ b/src/features/TopPlayed/Top100.tsx @@ -1,14 +1,16 @@ import React, { useState, useMemo, useCallback } from 'react'; -import { IonChip, IonModal, IonHeader, IonToolbar, IonTitle, IonButton, IonIcon, IonContent, IonList } from '@ionic/react'; -import { close, list } from 'ionicons/icons'; +import { IonChip, IonModal, IonHeader, IonToolbar, IonTitle, IonIcon, IonContent, IonList } from '@ionic/react'; +import { list } from 'ionicons/icons'; import { useTopPlayed } from '../../hooks'; import { useAppSelector } from '../../redux'; import { selectTopPlayed, selectSongsArray } from '../../redux'; -import { InfiniteScrollList, SongItem, ListItem, SongInfo } from '../../components/common'; +import { InfiniteScrollList, SongItem, ListItem, SongInfo, ActionButton } from '../../components/common'; import { filterSongs } from '../../utils/dataProcessing'; import { debugLog } from '../../utils/logger'; import { useSongOperations } from '../../hooks'; import { useToast } from '../../hooks'; +import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types'; +import { Icons } from '../../constants'; import type { TopPlayed, Song } from '../../types'; const Top100: React.FC = () => { @@ -139,9 +141,13 @@ const Top100: React.FC = () => { {selectedTopPlayed?.artist} - - - + diff --git a/src/types/index.ts b/src/types/index.ts index 3fa34b1..c06938d 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -117,13 +117,49 @@ export interface ToastProps { onClose: () => void; } +// ActionButton constants +export const ActionButtonVariant = { + PRIMARY: 'primary', + SECONDARY: 'secondary', + DANGER: 'danger' +} as const; + +export const ActionButtonSize = { + SMALL: 'sm', + MEDIUM: 'md', + LARGE: 'lg' +} as const; + +export const ActionButtonIconSlot = { + START: 'start', + END: 'end', + ICON_ONLY: 'icon-only' +} as const; + +export const ActionButtonIconSize = { + SMALL: 18, + MEDIUM: 20, + LARGE: 22 +} as const; + +export type ActionButtonVariantType = typeof ActionButtonVariant[keyof typeof ActionButtonVariant]; +export type ActionButtonSizeType = typeof ActionButtonSize[keyof typeof ActionButtonSize]; +export type ActionButtonIconSlotType = typeof ActionButtonIconSlot[keyof typeof ActionButtonIconSlot]; +export type ActionButtonIconSizeType = typeof ActionButtonIconSize[keyof typeof ActionButtonIconSize]; + +import type { IconType } from '../constants'; + export interface ActionButtonProps { onClick: () => void; - children: React.ReactNode; - variant?: 'primary' | 'secondary' | 'danger'; - size?: 'sm' | 'md' | 'lg'; + children?: React.ReactNode; + variant?: ActionButtonVariantType; + size?: ActionButtonSizeType; disabled?: boolean; className?: string; + icon?: IconType; + iconSlot?: ActionButtonIconSlotType; + iconSize?: ActionButtonIconSizeType; + fill?: 'solid' | 'outline' | 'clear'; } export interface SongItemProps {