mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-11 03:24:16 +00:00
improve handlers & style
This commit is contained in:
parent
5d6629402d
commit
95bae7cb61
@ -1,10 +1,8 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
import { Button } from "antd"
|
import Marquee from "react-fast-marquee"
|
||||||
|
|
||||||
import UseAnimations from "react-useanimations"
|
import Controls from "components/Player/Controls"
|
||||||
import LoadingAnimation from "react-useanimations/lib/loading"
|
|
||||||
import { Icons } from "components/Icons"
|
|
||||||
|
|
||||||
import Image from "components/Image"
|
import Image from "components/Image"
|
||||||
|
|
||||||
@ -12,6 +10,16 @@ import request from "comty.js/handlers/request"
|
|||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
|
function RGBStringToValues(rgbString) {
|
||||||
|
if (!rgbString) {
|
||||||
|
return [0, 0, 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rgb = rgbString.replace("rgb(", "").replace(")", "").split(",").map((v) => parseInt(v))
|
||||||
|
|
||||||
|
return [rgb[0], rgb[1], rgb[2]]
|
||||||
|
}
|
||||||
|
|
||||||
function composeRgbValues(values) {
|
function composeRgbValues(values) {
|
||||||
let value = ""
|
let value = ""
|
||||||
|
|
||||||
@ -37,12 +45,33 @@ function calculateLineTime(line) {
|
|||||||
return line.endTimeMs - line.startTimeMs
|
return line.endTimeMs - line.startTimeMs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isOverflown(element) {
|
||||||
|
if (!element) {
|
||||||
|
console.log("element is null")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
|
||||||
|
}
|
||||||
|
|
||||||
class PlayerController extends React.Component {
|
class PlayerController extends React.Component {
|
||||||
state = {
|
state = {
|
||||||
hovering: false,
|
|
||||||
colorAnalysis: null,
|
colorAnalysis: null,
|
||||||
currentState: null,
|
|
||||||
currentDragWidth: 0,
|
currentDragWidth: 0,
|
||||||
|
titleOverflown: false,
|
||||||
|
|
||||||
|
currentDuration: 0,
|
||||||
|
currentTime: 0,
|
||||||
|
|
||||||
|
currentPlaying: app.cores.player.getState("currentAudioManifest"),
|
||||||
|
loading: app.cores.player.getState("loading") ?? false,
|
||||||
|
playbackStatus: app.cores.player.getState("playbackStatus") ?? "stopped",
|
||||||
|
|
||||||
|
audioMuted: app.cores.player.getState("audioMuted") ?? false,
|
||||||
|
volume: app.cores.player.getState("audioVolume"),
|
||||||
|
|
||||||
|
syncModeLocked: app.cores.player.getState("syncModeLocked"),
|
||||||
|
syncMode: app.cores.player.getState("syncMode"),
|
||||||
}
|
}
|
||||||
|
|
||||||
events = {
|
events = {
|
||||||
@ -50,16 +79,37 @@ class PlayerController extends React.Component {
|
|||||||
this.setState({ colorAnalysis })
|
this.setState({ colorAnalysis })
|
||||||
},
|
},
|
||||||
"player.seek.update": (seekTime) => {
|
"player.seek.update": (seekTime) => {
|
||||||
const updatedState = this.state.currentState
|
|
||||||
|
|
||||||
updatedState.time = seekTime
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
currentState: updatedState,
|
currentTime: seekTime,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
"player.status.update": (data) => {
|
||||||
|
this.setState({ playbackStatus: data })
|
||||||
|
},
|
||||||
|
"player.current.update": (data) => {
|
||||||
|
this.setState({ titleOverflown: false })
|
||||||
|
|
||||||
|
this.setState({ currentPlaying: data })
|
||||||
|
},
|
||||||
|
"player.syncModeLocked.update": (to) => {
|
||||||
|
this.setState({ syncModeLocked: to })
|
||||||
|
},
|
||||||
|
"player.syncMode.update": (to) => {
|
||||||
|
this.setState({ syncMode: to })
|
||||||
|
},
|
||||||
|
"player.mute.update": (data) => {
|
||||||
|
this.setState({ audioMuted: data })
|
||||||
|
},
|
||||||
|
"player.volume.update": (data) => {
|
||||||
|
this.setState({ audioVolume: data })
|
||||||
|
},
|
||||||
|
"player.loading.update": (data) => {
|
||||||
|
this.setState({ loading: data })
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
titleRef = React.createRef()
|
||||||
|
|
||||||
startSync() {
|
startSync() {
|
||||||
// create a interval to get state from player
|
// create a interval to get state from player
|
||||||
if (this.syncInterval) {
|
if (this.syncInterval) {
|
||||||
@ -69,7 +119,15 @@ class PlayerController extends React.Component {
|
|||||||
this.syncInterval = setInterval(() => {
|
this.syncInterval = setInterval(() => {
|
||||||
const currentState = app.cores.player.currentState()
|
const currentState = app.cores.player.currentState()
|
||||||
|
|
||||||
this.setState({ currentState })
|
this.setState({
|
||||||
|
currentDuration: currentState.duration,
|
||||||
|
currentTime: currentState.time,
|
||||||
|
colorAnalysis: currentState.colorAnalysis,
|
||||||
|
})
|
||||||
|
|
||||||
|
const titleOverflown = isOverflown(this.titleRef.current)
|
||||||
|
|
||||||
|
this.setState({ titleOverflown: titleOverflown })
|
||||||
}, 800)
|
}, 800)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,13 +140,21 @@ class PlayerController extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onClickTooglePlayButton = () => {
|
onClickTooglePlayButton = () => {
|
||||||
if (this.state.currentState?.playbackStatus === "playing") {
|
if (this.state?.playbackStatus === "playing") {
|
||||||
app.cores.player.playback.pause()
|
app.cores.player.playback.pause()
|
||||||
} else {
|
} else {
|
||||||
app.cores.player.playback.play()
|
app.cores.player.playback.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateVolume = (value) => {
|
||||||
|
app.cores.player.volume(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
toogleMute = () => {
|
||||||
|
app.cores.player.toogleMute()
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
for (const event in this.events) {
|
for (const event in this.events) {
|
||||||
app.eventBus.on(event, this.events[event])
|
app.eventBus.on(event, this.events[event])
|
||||||
@ -99,6 +165,26 @@ class PlayerController extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.startSync()
|
this.startSync()
|
||||||
|
|
||||||
|
// // create a intersection observer to check if title is overflown
|
||||||
|
// // if the entire title is not visible, we will use marquee
|
||||||
|
// this.titleObserver = new IntersectionObserver((entries) => {
|
||||||
|
// for (const entry of entries) {
|
||||||
|
// if (entry.isIntersecting) {
|
||||||
|
// this.setState({ titleOverflown: false })
|
||||||
|
// } else {
|
||||||
|
// this.setState({ titleOverflown: true })
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }, {
|
||||||
|
// root: null,
|
||||||
|
// rootMargin: "0px",
|
||||||
|
// threshold: 1.0,
|
||||||
|
// })
|
||||||
|
|
||||||
|
console.log(this.titleRef.current)
|
||||||
|
|
||||||
|
//this.titleObserver.observe(this.titleRef.current)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@ -121,70 +207,91 @@ class PlayerController extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
//const bgColor = RGBStringToValues(getComputedStyle(document.documentElement).getPropertyValue("--background-color-accent-values"))
|
||||||
|
|
||||||
return <div className="player_controller_wrapper">
|
return <div className="player_controller_wrapper">
|
||||||
<div
|
<div
|
||||||
onMouseEnter={() => {
|
|
||||||
this.setState({ hovering: true })
|
|
||||||
}}
|
|
||||||
onMouseLeave={() => {
|
|
||||||
this.setState({ hovering: false })
|
|
||||||
}}
|
|
||||||
className={classnames(
|
className={classnames(
|
||||||
"player_controller",
|
"player_controller",
|
||||||
{
|
|
||||||
["player_controller--hovering"]: this.state.hovering || this.state.dragging,
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="player_controller_cover">
|
<div className="player_controller_cover">
|
||||||
<Image
|
<Image
|
||||||
src={this.state.currentState?.manifest?.thumbnail}
|
src={this.state.currentPlaying?.thumbnail ?? "/assets/no_song.png"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="player_controller_left">
|
<div className="player_controller_left">
|
||||||
<div className="player_controller_info">
|
<div className="player_controller_info">
|
||||||
<div className="player_controller_info_title">
|
<div className="player_controller_info_title">
|
||||||
{this.state.currentState?.manifest?.title}
|
{
|
||||||
|
<h4
|
||||||
|
ref={this.titleRef}
|
||||||
|
className={classnames(
|
||||||
|
"player_controller_info_title_text",
|
||||||
|
{
|
||||||
|
["overflown"]: this.state.titleOverflown,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
this.state.plabackState === "stopped" ? "Nothing is playing" : <>
|
||||||
|
{this.state.currentPlaying?.title ?? "Nothing is playing"}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</h4>
|
||||||
|
}
|
||||||
|
|
||||||
|
{this.state.titleOverflown &&
|
||||||
|
<Marquee
|
||||||
|
//gradient
|
||||||
|
//gradientColor={bgColor}
|
||||||
|
//gradientWidth={20}
|
||||||
|
play={this.state.plabackState !== "stopped"}
|
||||||
|
>
|
||||||
|
<h4>
|
||||||
|
{
|
||||||
|
this.state.plabackState === "stopped" ? "Nothing is playing" : <>
|
||||||
|
{this.state.currentPlaying?.title ?? "Nothing is playing"}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</h4>
|
||||||
|
</Marquee>}
|
||||||
</div>
|
</div>
|
||||||
<div className="player_controller_info_artist">
|
<div className="player_controller_info_artist">
|
||||||
{this.state.currentState?.manifest?.artist} - {this.state.currentState?.manifest?.album}
|
{
|
||||||
|
this.state.currentPlaying?.artist && <>
|
||||||
|
<h3>
|
||||||
|
{this.state.currentPlaying?.artist ?? "Unknown"}
|
||||||
|
</h3>
|
||||||
|
{
|
||||||
|
this.state.currentPlaying?.album && <>
|
||||||
|
<span> - </span>
|
||||||
|
<h3>
|
||||||
|
{this.state.currentPlaying?.album ?? "Unknown"}
|
||||||
|
</h3>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="player_controller_controls">
|
<Controls
|
||||||
<Button
|
className="player_controller_controls"
|
||||||
type="ghost"
|
controls={{
|
||||||
shape="round"
|
previous: this.onClickPreviousButton,
|
||||||
icon={<Icons.ChevronLeft />}
|
toogle: this.onClickTooglePlayButton,
|
||||||
onClick={this.onClickPreviousButton}
|
next: this.onClickNextButton,
|
||||||
disabled={this.state.currentState?.syncModeLocked}
|
}}
|
||||||
/>
|
syncModeLocked={this.state.syncModeLocked}
|
||||||
<Button
|
playbackStatus={this.state.playbackStatus}
|
||||||
className="playButton"
|
loading={this.state.loading}
|
||||||
type="primary"
|
audioVolume={this.state.audioVolume}
|
||||||
shape="circle"
|
audioMuted={this.state.audioMuted}
|
||||||
icon={this.state.currentState?.playbackStatus === "playing" ? <Icons.MdPause /> : <Icons.MdPlayArrow />}
|
onVolumeUpdate={this.updateVolume}
|
||||||
onClick={this.onClickTooglePlayButton}
|
onMuteUpdate={this.toogleMute}
|
||||||
disabled={this.state.currentState?.syncModeLocked}
|
/>
|
||||||
>
|
|
||||||
{
|
|
||||||
this.state.currentState?.loading && <div className="loadCircle">
|
|
||||||
<UseAnimations
|
|
||||||
animation={LoadingAnimation}
|
|
||||||
size="100%"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
type="ghost"
|
|
||||||
shape="round"
|
|
||||||
icon={<Icons.ChevronRight />}
|
|
||||||
onClick={this.onClickNextButton}
|
|
||||||
disabled={this.state.currentState?.syncModeLocked}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="player_controller_progress_wrapper">
|
<div className="player_controller_progress_wrapper">
|
||||||
@ -197,7 +304,7 @@ class PlayerController extends React.Component {
|
|||||||
}}
|
}}
|
||||||
onMouseUp={(e) => {
|
onMouseUp={(e) => {
|
||||||
const rect = e.currentTarget.getBoundingClientRect()
|
const rect = e.currentTarget.getBoundingClientRect()
|
||||||
const seekTime = this.state.currentState?.duration * (e.clientX - rect.left) / rect.width
|
const seekTime = this.state.currentDuration * (e.clientX - rect.left) / rect.width
|
||||||
|
|
||||||
this.onDragEnd(seekTime)
|
this.onDragEnd(seekTime)
|
||||||
}}
|
}}
|
||||||
@ -210,7 +317,7 @@ class PlayerController extends React.Component {
|
|||||||
>
|
>
|
||||||
<div className="player_controller_progress_bar"
|
<div className="player_controller_progress_bar"
|
||||||
style={{
|
style={{
|
||||||
width: `${this.state.dragging ? this.state.currentDragWidth : this.state.currentState?.time / this.state.currentState?.duration * 100}%`
|
width: `${this.state.dragging ? this.state.currentDragWidth : this.state.currentTime / this.state.currentDuration * 100}%`
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -234,20 +341,11 @@ export default class SyncLyrics extends React.Component {
|
|||||||
|
|
||||||
colorAnalysis: null,
|
colorAnalysis: null,
|
||||||
|
|
||||||
classnames: [
|
classnames: {
|
||||||
{
|
"cinematic-mode": false,
|
||||||
name: "cinematic-mode",
|
"centered-player": false,
|
||||||
enabled: false,
|
"video-canvas-enabled": false,
|
||||||
},
|
}
|
||||||
{
|
|
||||||
name: "centered-player",
|
|
||||||
enabled: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "video-canvas-enabled",
|
|
||||||
enabled: false,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
visualizerRef = React.createRef()
|
visualizerRef = React.createRef()
|
||||||
@ -274,6 +372,56 @@ export default class SyncLyrics extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toogleClassName = (className, to) => {
|
||||||
|
if (typeof to === "undefined") {
|
||||||
|
to = !this.state.classnames[className]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to) {
|
||||||
|
if (this.state.classnames[className] === true) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//app.message.info("Toogling on " + className)
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
classnames: {
|
||||||
|
...this.state.classnames,
|
||||||
|
[className]: true
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
if (this.state.classnames[className] === false) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
//app.message.info("Toogling off " + className)
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
classnames: {
|
||||||
|
...this.state.classnames,
|
||||||
|
[className]: false
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toogleVideoCanvas = (to) => {
|
||||||
|
return this.toogleClassName("video-canvas-enabled", to)
|
||||||
|
}
|
||||||
|
|
||||||
|
toogleCenteredControllerMode = (to) => {
|
||||||
|
return this.toogleClassName("centered-player", to)
|
||||||
|
}
|
||||||
|
|
||||||
|
toogleCinematicMode = (to) => {
|
||||||
|
return this.toogleClassName("cinematic-mode", to)
|
||||||
|
}
|
||||||
|
|
||||||
isCurrentLine = (line) => {
|
isCurrentLine = (line) => {
|
||||||
if (!this.state.currentLine) {
|
if (!this.state.currentLine) {
|
||||||
return false
|
return false
|
||||||
@ -342,9 +490,13 @@ export default class SyncLyrics extends React.Component {
|
|||||||
|
|
||||||
if (data.canvas_url) {
|
if (data.canvas_url) {
|
||||||
//app.message.info("Video canvas loaded")
|
//app.message.info("Video canvas loaded")
|
||||||
|
console.log(`[SyncLyrics] Video canvas loaded`)
|
||||||
|
|
||||||
this.toogleVideoCanvas(true)
|
this.toogleVideoCanvas(true)
|
||||||
} else {
|
} else {
|
||||||
//app.message.info("No video canvas available for this song")
|
//app.message.info("No video canvas available for this song")
|
||||||
|
console.log(`[SyncLyrics] No video canvas available for this song`)
|
||||||
|
|
||||||
this.toogleVideoCanvas(false)
|
this.toogleVideoCanvas(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,10 +504,13 @@ export default class SyncLyrics extends React.Component {
|
|||||||
if (data.lines.length === 0 || data.syncType !== "LINE_SYNCED") {
|
if (data.lines.length === 0 || data.syncType !== "LINE_SYNCED") {
|
||||||
//app.message.info("No lyrics available for this song")
|
//app.message.info("No lyrics available for this song")
|
||||||
|
|
||||||
|
console.log(`[SyncLyrics] No lyrics available for this song, sync type [${data.syncType}]`)
|
||||||
|
|
||||||
this.toogleCinematicMode(false)
|
this.toogleCinematicMode(false)
|
||||||
this.toogleCenteredControllerMode(true)
|
this.toogleCenteredControllerMode(true)
|
||||||
} else {
|
} else {
|
||||||
//app.message.info("Lyrics loaded, starting sync...")
|
//app.message.info("Lyrics loaded, starting sync...")
|
||||||
|
console.log(`[SyncLyrics] Starting sync with type [${data.syncType}]`)
|
||||||
|
|
||||||
this.toogleCenteredControllerMode(false)
|
this.toogleCenteredControllerMode(false)
|
||||||
this.startLyricsSync()
|
this.startLyricsSync()
|
||||||
@ -365,65 +520,11 @@ export default class SyncLyrics extends React.Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
syncType: data.syncType,
|
syncType: data.syncType,
|
||||||
canvas_url: data.canvas_url,
|
canvas_url: data.canvas_url ?? null,
|
||||||
lyrics: data.lines,
|
lyrics: data.lines,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
toogleClassName = (className, to) => {
|
|
||||||
let currentState = this.state.classnames.find((c) => c.name === className)
|
|
||||||
|
|
||||||
if (!currentState) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof to === "undefined") {
|
|
||||||
to = !currentState?.enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to) {
|
|
||||||
if (currentState.enabled) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//app.message.info("Toogling on " + className)
|
|
||||||
|
|
||||||
currentState.enabled = true
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
classnames: this.state.classnames,
|
|
||||||
})
|
|
||||||
|
|
||||||
return true
|
|
||||||
} else {
|
|
||||||
if (!currentState.enabled) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//app.message.info("Toogling off " + className)
|
|
||||||
|
|
||||||
currentState.enabled = false
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
classnames: this.state.classnames,
|
|
||||||
})
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
toogleVideoCanvas = (to) => {
|
|
||||||
return this.toogleClassName("video-canvas-enabled", to)
|
|
||||||
}
|
|
||||||
|
|
||||||
toogleCenteredControllerMode = (to) => {
|
|
||||||
return this.toogleClassName("centered-player", to)
|
|
||||||
}
|
|
||||||
|
|
||||||
toogleCinematicMode = (to) => {
|
|
||||||
return this.toogleClassName("cinematic-mode", to)
|
|
||||||
}
|
|
||||||
|
|
||||||
startLyricsSync = () => {
|
startLyricsSync = () => {
|
||||||
// create interval to sync lyrics
|
// create interval to sync lyrics
|
||||||
if (this.syncInterval) {
|
if (this.syncInterval) {
|
||||||
@ -495,8 +596,16 @@ export default class SyncLyrics extends React.Component {
|
|||||||
|
|
||||||
if (this.state.canvas_url) {
|
if (this.state.canvas_url) {
|
||||||
if (line.words === "♪" || line.words === "♫" || line.words === " " || line.words === "") {
|
if (line.words === "♪" || line.words === "♫" || line.words === " " || line.words === "") {
|
||||||
|
//console.log(`[SyncLyrics] Toogling cinematic mode on because line is empty`)
|
||||||
|
|
||||||
this.toogleCinematicMode(true)
|
this.toogleCinematicMode(true)
|
||||||
} else {
|
} else {
|
||||||
|
//console.log(`[SyncLyrics] Toogling cinematic mode off because line is not empty`)
|
||||||
|
|
||||||
|
this.toogleCinematicMode(false)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.state.classnames["cinematic-mode"] === true) {
|
||||||
this.toogleCinematicMode(false)
|
this.toogleCinematicMode(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -587,14 +696,10 @@ export default class SyncLyrics extends React.Component {
|
|||||||
"lyrics_viewer",
|
"lyrics_viewer",
|
||||||
{
|
{
|
||||||
["text_dark"]: this.state.colorAnalysis?.isDark ?? false,
|
["text_dark"]: this.state.colorAnalysis?.isDark ?? false,
|
||||||
...this.state.classnames.map((classname) => {
|
...Object.entries(this.state.classnames).reduce((acc, [key, value]) => {
|
||||||
return {
|
return {
|
||||||
[classname.name]: classname.enabled,
|
...acc,
|
||||||
}
|
[key]: value,
|
||||||
}).reduce((a, b) => {
|
|
||||||
return {
|
|
||||||
...a,
|
|
||||||
...b,
|
|
||||||
}
|
}
|
||||||
}, {}),
|
}, {}),
|
||||||
},
|
},
|
||||||
@ -628,7 +733,7 @@ export default class SyncLyrics extends React.Component {
|
|||||||
className="lyrics_viewer_thumbnail"
|
className="lyrics_viewer_thumbnail"
|
||||||
>
|
>
|
||||||
<Image
|
<Image
|
||||||
src={this.state.currentManifest?.thumbnail}
|
src={this.state.currentManifest?.thumbnail ?? "/assets/no_song.png"}
|
||||||
ref={this.thumbnailRef}
|
ref={this.thumbnailRef}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
@enabled-video-canvas-opacity: 0.4;
|
@enabled-video-canvas-opacity: 0.4;
|
||||||
|
// in px
|
||||||
|
@cover-width: 150px;
|
||||||
|
@left-panel-width: 300px;
|
||||||
|
|
||||||
.lyrics_viewer {
|
.lyrics_viewer {
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -66,10 +69,24 @@
|
|||||||
|
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
|
|
||||||
gap: 50px;
|
gap: 0;
|
||||||
|
|
||||||
|
padding: 20px 40px;
|
||||||
|
|
||||||
|
.player_controller_left {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.player_controller_cover {
|
.player_controller_cover {
|
||||||
width: 0px;
|
width: 0px;
|
||||||
|
|
||||||
|
min-width: 0px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
min-width: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.player_controller_info {
|
.player_controller_info {
|
||||||
@ -87,7 +104,7 @@
|
|||||||
-webkit-backdrop-filter: blur(0px)
|
-webkit-backdrop-filter: blur(0px)
|
||||||
}
|
}
|
||||||
|
|
||||||
.lyrics_viewer_background {
|
.lyrics_viewer_video_canvas {
|
||||||
video {
|
video {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@ -264,13 +281,18 @@
|
|||||||
|
|
||||||
transition: all 150ms ease-in-out;
|
transition: all 150ms ease-in-out;
|
||||||
|
|
||||||
|
.marquee-container {
|
||||||
|
gap: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
.player_controller {
|
.player_controller {
|
||||||
|
box-sizing: border-box;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
width: 25vw;
|
width: 100%;
|
||||||
|
|
||||||
min-width: 350px;
|
min-width: 350px;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
@ -299,7 +321,7 @@
|
|||||||
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&.player_controller--hovering {
|
&:hover {
|
||||||
.player_controller_controls {
|
.player_controller_controls {
|
||||||
height: 8vh;
|
height: 8vh;
|
||||||
max-height: 100px;
|
max-height: 100px;
|
||||||
@ -326,7 +348,10 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
width: 10vw;
|
width: @cover-width;
|
||||||
|
min-width: @cover-width;
|
||||||
|
max-width: @cover-width;
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
@ -340,6 +365,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.player_controller_left {
|
.player_controller_left {
|
||||||
|
flex: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
@ -347,6 +373,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: @left-panel-width;
|
||||||
|
|
||||||
transition: all 150ms ease-in-out;
|
transition: all 150ms ease-in-out;
|
||||||
|
|
||||||
@ -354,7 +381,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
align-items: flex-start;
|
//align-items: flex-start;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|
||||||
@ -364,12 +393,45 @@
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
color: var(--background-color-contrast)
|
width: 100%;
|
||||||
|
|
||||||
|
color: var(--background-color-contrast);
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.player_controller_info_title_text {
|
||||||
|
transition: all 150ms ease-in-out;
|
||||||
|
|
||||||
|
width: 90%;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
// do not wrap text
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.overflown {
|
||||||
|
opacity: 0;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.player_controller_info_artist {
|
.player_controller_info_artist {
|
||||||
font-size: 0.8rem;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
gap: 7px;
|
||||||
|
|
||||||
|
font-size: 0.6rem;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -385,6 +447,8 @@
|
|||||||
|
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
height: 0px;
|
height: 0px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user