فهرست منبع

feat: client list

Fela Maslen 5 سال پیش
والد
کامیت
2e453aad29

+ 85 - 0
gmus-web/src/components/ui/mobile/clients.tsx

@@ -0,0 +1,85 @@
+import { rem } from 'polished';
+import React, { useCallback, useContext, useMemo } from 'react';
+import styled from 'styled-components';
+import { masterSet } from '../../../actions';
+
+import { DispatchContext, StateContext } from '../../../context/state';
+import { Member } from '../../../types';
+
+const Container = styled.ul`
+  flex: 1;
+  list-style: none;
+  margin: ${rem(8)};
+  min-width: 60%;
+  padding: 0;
+`;
+
+type ClientProps = {
+  isMaster: boolean;
+  isUs: boolean;
+  isPaused: boolean;
+};
+
+const Client = styled.li<ClientProps>`
+  align-items: center;
+  background: ${({ isMaster }): string => (isMaster ? 'white' : '#ececec')};
+  border-radius: ${rem(4)};
+  display: flex;
+  height: ${rem(32)};
+  justify-content: center;
+  margin: 0 0 ${rem(4)} 0;
+  padding: 0 ${rem(16)};
+
+  button {
+    appearance: none;
+    background: none;
+    border: none;
+    font-style: inherit;
+    font-weight: inherit;
+    height: 100%;
+    outline: none;
+    width: 100%;
+  }
+`;
+
+const ClientMeta = styled.div`
+  flex: 0 0 ${rem(32)};
+  white-space: nowrap;
+`;
+
+export const ClientList: React.FC = () => {
+  const state = useContext(StateContext);
+  const dispatch = useContext(DispatchContext);
+
+  const onSwitchClient = useCallback(
+    (client: string) => {
+      dispatch(masterSet(client));
+    },
+    [dispatch],
+  );
+
+  const sortedClientList = useMemo<Member[]>(
+    () => state.clientList.slice().sort((a, b) => (a.name < b.name ? -1 : 1)),
+    [state.clientList],
+  );
+
+  return (
+    <Container>
+      {sortedClientList.map(({ name }) => (
+        <Client
+          key={name}
+          isMaster={name === state.player.master}
+          isUs={name === state.myClientName}
+          isPaused={!state.player.playing}
+          onClick={(): void => onSwitchClient(name)}
+        >
+          <button onClick={(): void => onSwitchClient(name)}>{name}</button>
+          <ClientMeta>
+            {name === state.player.master && (state.player.playing ? '🔊' : '🔈')}
+            {name === state.myClientName ? '🏠' : '📶'}
+          </ClientMeta>
+        </Client>
+      ))}
+    </Container>
+  );
+};

+ 9 - 10
gmus-web/src/components/ui/mobile/info.tsx

@@ -12,7 +12,6 @@ export type Props = {
 };
 
 const Wrapper = styled.div`
-  flex: 1;
   width: 100%;
 `;
 
@@ -33,18 +32,19 @@ const Title = styled.span`
   margin-bottom: ${rem(4)};
 `;
 
-const Meta = styled.span``;
+const Meta = styled.span`
+  box-sizing: border-box;
+  padding: 0 ${rem(4)};
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  width: 100%;
+`;
 const Artist = styled.span``;
 const Album = styled.span``;
 
-const Master = styled.div`
-  font-size: ${rem(13)};
-  font-style: italic;
-  margin: ${rem(4)} 0;
-`;
-
 const Dash = styled.span`
-  margin: 0 ${rem(12)};
+  margin: 0 ${rem(8)};
 `;
 
 const Seeker = styled.div`
@@ -116,7 +116,6 @@ export const SongInfo: React.FC<Props> = ({ song, player, onSeek }) => {
               <Dash>-</Dash>
               <Album>{song.album || 'Unknown Album'}</Album>
             </Meta>
-            <Master>Playing on {player.master || '<unknown>'}</Master>
             <Seeker>
               <Time>{formatTime(player.currentTime)}</Time>
               <Gutter ref={gutter} onTouchEnd={seekToTouch}>

+ 1 - 1
gmus-web/src/components/ui/mobile/wrapper.styles.ts

@@ -12,5 +12,5 @@ export const Container = styled.div`
   position: absolute;
   right: 0;
   top: 0;
-  top: 0;
+  width: 100%;
 `;

+ 2 - 0
gmus-web/src/components/ui/mobile/wrapper.tsx

@@ -5,6 +5,7 @@ import { DispatchContext, StateContext } from '../../../context/state';
 import { Logo } from '../../logo';
 import { UIProviderComponent } from '../types';
 import { Buttons } from './buttons';
+import { ClientList } from './clients';
 import { SongInfo } from './info';
 
 import * as Styled from './wrapper.styles';
@@ -20,6 +21,7 @@ export const MobileUIProvider: UIProviderComponent = ({ prevSong, nextSong, curr
     <Styled.Container>
       <Logo size={128} />
       <SongInfo song={currentSong} player={state.player} onSeek={onSeek} />
+      <ClientList />
       <Buttons
         playing={state.player.playing}
         onPrev={prevSong}