Signed-off-by: mbrucedogs <mbrucedogs@gmail.com>

This commit is contained in:
mbrucedogs 2025-07-20 18:31:36 -05:00
parent dfb3da4e10
commit b696dbdabd
7 changed files with 93 additions and 61 deletions

View File

@ -41,6 +41,8 @@ const ActionButton: React.FC<ActionButtonProps> = ({
} }
}; };
const isIconOnly = icon && iconSlot === ActionButtonIconSlot.ICON_ONLY && !children;
return ( return (
<IonButton <IonButton
onClick={onClick} onClick={onClick}
@ -50,11 +52,14 @@ const ActionButton: React.FC<ActionButtonProps> = ({
size={getSize()} size={getSize()}
className={className} className={className}
style={{ style={{
minWidth: '40px', minWidth: isIconOnly ? '40px' : '40px',
minHeight: '40px', minHeight: '40px',
width: isIconOnly ? '40px' : 'auto',
height: isIconOnly ? '40px' : 'auto',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center' justifyContent: 'center',
padding: isIconOnly ? '0' : undefined
}} }}
> >
{icon && <IonIcon {icon && <IonIcon

View File

@ -1,7 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { IonSearchbar, IonModal, IonHeader, IonToolbar, IonTitle, IonButton, IonIcon, IonContent, IonItem } from '@ionic/react'; import { IonSearchbar, IonModal, IonHeader, IonToolbar, IonTitle, IonContent, IonItem } from '@ionic/react';
import { close, list } from 'ionicons/icons'; import { list } from 'ionicons/icons';
import { InfiniteScrollList, SongItem, ListItem, NumberDisplay, SongInfo } from '../../components/common'; import { InfiniteScrollList, SongItem, ListItem, NumberDisplay, SongInfo, ActionButton } from '../../components/common';
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
import { Icons } from '../../constants';
import { useArtists } from '../../hooks'; import { useArtists } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectSongs } from '../../redux'; import { selectSongs } from '../../redux';
@ -97,9 +99,16 @@ const Artists: React.FC = () => {
<IonHeader> <IonHeader>
<IonToolbar> <IonToolbar>
<IonTitle>Songs by {selectedArtist}</IonTitle> <IonTitle>Songs by {selectedArtist}</IonTitle>
<IonButton slot="end" fill="clear" onClick={handleCloseArtistSongs}> <div slot="end">
<IonIcon icon={close} /> <ActionButton
</IonButton> onClick={handleCloseArtistSongs}
variant={ActionButtonVariant.SECONDARY}
size={ActionButtonSize.SMALL}
icon={Icons.CLOSE}
iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="clear"
/>
</div>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>

View File

@ -234,20 +234,20 @@ const Queue: React.FC = () => {
return ( return (
<> <>
<div className="ion-padding ion-text-end">
{isAdmin && (
<ActionButton
onClick={toggleQueueMode}
variant={ActionButtonVariant.SECONDARY}
size={ActionButtonSize.SMALL}
icon={queueMode === 'delete' ? reorderThreeOutline : Icons.TRASH}
iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="outline"
/>
)}
</div>
<div className="ion-padding"> <div className="ion-padding">
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '1rem' }}>
{isAdmin && (
<ActionButton
onClick={toggleQueueMode}
variant={ActionButtonVariant.SECONDARY}
size={ActionButtonSize.SMALL}
icon={queueMode === 'delete' ? reorderThreeOutline : Icons.TRASH}
iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="outline"
/>
)}
</div>
{/* First Item (Currently Playing) */} {/* First Item (Currently Playing) */}
{renderFirstItem()} {renderFirstItem()}

View File

@ -134,13 +134,16 @@ const Settings: React.FC = () => {
<IonHeader> <IonHeader>
<IonToolbar> <IonToolbar>
<IonTitle>Disabled Songs ({filteredDisabledSongs.length})</IonTitle> <IonTitle>Disabled Songs ({filteredDisabledSongs.length})</IonTitle>
<IonButton <div slot="end">
slot="end" <ActionButton
fill="clear" onClick={() => setShowDisabledSongsModal(false)}
onClick={() => setShowDisabledSongsModal(false)} variant={ActionButtonVariant.SECONDARY}
> size={ActionButtonSize.SMALL}
Close icon={Icons.CLOSE}
</IonButton> iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="clear"
/>
</div>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>

View File

@ -74,20 +74,20 @@ const Singers: React.FC = () => {
return ( return (
<> <>
<div className="ion-padding ion-text-end">
{isAdmin && (
<ActionButton
onClick={handleOpenAddModal}
variant={ActionButtonVariant.PRIMARY}
size={ActionButtonSize.SMALL}
icon={Icons.ADD}
iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="clear"
/>
)}
</div>
<div className="ion-padding"> <div className="ion-padding">
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: '1rem' }}>
{isAdmin && (
<ActionButton
onClick={handleOpenAddModal}
variant={ActionButtonVariant.PRIMARY}
size={ActionButtonSize.SMALL}
icon={Icons.ADD}
iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="solid"
/>
)}
</div>
<InfiniteScrollList<Singer> <InfiniteScrollList<Singer>
items={singers} items={singers}
isLoading={singersCount === 0} isLoading={singersCount === 0}
@ -112,13 +112,16 @@ const Singers: React.FC = () => {
<IonHeader> <IonHeader>
<IonToolbar> <IonToolbar>
<IonTitle>Add New Singer</IonTitle> <IonTitle>Add New Singer</IonTitle>
<ActionButton <div slot="end">
onClick={handleCloseAddModal} <ActionButton
variant={ActionButtonVariant.SECONDARY} onClick={handleCloseAddModal}
size={ActionButtonSize.SMALL} variant={ActionButtonVariant.SECONDARY}
icon={Icons.CLOSE} size={ActionButtonSize.SMALL}
iconSlot={ActionButtonIconSlot.ICON_ONLY} icon={Icons.CLOSE}
/> iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="clear"
/>
</div>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>

View File

@ -1,7 +1,9 @@
import React, { useState, useMemo, useCallback } from 'react'; import React, { useState, useMemo, useCallback } from 'react';
import { IonItem, IonModal, IonHeader, IonToolbar, IonTitle, IonButton, IonIcon, IonChip, IonContent, IonList, IonAccordionGroup, IonAccordion } from '@ionic/react'; import { IonItem, IonModal, IonHeader, IonToolbar, IonTitle, IonChip, IonContent, IonList, IonAccordionGroup, IonAccordion } from '@ionic/react';
import { close, list } from 'ionicons/icons'; import { list } from 'ionicons/icons';
import { InfiniteScrollList, SongItem, ListItem, TwoLineDisplay, NumberDisplay, SongInfo } from '../../components/common'; import { InfiniteScrollList, SongItem, ListItem, TwoLineDisplay, NumberDisplay, SongInfo, ActionButton } from '../../components/common';
import { ActionButtonVariant, ActionButtonSize, ActionButtonIconSlot } from '../../types';
import { Icons } from '../../constants';
import { useSongLists } from '../../hooks'; import { useSongLists } from '../../hooks';
import { useAppSelector } from '../../redux'; import { useAppSelector } from '../../redux';
import { selectSongList } from '../../redux'; import { selectSongList } from '../../redux';
@ -101,9 +103,16 @@ const SongLists: React.FC = () => {
<IonHeader> <IonHeader>
<IonToolbar> <IonToolbar>
<IonTitle>{finalSelectedList?.title}</IonTitle> <IonTitle>{finalSelectedList?.title}</IonTitle>
<IonButton slot="end" fill="clear" onClick={handleCloseSongList}> <div slot="end">
<IonIcon icon={close} /> <ActionButton
</IonButton> onClick={handleCloseSongList}
variant={ActionButtonVariant.SECONDARY}
size={ActionButtonSize.SMALL}
icon={Icons.CLOSE}
iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="clear"
/>
</div>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>

View File

@ -141,13 +141,16 @@ const Top100: React.FC = () => {
<IonHeader> <IonHeader>
<IonToolbar> <IonToolbar>
<IonTitle>{selectedTopPlayed?.artist}</IonTitle> <IonTitle>{selectedTopPlayed?.artist}</IonTitle>
<ActionButton <div slot="end">
onClick={handleCloseModal} <ActionButton
variant={ActionButtonVariant.SECONDARY} onClick={handleCloseModal}
size={ActionButtonSize.SMALL} variant={ActionButtonVariant.SECONDARY}
icon={Icons.CLOSE} size={ActionButtonSize.SMALL}
iconSlot={ActionButtonIconSlot.ICON_ONLY} icon={Icons.CLOSE}
/> iconSlot={ActionButtonIconSlot.ICON_ONLY}
fill="clear"
/>
</div>
</IonToolbar> </IonToolbar>
</IonHeader> </IonHeader>