From 524513af8d9d34ef21e10c55b9a53d7a20b9e953 Mon Sep 17 00:00:00 2001 From: Doma Date: Thu, 27 Jul 2023 11:36:35 +0800 Subject: [PATCH 1/4] fix: make whole cover image clickable for toggling play/pause --- src/components/player.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/player.tsx b/src/components/player.tsx index 0b381c9..0657880 100644 --- a/src/components/player.tsx +++ b/src/components/player.tsx @@ -171,6 +171,7 @@ export function APlayer({
{audioControl.isPlaying ? : }
From e29f5930916fde7519303870a324d71a406105e2 Mon Sep 17 00:00:00 2001 From: Doma Date: Thu, 27 Jul 2023 13:23:34 +0800 Subject: [PATCH 2/4] fix: playlist height transition not working --- src/components/list.tsx | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/list.tsx b/src/components/list.tsx index e2f7d7e..7451688 100644 --- a/src/components/list.tsx +++ b/src/components/list.tsx @@ -1,7 +1,7 @@ +import { useCallback, useEffect, useRef } from "react"; import { clsx } from "clsx"; import { defaultThemeColor } from "../constants"; import type { ArtistInfo, AudioInfo } from "../types"; -import { useCallback } from "react"; type PlaylistProps = { open: boolean; @@ -29,8 +29,26 @@ export function Playlist({ return artist.name ?? "Audio artist"; }, []); + const listRef = useRef(null); + + useEffect(() => { + if (listRef.current) { + const listElement = listRef.current; + + listElement.style.maxHeight = `${Math.min( + listElement.scrollHeight, + listMaxHeight ?? Infinity + )}px`; + + return () => { + listElement.removeAttribute("style"); + }; + } + }, [listMaxHeight]); + return (
Date: Thu, 27 Jul 2023 13:30:32 +0800 Subject: [PATCH 3/4] feat: fixed mode --- demo/index.tsx | 7 +++- src/components/controller.tsx | 44 +++++++++++++++++--- src/components/lyrics.tsx | 9 ++++- src/components/player.tsx | 76 +++++++++++++++++++++++++++++++---- src/hooks/usePlaylist.ts | 14 +++++++ 5 files changed, 135 insertions(+), 15 deletions(-) diff --git a/demo/index.tsx b/demo/index.tsx index e3e8d09..c2b3328 100644 --- a/demo/index.tsx +++ b/demo/index.tsx @@ -62,7 +62,12 @@ function App() { }} >
- +
); diff --git a/src/components/controller.tsx b/src/components/controller.tsx index d81997a..bfff389 100644 --- a/src/components/controller.tsx +++ b/src/components/controller.tsx @@ -1,4 +1,10 @@ +import { useCallback } from "react"; +import { clsx } from "clsx"; import { ReactComponent as IconMenu } from "../assets/menu.svg"; +import { ReactComponent as IconPlay } from "../assets/play.svg"; +import { ReactComponent as IconPause } from "../assets/pause.svg"; +import { ReactComponent as IconSkip } from "../assets/skip.svg"; +import { ReactComponent as IconLrc } from "../assets/lrc.svg"; import { ReactComponent as IconOrderList } from "../assets/order-list.svg"; import { ReactComponent as IconOrderRandom } from "../assets/order-random.svg"; import { ReactComponent as IconLoopAll } from "../assets/loop-all.svg"; @@ -6,7 +12,6 @@ import { ReactComponent as IconLoopOne } from "../assets/loop-one.svg"; import { ReactComponent as IconLoopNone } from "../assets/loop-none.svg"; import { formatAudioDuration } from "../utils/formatAudioDuration"; import { ProgressBar } from "./progress"; -import React, { useCallback } from "react"; import { PlaylistLoop, PlaylistOrder } from "../hooks/usePlaylist"; import { Volume } from "./volume"; @@ -25,6 +30,12 @@ type PlaybackControlsProps = { loop: PlaylistLoop; onLoopChange: (loop: PlaylistLoop) => void; onSeek?: (second: number) => void; + isPlaying: boolean; + onTogglePlay?: () => void; + onSkipForward?: () => void; + onSkipBack?: () => void; + showLyrics?: boolean; + onToggleLyrics?: () => void; }; export function PlaybackControls({ @@ -42,6 +53,12 @@ export function PlaybackControls({ loop, onLoopChange, onSeek, + isPlaying, + onTogglePlay, + onSkipForward, + onSkipBack, + showLyrics = true, + onToggleLyrics, }: PlaybackControlsProps) { // Switch order between "list" and "random" const handleOrderButtonClick = useCallback(() => { @@ -96,9 +113,18 @@ export function PlaybackControls({ {formatAudioDuration(audioDurationSeconds)} - - - + + + + + {isPlaying ? : } + + + + - +
); diff --git a/src/components/lyrics.tsx b/src/components/lyrics.tsx index e485d10..3715c24 100644 --- a/src/components/lyrics.tsx +++ b/src/components/lyrics.tsx @@ -2,11 +2,12 @@ import React, { useMemo } from "react"; import { clsx } from "clsx"; type LyricsProps = { + show: boolean; lrcText?: string; currentTime: number; }; -export function Lyrics({ lrcText, currentTime }: LyricsProps) { +export function Lyrics({ show, lrcText, currentTime }: LyricsProps) { const lines = useMemo(() => parseLrc(lrcText), [lrcText]); const currentLineIndex = useMemo(() => { @@ -29,7 +30,11 @@ export function Lyrics({ lrcText, currentTime }: LyricsProps) { }, [currentLineIndex]); return ( -
+
{lrcText ? (
{lines.map(([, text], index) => ( diff --git a/src/components/player.tsx b/src/components/player.tsx index 0657880..25e4ec8 100644 --- a/src/components/player.tsx +++ b/src/components/player.tsx @@ -3,6 +3,7 @@ import { clsx } from "clsx"; import { ReactComponent as IconPlay } from "../assets/play.svg"; import { ReactComponent as IconPause } from "../assets/pause.svg"; +import { ReactComponent as IconRight } from "../assets/right.svg"; import type { ArtistInfo, AudioInfo } from "../types"; import { Playlist } from "./list"; import { PlaybackControls } from "./controller"; @@ -31,6 +32,11 @@ type APlayerProps = { */ volume?: number; + /** + * @default "normal" + */ + appearance?: "normal" | "fixed"; + /** * @default "all" */ @@ -52,6 +58,7 @@ type APlayerProps = { export function APlayer({ theme = defaultThemeColor, audio, + appearance = "normal", volume = 0.7, initialLoop, initialOrder, @@ -160,15 +167,39 @@ export function APlayer({ ); }, []); + const [mini, setMini] = useState(false); + + const [displayLyrics, setDisplayLyrics] = useState(true); + + const bodyRef = useRef(null); + + useEffect(() => { + if (appearance === "fixed") { + if (bodyRef.current) { + const bodyElement = bodyRef.current; + // Explicitly set width on the body element + // to ensure the width transition works + bodyElement.style.width = bodyElement.offsetWidth - 18 + "px"; + + return () => { + bodyElement.removeAttribute("style"); + }; + } + } + }, [appearance]); + return (
-
+
- + {appearance === "fixed" ? null : ( + + )} { + if (playlist.hasNextSong) { + playlist.next(); + } + }} + onSkipBack={() => { + playlist.previous(); + }} + showLyrics={displayLyrics} + onToggleLyrics={() => { + setDisplayLyrics((prev) => !prev); + }} />
{notice.text}
-
+
setMini((prev) => !prev)} + > + +
{hasPlaylist ? ( ) : null} + {appearance === "fixed" && ( + + )}
); } diff --git a/src/hooks/usePlaylist.ts b/src/hooks/usePlaylist.ts index d4e2b59..2abe393 100644 --- a/src/hooks/usePlaylist.ts +++ b/src/hooks/usePlaylist.ts @@ -14,6 +14,7 @@ type PlaylistState = Readonly<{ currentSong: T; hasNextSong: boolean; next: () => void; + previous: () => void; prioritize: (song: T) => void; order: PlaylistOrder; setOrder: (order: PlaylistOrder) => void; @@ -79,6 +80,18 @@ export function usePlaylist( } }, [nextSong]); + const previous = useCallback(() => { + setCurrentSong((prev) => { + const currentSongIndex = list.indexOf(prev); + + if (currentSongIndex > 0) { + return list[currentSongIndex - 1]; + } + + return prev; + }); + }, [list]); + const prioritize = useCallback((song: T) => { setCurrentSong(song); }, []); @@ -87,6 +100,7 @@ export function usePlaylist( currentSong, hasNextSong: typeof nextSong !== "undefined", next, + previous, prioritize, order, setOrder, From 5877f2f5cfb83dee630f62fefe5733c5be4fc19c Mon Sep 17 00:00:00 2001 From: Doma Date: Thu, 27 Jul 2023 13:32:45 +0800 Subject: [PATCH 4/4] ci: run semantic-release on beta branch --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25358ea..85ebad8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [master, alpha] + branches: [master, beta] pull_request: branches: [master]