Bläddra i källkod

[web] Queue add/remove, svg refactor

Innokentiy Enikeev 4 år sedan
förälder
incheckning
cf79454761

+ 2 - 2
web/src/components/Album/Album.js

@@ -29,10 +29,10 @@ export default function Album({album, showArtist, showType, dispatch}) {
         <span className="Album-genre">{album.genre}</span>
         <div className="Album-actions">
           <button onClick={(e)=>fetchTracks(album.id, 'ALBUM_PLAY', dispatch)}>
-            <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
+            <svg><use href="#control-play" /></svg>
           </button>
           <button onClick={(e)=>fetchTracks(album.id, 'ALBUM_ENQUEUE', dispatch)}>
-            <svg viewBox="0 0 24 24"><g><path d="M10 6h4v4h4v4h-4v4h-4v-4h-4v-4h4z"/></g></svg>
+            <svg><use href="#control-add" /></svg>
           </button>
         </div>
       </div>

+ 7 - 0
web/src/components/AlbumPage/AlbumPage.css

@@ -3,6 +3,13 @@
   width: 24px;
   height: 24px;
   vertical-align: bottom;
+  border: 0;
+  border-radius: 4px;
+  cursor: pointer;
+  background: var(--button-background);
+}
+.AlbumPage table button:hover {
+  background: var(--controls-button-hover-background);
 }
 
 @media screen and (max-width: 800px) {

+ 10 - 5
web/src/components/AlbumPage/AlbumPage.js

@@ -43,10 +43,10 @@ export default function AlbumPage({dispatch, scrollRef}) {
       </h1>
       <h2>{albumName}</h2>{tracks && (<div className="Album-actions">
           <button onClick={(e)=>dispatch({type:'ALBUM_PLAY', payload: {tracks, pos: 0}})}>
-            <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
+            <svg><use href="#control-play" /></svg>
           </button>
           <button onClick={(e)=>dispatch({type: 'ALBUM_ENQUEUE', payload: {tracks}})}>
-            <svg viewBox="0 0 24 24"><g><path d="M10 6h4v4h4v4h-4v4h-4v-4h-4v-4h4z"/></g></svg>
+            <svg><use href="#control-add" /></svg>
           </button>
       </div>)}
       {album && (<>
@@ -68,9 +68,14 @@ export default function AlbumPage({dispatch, scrollRef}) {
               <td>{track.title}</td>
               <td>{track.bit_rate} kbps</td>
               <td>{formatDuration(track.duration)}</td>
-              <td><button onClick={() => dispatch({type:'ALBUM_PLAY', payload: {tracks, pos: i}})}>
-                  <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
-              </button></td>
+              <td>
+                <button onClick={() => dispatch({type:'ALBUM_PLAY', payload: {tracks, pos: i}})}>
+                  <svg><use href="#control-play" /></svg>
+                </button>
+                <button onClick={(e)=>dispatch({type: 'QUEUE_ADD', payload: track})}>
+                  <svg><use href="#control-add" /></svg>
+                </button>
+              </td>
             </tr>))
           }
       </tbody></table>

+ 5 - 0
web/src/components/App/App.css

@@ -1,3 +1,8 @@
+button svg {
+  height: 100%;
+  width: 100%;
+}
+
 .App {
   --accent: #388E3C;
   --header-background: #000;

+ 3 - 1
web/src/components/App/App.js

@@ -4,6 +4,7 @@ import {storeToken, loadToken} from 'src/Api';
 import Login from '../Login';
 import Header from '../Header';
 import Player from '../Player';
+import SvgSymbols from '../SvgSymbols';
 
 function storeSettings(settings) {
   localStorage.setItem('settings', JSON.stringify(settings));
@@ -39,13 +40,14 @@ function App() {
 
   return (
     <div className="App" data-theme={settings.theme} data-layout={settings.layout} data-panel={settings.panel || 'main'}>
+      <SvgSymbols />
+      <Header settings={settings} dispatch={dispatch} />
       <div className="App-panels">
         <input id="panel-main" type="radio" name="panel" value="main" checked={settings.panel === 'main'} onChange={handleRadio(dispatch)} />
         <input id="panel-side" type="radio" name="panel" value="side" checked={settings.panel === 'side'} onChange={handleRadio(dispatch)} />
         <label htmlFor="panel-main">Browse</label>
         <label htmlFor="panel-side">Queue</label>
       </div>
-      <Header settings={settings} dispatch={dispatch} />
       <Player />
     </div>
   );

+ 5 - 5
web/src/components/Controls/Controls.js

@@ -22,21 +22,21 @@ export default function Controls({queue, error, sound, dispatch}) {
       <div className="Controls-title">{track.no && `${track.no}. `}{track.title}</div>
       <div className="Controls-buttons">
         <button disabled={queue.pos < 1} onClick={()=>dispatch({type: 'CONTROL_PREV'})}>
-          <svg viewBox="0 0 24 24"><g><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"></path></g></svg>
+          <svg><use href="#control-prev" /></svg>
         </button>
         <button disabled={queue.pos < 0}
                 onClick={()=>dispatch({type: (playing ? 'CONTROL_PAUSE' : 'CONTROL_PLAY')})}>
           {playing
-            ? <svg viewBox="0 0 24 24"><g><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></g></svg>
-            : <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
+            ? <svg><use href="#control-pause" /></svg>
+            : <svg><use href="#control-play" /></svg>
           }
         </button>
         <button disabled={sound.playStatus === Sound.status.STOPPED}
                 onClick={()=>dispatch({type: 'CONTROL_STOP'})}>
-          <svg viewBox="0 0 24 24"><g><path d="M6 6v12h12v-12z"/></g></svg>
+          <svg><use href="#control-stop" /></svg>
         </button>
         <button disabled={(queue.pos+1) >= queue.items.length} onClick={()=>dispatch({type: 'CONTROL_NEXT'})}>
-          <svg viewBox="0 0 24 24"><g><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"></path></g></svg>
+          <svg><use href="#control-next" /></svg>
         </button>
       </div>
     </footer>

+ 13 - 0
web/src/components/Player.js

@@ -67,6 +67,19 @@ function playerReducer(state, action) {
   case 'QUEUE_LOAD': {
     const queue = action.payload;
     return {...state, queue, ...playTrack(queue.items[queue.pos], Sound.status.PAUSED)}}
+  case 'QUEUE_DELETE': {
+    const idx = action.payload;
+    const pos = (idx < state.queue.pos ? state.queue.pos-1 : (idx > state.queue.pos ? state.queue.pos : -1));
+    const items = [...state.queue.items];
+    items.splice(idx, 1);
+    const queue = {items, pos};
+    storeQueue(queue);
+    return {...state, queue}}
+  case 'QUEUE_ADD': {
+    const items = state.queue.items.concat(action.payload);
+    const queue = {...state.queue, items};
+    storeQueue(queue);
+    return {...state, queue}}
   case 'SOUND_ERROR':
     return {...state, sound: NO_SOUND, metadata: NO_METADATA, error: action.payload}
   case 'SOUND_PLAYING':

+ 8 - 3
web/src/components/Queue/Queue.js

@@ -17,9 +17,14 @@ export default function Queue({queue, dispatch}) {
               <td>{track.no}</td>
               <td>{track.bit_rate} kbps</td>
               <td>{formatDuration(track.duration)}</td>
-              <td><button onClick={() => dispatch({type:'QUEUE_PLAY', payload: i})}>
-                  <svg viewBox="0 0 24 24"><g><path d="M8 5v14l11-7z"/></g></svg>
-              </button></td>
+              <td>
+                <button onClick={() => dispatch({type:'QUEUE_PLAY', payload: i})}>
+                  <svg><use href="#control-play" /></svg>
+                </button>
+                <button onClick={() => dispatch({type:'QUEUE_DELETE', payload: i})}>
+                  <svg><use href="#control-stop" /></svg>
+                </button>
+              </td>
             </tr>))}
       </tbody></table>
     </aside>

+ 24 - 0
web/src/components/SvgSymbols.js

@@ -0,0 +1,24 @@
+export default SvgSymbols = () => (
+  <>
+    <svg style={{display: "none"}}>
+      <symbol id="control-prev" viewBox="0 0 24 24">
+        <path d="M6 6h2v12H6zm3.5 6l8.5 6V6z" />
+      </symbol>
+      <symbol id="control-pause" viewBox="0 0 24 24">
+        <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
+      </symbol>
+      <symbol id="control-play" viewBox="0 0 24 24">
+        <path d="M8 5v14l11-7z" />
+      </symbol>
+      <symbol id="control-stop" viewBox="0 0 24 24">
+        <path d="M6 6v12h12v-12z" />
+      </symbol>
+      <symbol id="control-next" viewBox="0 0 24 24">
+        <path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z" />
+      </symbol>
+      <symbol id="control-add" viewBox="0 0 24 24">
+        <path d="M10 6h4v4h4v4h-4v4h-4v-4h-4v-4h4z" />
+      </symbol>
+    </svg>
+  </>
+)