Dynamic realtime profile ReadMe linked with spotify
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
3.9 KiB

  1. import React from "react";
  2. import ReadmeImg from "./ReadmeImg";
  3. import Text from "./Text";
  4. export interface Props {
  5. cover?: string;
  6. track: string;
  7. artist: string;
  8. progress: number;
  9. duration: number;
  10. isPlaying: boolean;
  11. }
  12. export const Player: React.FC<Props> = ({
  13. cover,
  14. track,
  15. artist,
  16. progress,
  17. duration,
  18. isPlaying,
  19. }) => {
  20. return (
  21. <ReadmeImg width="256" height="64">
  22. <style>
  23. {`
  24. .paused {
  25. animation-play-state: paused !important;
  26. background: #e1e4e8 !important;
  27. }
  28. img:not([src]) {
  29. content: url("data:image/gif;base64,R0lGODlhAQABAPAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==");
  30. border-radius: 6px;
  31. background: #FFF;
  32. border: 1px solid #e1e4e8;
  33. }
  34. p {
  35. display: block;
  36. opacity: 0;
  37. }
  38. .progress-bar {
  39. position: relative;
  40. width: 100%;
  41. height: 4px;
  42. margin: -1px;
  43. border: 1px solid #e1e4e8;
  44. border-radius: 4px;
  45. overflow: hidden;
  46. padding: 2px;
  47. z-index: 0;
  48. }
  49. #progress {
  50. position: absolute;
  51. top: -1px;
  52. left: 0;
  53. width: 100%;
  54. height: 6px;
  55. transform-origin: left center;
  56. background-color: #24292e;
  57. animation: progress ${duration}ms linear;
  58. animation-delay: -${progress}ms;
  59. }
  60. .progress-bar,
  61. #track,
  62. #artist,
  63. #cover {
  64. opacity: 0;
  65. animation: appear 300ms ease-out forwards;
  66. }
  67. #track {
  68. animation-delay: 400ms;
  69. }
  70. #artist {
  71. animation-delay: 500ms;
  72. }
  73. .progress-bar {
  74. animation-delay: 550ms;
  75. margin-top: 4px;
  76. }
  77. #cover {
  78. animation-name: cover-appear;
  79. animation-delay: 300ms;
  80. box-shadow: 0 1px 3px rgba(0,0,0,0.1), 0 3px 10px rgba(0,0,0,0.05);
  81. }
  82. #cover:not([src]) {
  83. box-shadow: none;
  84. }
  85. @keyframes cover-appear {
  86. from {
  87. opacity: 0;
  88. transform: scale(0.8);
  89. }
  90. to {
  91. opacity: 1;
  92. transform: scale(1);
  93. }
  94. }
  95. @keyframes appear {
  96. from {
  97. opacity: 0;
  98. transform: translateX(-8px);
  99. }
  100. to {
  101. opacity: 1;
  102. transform: translateX(0);
  103. }
  104. }
  105. @keyframes progress {
  106. from {
  107. transform: scaleX(0)
  108. }
  109. to {
  110. transform: scaleX(1)
  111. }
  112. }
  113. `}
  114. </style>
  115. <div
  116. className={isPlaying ? "disabled" : ""}
  117. style={{
  118. display: "flex",
  119. alignItems: "center",
  120. paddingTop: 8,
  121. paddingLeft: 4,
  122. }}
  123. >
  124. <img id="cover" src={cover ?? null} width="48" height="48" />
  125. <div
  126. style={{
  127. display: "flex",
  128. flex: 1,
  129. flexDirection: "column",
  130. marginTop: -4,
  131. marginLeft: 8,
  132. }}
  133. >
  134. <Text id="track" weight="bold">
  135. {`${track ?? ""} `.trim()}
  136. </Text>
  137. <Text id="artist" color={!track ? "gray" : undefined}>
  138. {artist || "Nothing playing..."}
  139. </Text>
  140. {track && (
  141. <div className="progress-bar">
  142. <div id="progress" className={!isPlaying ? "paused" : ""} />
  143. </div>
  144. )}
  145. </div>
  146. </div>
  147. </ReadmeImg>
  148. );
  149. };