mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-09 20:29:36 +02:00
redesign PlayButtonGroup to match card styles
This commit is contained in:
@@ -12,7 +12,7 @@ import { api } from '/@/renderer/api';
|
|||||||
import { queryKeys } from '/@/renderer/api/query-keys';
|
import { queryKeys } from '/@/renderer/api/query-keys';
|
||||||
import { useGenreList } from '/@/renderer/features/genres/api/genres-api';
|
import { useGenreList } from '/@/renderer/features/genres/api/genres-api';
|
||||||
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
import { usePlayer } from '/@/renderer/features/player/context/player-context';
|
||||||
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
import { PlayButtonGroup } from '/@/renderer/features/shared/components/play-button-group';
|
||||||
import { useCurrentServer } from '/@/renderer/store';
|
import { useCurrentServer } from '/@/renderer/store';
|
||||||
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
|
import { Checkbox } from '/@/shared/components/checkbox/checkbox';
|
||||||
import { Divider } from '/@/shared/components/divider/divider';
|
import { Divider } from '/@/shared/components/divider/divider';
|
||||||
@@ -101,16 +101,6 @@ export const ShuffleAllContextModal = () => {
|
|||||||
closeAllModals();
|
closeAllModals();
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoadingNext =
|
|
||||||
isFetching &&
|
|
||||||
(fetchTypeRef.current === Play.NEXT || fetchTypeRef.current === Play.NEXT_SHUFFLE);
|
|
||||||
|
|
||||||
const isLoadingLast =
|
|
||||||
isFetching &&
|
|
||||||
(fetchTypeRef.current === Play.LAST || fetchTypeRef.current === Play.LAST_SHUFFLE);
|
|
||||||
|
|
||||||
const isLoadingNow = isFetching && fetchTypeRef.current === Play.NOW;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack gap="md">
|
<Stack gap="md">
|
||||||
<NumberInput
|
<NumberInput
|
||||||
@@ -166,60 +156,10 @@ export const ShuffleAllContextModal = () => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Divider />
|
<Divider />
|
||||||
<Group align="center" gap="md" justify="center" w="100%">
|
<PlayButtonGroup
|
||||||
<PlayButton
|
loading={(isFetching && fetchTypeRef.current) || false}
|
||||||
icon="mediaPlayNext"
|
onPlay={handlePlay}
|
||||||
isSecondary
|
|
||||||
loading={isLoadingNext}
|
|
||||||
onClick={() => handlePlay(Play.NEXT)}
|
|
||||||
onLongPress={() => handlePlay(Play.NEXT_SHUFFLE)}
|
|
||||||
/>
|
/>
|
||||||
<PlayButton
|
|
||||||
fill
|
|
||||||
loading={isLoadingNow}
|
|
||||||
onClick={() => handlePlay(Play.NOW)}
|
|
||||||
onLongPress={() => handlePlay(Play.SHUFFLE)}
|
|
||||||
/>
|
|
||||||
<PlayButton
|
|
||||||
icon="mediaPlayLast"
|
|
||||||
isSecondary
|
|
||||||
loading={isLoadingLast}
|
|
||||||
onClick={() => handlePlay(Play.LAST)}
|
|
||||||
onLongPress={() => handlePlay(Play.LAST_SHUFFLE)}
|
|
||||||
/>
|
|
||||||
</Group>
|
|
||||||
{/* <Group grow>
|
|
||||||
<Button
|
|
||||||
disabled={!limit || isFetching}
|
|
||||||
leftSection={<Icon icon="mediaPlayNext" />}
|
|
||||||
loading={fetchTypeRef.current === Play.NEXT && isFetching}
|
|
||||||
onClick={() => handlePlay(Play.NEXT)}
|
|
||||||
type="submit"
|
|
||||||
variant="default"
|
|
||||||
>
|
|
||||||
{t('player.addNext', { postProcess: 'sentenceCase' })}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
disabled={!limit || isFetching}
|
|
||||||
leftSection={<Icon icon="mediaPlayLast" />}
|
|
||||||
loading={fetchTypeRef.current === Play.LAST && isFetching}
|
|
||||||
onClick={() => handlePlay(Play.LAST)}
|
|
||||||
type="submit"
|
|
||||||
variant="default"
|
|
||||||
>
|
|
||||||
{t('player.addLast', { postProcess: 'sentenceCase' })}
|
|
||||||
</Button>
|
|
||||||
</Group>
|
|
||||||
<Button
|
|
||||||
disabled={!limit || isFetching}
|
|
||||||
leftSection={<Icon icon="mediaPlay" />}
|
|
||||||
loading={fetchTypeRef.current === Play.NOW && isFetching}
|
|
||||||
onClick={() => handlePlay(Play.NOW)}
|
|
||||||
type="submit"
|
|
||||||
variant="filled"
|
|
||||||
>
|
|
||||||
{t('player.play', { postProcess: 'sentenceCase' })}
|
|
||||||
</Button> */}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { closeAllModals, openModal } from '@mantine/modals';
|
import { closeAllModals, openModal } from '@mantine/modals';
|
||||||
import { CSSProperties, memo, ReactNode, useCallback } from 'react';
|
import { CSSProperties, memo, ReactNode, useCallback } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
|
||||||
|
|
||||||
import styles from './library-header-bar.module.css';
|
import styles from './library-header-bar.module.css';
|
||||||
|
|
||||||
@@ -53,7 +52,6 @@ const HeaderPlayButton = ({
|
|||||||
...props
|
...props
|
||||||
}: HeaderPlayButtonProps) => {
|
}: HeaderPlayButtonProps) => {
|
||||||
const serverId = useCurrentServerId();
|
const serverId = useCurrentServerId();
|
||||||
const { t } = useTranslation();
|
|
||||||
const player = usePlayer();
|
const player = usePlayer();
|
||||||
|
|
||||||
const handlePlay = useCallback(
|
const handlePlay = useCallback(
|
||||||
@@ -77,9 +75,16 @@ const HeaderPlayButton = ({
|
|||||||
openModal({
|
openModal({
|
||||||
children: <PlayButtonGroup onPlay={handlePlay} />,
|
children: <PlayButtonGroup onPlay={handlePlay} />,
|
||||||
size: 'xs',
|
size: 'xs',
|
||||||
title: t('player.play', { postProcess: 'titleCase' }),
|
styles: {
|
||||||
|
body: {
|
||||||
|
padding: 'var(--theme-spacing-md)',
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}, [serverId, handlePlay, t]);
|
}, [serverId, handlePlay]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.playButtonContainer}>
|
<div className={styles.playButtonContainer}>
|
||||||
|
|||||||
@@ -1,58 +1,56 @@
|
|||||||
import i18n from '/@/i18n/i18n';
|
import i18n from '/@/i18n/i18n';
|
||||||
import { ActionIcon } from '/@/shared/components/action-icon/action-icon';
|
import { PlayButton } from '/@/renderer/features/shared/components/play-button';
|
||||||
import { Group } from '/@/shared/components/group/group';
|
import { Group } from '/@/shared/components/group/group';
|
||||||
import { AppIconSelection } from '/@/shared/components/icon/icon';
|
import { AppIconSelection } from '/@/shared/components/icon/icon';
|
||||||
|
import { Tooltip } from '/@/shared/components/tooltip/tooltip';
|
||||||
import { Play } from '/@/shared/types/types';
|
import { Play } from '/@/shared/types/types';
|
||||||
|
|
||||||
const playButtons: { icon: AppIconSelection; label: string; type: Play }[] = [
|
const playButtons: { icon: AppIconSelection; label: string; secondary: boolean; type: Play }[] = [
|
||||||
{
|
|
||||||
icon: 'mediaPlay',
|
|
||||||
label: i18n.t('player.play', { postProcess: 'sentenceCase' }),
|
|
||||||
type: Play.NOW,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: 'mediaPlayNext',
|
icon: 'mediaPlayNext',
|
||||||
label: i18n.t('player.addNext', { postProcess: 'sentenceCase' }),
|
label: i18n.t('player.addNext', { postProcess: 'sentenceCase' }),
|
||||||
|
secondary: true,
|
||||||
type: Play.NEXT,
|
type: Play.NEXT,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
icon: 'mediaPlay',
|
||||||
|
label: i18n.t('player.play', { postProcess: 'sentenceCase' }),
|
||||||
|
secondary: false,
|
||||||
|
type: Play.NOW,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
icon: 'mediaPlayLast',
|
icon: 'mediaPlayLast',
|
||||||
label: i18n.t('player.addLast', { postProcess: 'sentenceCase' }),
|
label: i18n.t('player.addLast', { postProcess: 'sentenceCase' }),
|
||||||
|
secondary: true,
|
||||||
type: Play.LAST,
|
type: Play.LAST,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: 'mediaShuffle',
|
|
||||||
label: i18n.t('player.shuffle', { postProcess: 'sentenceCase' }),
|
|
||||||
type: Play.SHUFFLE,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const LONG_PRESS_PLAY_BEHAVIOR = {
|
||||||
|
[Play.LAST]: Play.LAST_SHUFFLE,
|
||||||
|
[Play.NEXT]: Play.NEXT_SHUFFLE,
|
||||||
|
[Play.NOW]: Play.SHUFFLE,
|
||||||
|
};
|
||||||
|
|
||||||
interface PlayButtonGroupProps {
|
interface PlayButtonGroupProps {
|
||||||
|
loading?: boolean | Play;
|
||||||
onPlay: (type: Play) => void;
|
onPlay: (type: Play) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PlayButtonGroup = ({ onPlay }: PlayButtonGroupProps) => {
|
export const PlayButtonGroup = ({ loading, onPlay }: PlayButtonGroupProps) => {
|
||||||
return (
|
return (
|
||||||
<Group grow>
|
<Group align="center" gap="md" justify="center">
|
||||||
{playButtons.map((button) => (
|
{playButtons.map((button) => (
|
||||||
<ActionIcon
|
<Tooltip key={button.type} label={button.label} openDelay={2000}>
|
||||||
|
<PlayButton
|
||||||
|
fill={button.type === Play.NOW}
|
||||||
icon={button.icon}
|
icon={button.icon}
|
||||||
iconProps={{
|
isSecondary={button.secondary}
|
||||||
size: 'xl',
|
loading={loading === button.type}
|
||||||
}}
|
|
||||||
key={button.type}
|
|
||||||
onClick={() => onPlay(button.type)}
|
onClick={() => onPlay(button.type)}
|
||||||
styles={{
|
onLongPress={() => onPlay(LONG_PRESS_PLAY_BEHAVIOR[button.type])}
|
||||||
root: {
|
|
||||||
padding: 'var(--mantine-spacing-lg)',
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
tooltip={{
|
|
||||||
label: button.label,
|
|
||||||
openDelay: 0,
|
|
||||||
}}
|
|
||||||
variant="default"
|
|
||||||
/>
|
/>
|
||||||
|
</Tooltip>
|
||||||
))}
|
))}
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { memo } from 'react';
|
import { forwardRef, memo } from 'react';
|
||||||
|
|
||||||
import styles from './play-button.module.css';
|
import styles from './play-button.module.css';
|
||||||
|
|
||||||
@@ -85,8 +85,9 @@ interface PlayButtonProps {
|
|||||||
onLongPress?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
onLongPress?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PlayButton = memo(
|
const PlayButtonBase = forwardRef<HTMLButtonElement, PlayButtonProps>(
|
||||||
({
|
(
|
||||||
|
{
|
||||||
classNames,
|
classNames,
|
||||||
fill,
|
fill,
|
||||||
icon = 'mediaPlay',
|
icon = 'mediaPlay',
|
||||||
@@ -94,7 +95,9 @@ export const PlayButton = memo(
|
|||||||
loading,
|
loading,
|
||||||
onClick,
|
onClick,
|
||||||
onLongPress,
|
onLongPress,
|
||||||
}: PlayButtonProps) => {
|
}: PlayButtonProps,
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
const clickHandlers = usePlayButtonClick({
|
const clickHandlers = usePlayButtonClick({
|
||||||
loading,
|
loading,
|
||||||
onClick,
|
onClick,
|
||||||
@@ -107,6 +110,7 @@ export const PlayButton = memo(
|
|||||||
[styles.fill]: fill,
|
[styles.fill]: fill,
|
||||||
[styles.secondary]: isSecondary,
|
[styles.secondary]: isSecondary,
|
||||||
})}
|
})}
|
||||||
|
ref={ref}
|
||||||
{...clickHandlers.handlers}
|
{...clickHandlers.handlers}
|
||||||
{...clickHandlers.props}
|
{...clickHandlers.props}
|
||||||
>
|
>
|
||||||
@@ -116,4 +120,6 @@ export const PlayButton = memo(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const PlayButton = memo(PlayButtonBase);
|
||||||
|
|
||||||
PlayButton.displayName = 'PlayButton';
|
PlayButton.displayName = 'PlayButton';
|
||||||
|
|||||||
Reference in New Issue
Block a user