Compare commits
7 Commits
66a9dbea5c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 153f634a08 | |||
| 1f6c906576 | |||
| c0ead41d21 | |||
| e383876bb0 | |||
| eaf6d47ba0 | |||
| 56c4cf014d | |||
| 2c10ec28aa |
3
.dockerignore
Normal file
3
.dockerignore
Normal file
@@ -0,0 +1,3 @@
|
||||
**/node_modules/
|
||||
**/dist
|
||||
.git
|
||||
@@ -1,6 +1,15 @@
|
||||
steps:
|
||||
- name: build
|
||||
image: node:18-alpine
|
||||
commands:
|
||||
- npm install
|
||||
- npm run build
|
||||
when:
|
||||
branch: main
|
||||
event:
|
||||
- push
|
||||
- manual
|
||||
steps:
|
||||
- name: build
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
repo: git.halfbinary.net/${CI_REPO_OWNER}/prettyplayerfe
|
||||
registry: git.halfbinary.net
|
||||
tags: ${CI_PIPELINE_NUMBER}
|
||||
username: ${CI_REPO_OWNER}
|
||||
password:
|
||||
from_secret: docker_password
|
||||
33
src/App.css
33
src/App.css
@@ -35,6 +35,25 @@
|
||||
transition: height 2s;
|
||||
}
|
||||
|
||||
.player-container {
|
||||
background: rgba(0,0,0,0.5);
|
||||
position: sticky;
|
||||
width: 100%;
|
||||
bottom:0;
|
||||
}
|
||||
|
||||
.expander {
|
||||
align-self: center;
|
||||
height:.75em;
|
||||
aspect-ratio: 1 / 1;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 500%;
|
||||
}
|
||||
|
||||
.album-title {
|
||||
font-size: larger;
|
||||
}
|
||||
@@ -42,17 +61,3 @@
|
||||
.bold-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.expander {
|
||||
position: absolute;
|
||||
height: 8vmin;
|
||||
width: 8vmin;
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
border-radius: 50%;
|
||||
margin-top: 1vmin;
|
||||
margin-left: 5vmin;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 500%;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ function App() {
|
||||
const [albums, setAlbums] = useState(Array<AlbumMetadata>)
|
||||
const [selectedAlbum, setSelectedAlbum] = useState("")
|
||||
const [albumInfo, setAlbumInfo] = useState<AlbumInfo>()
|
||||
const [isShowAlbumInfo, setIsShowAlbumInfo] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
let fetched = fetch(`${hostName}/album`)
|
||||
@@ -41,10 +42,14 @@ function App() {
|
||||
setSelectedAlbum(event.currentTarget.id)
|
||||
}
|
||||
|
||||
function handleAlbumInfoAdjust() {
|
||||
setIsShowAlbumInfo(!isShowAlbumInfo)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={"gallery"}>
|
||||
<PhotoContainer imageList={albums} albumClickHandler={handleAlbumClick}/>
|
||||
{albumInfo ? <AlbumPlayer albumHash={selectedAlbum} albumInfo={albumInfo} key={selectedAlbum}/> : <div></div> }
|
||||
{albumInfo ? <AlbumPlayer handleAlbumInfoAdjust={handleAlbumInfoAdjust} isShowAlbumInfo={isShowAlbumInfo} albumHash={selectedAlbum} albumInfo={albumInfo} key={selectedAlbum}/> : <div></div> }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import {AlbumInfo} from "../models/AlbumInfo.ts";
|
||||
import TrackListing from "./TrackListing.tsx";
|
||||
import React from "react";
|
||||
|
||||
interface AlbumInfoDisplayProps {
|
||||
albumInfo: AlbumInfo,
|
||||
trackNumber: number
|
||||
trackNumber: number,
|
||||
trackClickHandler: (event: React.MouseEvent<HTMLElement>, trackNumber: number) => void
|
||||
}
|
||||
export default function AlbumInfoDisplay(props: Readonly<AlbumInfoDisplayProps>) {
|
||||
let isVarious = props.albumInfo.albumArtist.startsWith("Various")
|
||||
@@ -11,7 +13,7 @@ export default function AlbumInfoDisplay(props: Readonly<AlbumInfoDisplayProps>)
|
||||
return (
|
||||
<div>
|
||||
<div className={`album-title`}>{!isVarious && `${props.albumInfo.albumArtist} - `}{props.albumInfo.albumTitle}</div>
|
||||
<TrackListing trackList={props.albumInfo.trackList} isOneArtist={isOneArtist} trackNumber={props.trackNumber}/>
|
||||
<TrackListing trackClickHandler={props.trackClickHandler} trackList={props.albumInfo.trackList} isOneArtist={isOneArtist} trackNumber={props.trackNumber}/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import {useEffect, useState} from "react";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import hostName from "../Config.ts";
|
||||
import {AlbumInfo} from "../models/AlbumInfo.ts";
|
||||
import AlbumInfoDisplay from "./AlbumInfoDisplay.tsx";
|
||||
@@ -9,12 +9,13 @@ import minimize from '/minimize-2.svg'
|
||||
interface AlbumPlayerProps {
|
||||
albumHash: string,
|
||||
albumInfo: AlbumInfo
|
||||
handleAlbumInfoAdjust: () => void,
|
||||
isShowAlbumInfo: boolean
|
||||
}
|
||||
|
||||
export default function AlbumPlayer(props: Readonly<AlbumPlayerProps>) {
|
||||
const [trackNum, setTrackNum] = useState<number>(0)
|
||||
const [isAlbumOver, setIsAlbumOver] = useState(false)
|
||||
const [isShowAlbumInfo, setIsShowAlbumInfo] = useState(false)
|
||||
|
||||
let album = props.albumInfo
|
||||
|
||||
@@ -30,16 +31,16 @@ export default function AlbumPlayer(props: Readonly<AlbumPlayerProps>) {
|
||||
}
|
||||
}
|
||||
|
||||
function handleAlbumInfoAdjust() {
|
||||
setIsShowAlbumInfo(!isShowAlbumInfo)
|
||||
function handleTrackClick(_: React.MouseEvent<HTMLElement>, trackNumber: number) {
|
||||
setTrackNum(trackNumber)
|
||||
}
|
||||
|
||||
if(props.albumHash && album) {
|
||||
console.log(album)
|
||||
return (
|
||||
<div className={"player"}>
|
||||
<div className={`expander`} onClick={handleAlbumInfoAdjust} id={"maximizer"}>{isShowAlbumInfo ? <img src={minimize} alt={'minimize song text'}/> : <img src={maximize} alt={'show full album information'}/>}</div>
|
||||
{isShowAlbumInfo ? <AlbumInfoDisplay albumInfo={props.albumInfo} trackNumber={trackNum} /> : <TrackInfoDisplay artist={album.trackList[trackNum].trackArtist} track={album.trackList[trackNum].trackTitle} />}
|
||||
<div className={"player-container"}>
|
||||
<div className={`expander`} onClick={props.handleAlbumInfoAdjust} id={"maximizer"}>{props.isShowAlbumInfo ? <img src={minimize} alt={'minimize song text'}/> : <img src={maximize} alt={'show full album information'}/>}</div>
|
||||
<div>{props.isShowAlbumInfo ? <AlbumInfoDisplay albumInfo={props.albumInfo} trackNumber={trackNum} trackClickHandler={handleTrackClick} /> : <TrackInfoDisplay artist={album.trackList[trackNum].trackArtist} track={album.trackList[trackNum].trackTitle} />}</div>
|
||||
<audio title={album.trackList[trackNum].trackTitle} controls={true} autoPlay={true} preload={"metadata"}
|
||||
src={`${hostName}/music/album/${props.albumHash}/track/${trackNum}`}
|
||||
onEnded={handleNextTrack} />
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import {AlbumTrackInfo} from "../models/AlbumTrackInfo.ts";
|
||||
import React from "react";
|
||||
|
||||
interface TrackListingProps {
|
||||
trackList: AlbumTrackInfo[],
|
||||
isOneArtist: boolean,
|
||||
trackNumber: number
|
||||
trackNumber: number,
|
||||
trackClickHandler: (event: React.MouseEvent<HTMLElement>, trackNumber: number) => void
|
||||
}
|
||||
export default function TrackListing(props: Readonly<TrackListingProps>) {
|
||||
return (
|
||||
@@ -12,7 +14,7 @@ export default function TrackListing(props: Readonly<TrackListingProps>) {
|
||||
let rawKeyString = `${track.trackNumber}${track.trackArtist}${track.trackTitle}`
|
||||
let isCurrentTrack = index===props.trackNumber
|
||||
return (
|
||||
<div key={rawKeyString} className={ isCurrentTrack ? `bold-title` : ``}>{track.trackNumber}. {!props.isOneArtist && `${track.trackArtist} - `}{track.trackTitle}</div>
|
||||
<div onClick={(e) => props.trackClickHandler(e, index)} key={rawKeyString} className={ isCurrentTrack ? `bold-title` : ``}>{track.trackNumber}. {!props.isOneArtist && `${track.trackArtist} - `}{track.trackTitle}</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user