CoverGridItem.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. import React, { Component } from 'react';
  2. import '../css/CoverGridItem.scss'
  3. import LibraryIndicator from './LibraryIndicator'
  4. import Loader from '../assets/loading-dots2.png'
  5. import { connect } from 'react-redux'
  6. import PropTypes from 'prop-types'
  7. import { loadDetailsFromFile, loadDetailsFromKey } from '../actions/detailsActions'
  8. import { setScrollTop } from '../actions/songListActions'
  9. const getColors = window.require('get-image-colors')
  10. function Difficulties(props) {
  11. let difficulties = props.difficulties
  12. if (!difficulties) return null
  13. let badges = []
  14. if(difficulties.easy) {
  15. badges.push({
  16. text: 'Easy',
  17. backgroundColor: 'teal',
  18. color: 'white'
  19. })
  20. }
  21. if(difficulties.normal) {
  22. badges.push({
  23. text: 'Normal',
  24. backgroundColor: 'green',
  25. color: 'white'
  26. })
  27. }
  28. if(difficulties.hard) {
  29. badges.push({
  30. text: 'Hard',
  31. backgroundColor: 'orange',
  32. color: 'white'
  33. })
  34. }
  35. if(difficulties.expert) {
  36. badges.push({
  37. text: 'Expert',
  38. backgroundColor: 'darkred',
  39. color: 'white'
  40. })
  41. }
  42. if(difficulties.expertPlus) {
  43. badges.push({
  44. text: 'Expert+',
  45. backgroundColor: 'purple',
  46. color: 'white'
  47. })
  48. }
  49. return badges.map((badge, i) => {
  50. return <div key={ i } className='dot' title={ badge.text } style={ { backgroundColor: badge.backgroundColor, border: `1px solid ${props.textColor}` } }></div>
  51. })
  52. }
  53. function VoteRatio(props){
  54. var total = props.up + props.down;
  55. if(props.up > props.down){
  56. return <span>👍{(props.up / total * 100).toFixed(1) }/<CompactNumber value={ props.up + props.down }/></span>
  57. }else if (props.up < props.down){
  58. return <span>👎{(props.down / total * 100).toFixed(1)}/<CompactNumber value={ props.up + props.down }/></span>
  59. }else{
  60. return <span></span>
  61. }
  62. }
  63. function CompactNumber(props){
  64. var num = props.value, uni = 0;
  65. if( num >= 100 && num < 1000) return <span>{(num / 100).toFixed(0)}H</span>
  66. if( num >= 1000 && num < 10000) return <span>{(num / 1000).toFixed(0)}K</span>
  67. if( num >= 10000 && num < 1000000) return <span>{(num / 10000).toFixed(0)}万</span>
  68. if( num >= 1000000 && num < 10000000) return <span>{(num / 1000000).toFixed(0)}M</span>
  69. return <span>{num}</span>
  70. }
  71. class CoverGridItem extends Component {
  72. constructor() {
  73. super()
  74. this.state = {
  75. bgc: 'rgba(128, 128, 128)',
  76. textColor: 'black'
  77. }
  78. }
  79. componentWillReceiveProps(props) {
  80. getColors(this.props.imageSource.startsWith('file://') ? this.props.imageSource.substring(7, this.props.imageSource.length) : `https://beatsaver.com/${ this.props.imageSource }`)
  81. .then(colors => {
  82. this.setState({
  83. bgc: `rgb(${colors[0].rgb()[0]},${colors[0].rgb()[1]},${colors[0].rgb()[2]})`,
  84. textColor: (colors[0].rgb()[0] * 0.299 + colors[0].rgb()[1] * 0.587 + colors[0].rgb()[2] * 0.114) > 186 ? 'black' : 'white'
  85. })
  86. })
  87. .catch(() => {})
  88. }
  89. componentDidMount() {
  90. console.log( encodeURI(this.props.imageSource) )
  91. if(!this.props.imageSource) return
  92. getColors(this.props.imageSource.startsWith('file://') ? this.props.imageSource.substring(7, this.props.imageSource.length) : `https://beatsaver.com/${ this.props.imageSource }`)
  93. .then(colors => {
  94. this.setState({
  95. bgc: `rgb(${colors[0].rgb()[0]},${colors[0].rgb()[1]},${colors[0].rgb()[2]})`,
  96. textColor: (colors[0].rgb()[0] * 0.299 + colors[0].rgb()[1] * 0.587 + colors[0].rgb()[2] * 0.114) > 186 ? 'black' : 'white'
  97. })
  98. })
  99. .catch(() => {})
  100. }
  101. render() {
  102. if(this.props.loading) {
  103. return (
  104. <div className="cover-grid-item loading">
  105. <img className="cover-image" src={ Loader } alt={ this.props.key } />
  106. </div>
  107. )
  108. } else {
  109. return (
  110. <div key={ this.props.key } className='cover-grid-item' onClick={ () => { this.props.setScrollTop(document.getElementById('cover-grid-container').scrollTop); if(this.props.file) { this.props.loadDetailsFromFile(this.props.file) } else { this.props.loadDetailsFromKey(this.props.songKey) } } }>
  111. <img className="cover-image" src={ this.props.imageSource.startsWith('file://') ? this.props.imageSource : `https://beatsaver.com${ this.props.imageSource }` } alt=""/>
  112. {(!!this.props.file || this.props.downloadedSongs.some(dsong => dsong.hash === this.props.hash)) ? <LibraryIndicator /> : null}
  113. <div style={ { backgroundColor: this.state.bgc, color: this.state.textColor } } className="cover-grid-info-tab">
  114. <div className="cover-grid-title">{this.props.title}</div>
  115. <div className="cover-grid-artist">{this.props.artist}</div>
  116. <div>
  117. {/* 👍{ this.props.upvotes } 👎{ this.props.downvotes } */}
  118. <VoteRatio up={ this.props.upvotes } down={ this.props.downvotes } />
  119. 🏁{ ( 100 * this.props.plays / this.props.downloads).toFixed(1) }/<CompactNumber value={ this.props.downloads }/>
  120. </div>
  121. <div className="dots">
  122. <Difficulties difficulties={ this.props.difficulties } textColor={ this.state.textColor } />
  123. </div>
  124. </div>
  125. </div>
  126. )
  127. }
  128. }
  129. }
  130. CoverGridItem.propTypes = ({
  131. loadDetailsFromFile: PropTypes.func.isRequired,
  132. loadDetailsFromKey: PropTypes.func.isRequired
  133. })
  134. let mapStateToProps = state => ({
  135. downloadedSongs: state.songs.downloadedSongs
  136. })
  137. export default connect(mapStateToProps, { loadDetailsFromFile, loadDetailsFromKey, setScrollTop })(CoverGridItem)