Skip to content

Commit

Permalink
feat: add collapsible setting for sidebar panels
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelmaddock committed Jul 7, 2020
1 parent 15a6ba7 commit 881e5cf
Show file tree
Hide file tree
Showing 10 changed files with 93 additions and 84 deletions.
43 changes: 0 additions & 43 deletions packages/metastream-app/src/components/lobby/ListOverlay.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,51 +3,8 @@
flex-direction: column;
}

.header {
display: flex;
flex-direction: row;
align-items: center;
padding: 10px;
flex-wrap: nowrap;
}

.title {
composes: single-line from '~styles/text.css';
font-weight: bold;
text-transform: uppercase;
letter-spacing: 2px;
margin-right: 5px;
text-overflow: clip;
}

.tagline {
border: 1px solid rgba(255, 255, 255, 0.22);
padding: 2px 4px;
font-size: 12px;
min-width: 18px;
text-align: center;
}

.actions {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
margin-left: auto;
}

.actions > *:not(:last-child) {
margin-right: 0.5rem;
}

.list {
composes: scroller from '~styles/layout.css';
overflow-y: auto;
flex-grow: 1;
}

.placeholder {
padding: 0.5rem 1rem;
text-align: center;
mix-blend-mode: overlay;
}
11 changes: 3 additions & 8 deletions packages/metastream-app/src/components/lobby/ListOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ interface IProps<T> {
title?: string
tagline?: string
action?: ReactNode
placeholder?: ReactNode
renderMenuOptions: (item: T, onClose: Function) => ReactNode
onTitleClick?: React.MouseEventHandler<HTMLButtonElement>
}

interface IState<T> {
Expand All @@ -36,14 +36,9 @@ export class ListOverlay<T = any> extends Component<IProps<T>, IState<T>> {
title={this.props.title}
tagline={this.props.tagline}
action={this.props.action}
onTitleClick={this.props.onTitleClick}
/>
<div className={styles.list}>
{React.Children.count(this.props.children) > 0 ? (
this.props.children
) : (
<div className={styles.placeholder}>{this.props.placeholder}</div>
)}
</div>
<div className={styles.list}>{this.props.children}</div>
{this.renderMenu()}
</div>
)
Expand Down
42 changes: 26 additions & 16 deletions packages/metastream-app/src/components/lobby/MediaList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import cx from 'classnames'

import { IAppState } from '../../reducers'
import { IMediaItem } from '../../lobby/reducers/mediaPlayer'
Expand All @@ -14,7 +15,7 @@ import {
server_requestToggleQueueLock
} from '../../lobby/actions/mediaPlayer'

import { HighlightButton, IconButton } from '../common/button'
import { IconButton } from '../common/button'
import { ListOverlay } from './ListOverlay'

import MenuItem from '@material-ui/core/MenuItem'
Expand All @@ -23,11 +24,11 @@ import { localUser } from 'network'
import { copyMediaLink, openMediaInBrowser } from '../../media/utils'
import { withNamespaces, WithNamespaces } from 'react-i18next'
import { sendMediaRequest } from 'lobby/actions/media-request'
import { setLobbyModal } from 'actions/ui'
import { LobbyModal } from 'reducers/ui'
import { setSetting } from 'actions/settings'

interface IProps {
className?: string
collapsible?: boolean
onShowInfo(media?: IMediaItem): void
onOpenMediaBrowser(): void
}
Expand All @@ -37,13 +38,15 @@ interface IConnectedProps {
currentMedia?: IMediaItem
mediaQueue: IMediaItem[]
mediaQueueLocked: boolean
collapsed: boolean
}

interface DispatchProps {
moveToTop(mediaId: string): void
sendMediaRequest(url: string): void
deleteMedia(mediaId: string): void
toggleQueueLock(): void
toggleCollapsed(): void
}

type Props = IProps & IConnectedProps & DispatchProps & WithNamespaces
Expand All @@ -62,7 +65,7 @@ class _MediaList extends Component<Props> {
<ListOverlay
ref={(e: any) => (this.listOverlay = e)}
id="mediaqueue"
className={this.props.className}
className={cx(this.props.className, { collapsed: this.props.collapsed })}
title={t('nextUp')}
tagline={this.props.mediaQueue.length ? `${this.props.mediaQueue.length}` : undefined}
action={
Expand All @@ -71,6 +74,7 @@ class _MediaList extends Component<Props> {
{this.renderAddMedia()}
</>
}
onTitleClick={this.props.collapsible ? this.props.toggleCollapsed : undefined}
renderMenuOptions={(media: IMediaItem, close) => {
let items = [
{
Expand Down Expand Up @@ -125,17 +129,19 @@ class _MediaList extends Component<Props> {
))
}}
>
{this.mediaList.map(media => {
return (
<MediaItem
key={media.id}
media={media}
onClickMenu={e => {
this.listOverlay!.onSelect(e, media)
}}
/>
)
})}
{this.props.collapsible && this.props.collapsed
? null
: this.mediaList.map(media => {
return (
<MediaItem
key={media.id}
media={media}
onClickMenu={e => {
this.listOverlay!.onSelect(e, media)
}}
/>
)
})}
</ListOverlay>
)
}
Expand Down Expand Up @@ -179,7 +185,8 @@ export const MediaList = withNamespaces()(
hasPlaybackPermissions: hasPlaybackPermissions(state, localUser()),
currentMedia: getCurrentMedia(state),
mediaQueue: getMediaQueue(state),
mediaQueueLocked: state.mediaPlayer.queueLocked
mediaQueueLocked: state.mediaPlayer.queueLocked,
collapsed: !!state.settings.mediaListCollapsed
}),
(dispatch): DispatchProps => ({
moveToTop(mediaId) {
Expand All @@ -196,6 +203,9 @@ export const MediaList = withNamespaces()(
},
toggleQueueLock() {
dispatch(server_requestToggleQueueLock() as any)
},
toggleCollapsed() {
dispatch(setSetting('mediaListCollapsed', collapsed => !collapsed))
}
})
)(_MediaList)
Expand Down
21 changes: 12 additions & 9 deletions packages/metastream-app/src/components/lobby/PanelHeader.css
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
.header {
display: flex;
flex-direction: row;
align-items: center;
composes: row-center from '~styles/layout.css';
}

.titleContainer,
.actions {
padding: 10px;
flex-wrap: nowrap;
}

.titleContainer {
composes: row-center from '~styles/layout.css';
flex-grow: 1;
padding-right: 0;
}

.title {
Expand All @@ -24,11 +31,7 @@
}

.actions {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
margin-left: auto;
composes: row-center from '~styles/layout.css';
}

.actions > *:not(:last-child) {
Expand Down
18 changes: 15 additions & 3 deletions packages/metastream-app/src/components/lobby/PanelHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,25 @@ interface Props {
title?: string
tagline?: string
action?: React.ReactNode
onTitleClick?: React.MouseEventHandler<HTMLButtonElement>
}

export const PanelHeader: React.SFC<Props> = ({ title, tagline, action }) => {
return (
<header className={styles.header}>
export const PanelHeader: React.SFC<Props> = ({ title, tagline, action, onTitleClick }) => {
const clickable = typeof onTitleClick === 'function'
const titleContainer = React.createElement(
clickable ? 'button' : 'div',
clickable
? { className: styles.titleContainer, type: 'button', onClick: onTitleClick }
: { className: styles.titleContainer },
<>
<h2 className={styles.title}>{title}</h2>
{tagline && <span className={styles.tagline}>{tagline}</span>}
</>
)

return (
<header className={styles.header}>
{titleContainer}
<div className={styles.actions}>{action}</div>
</header>
)
Expand Down
24 changes: 21 additions & 3 deletions packages/metastream-app/src/components/lobby/UserList.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import cx from 'classnames'

import { IAppState } from '../../reducers'
import { IUsersState, IUser, UserRole, IUserInvite } from '../../lobby/reducers/users'
Expand All @@ -8,7 +9,7 @@ import { getMaxUsers } from '../../lobby/reducers/session'
import { server_kickUser, server_toggleUserRole, answerUserInvite } from '../../lobby/actions/users'

import MenuItem from '@material-ui/core/MenuItem'
import { HighlightButton, IconButton } from '../common/button'
import { IconButton } from '../common/button'
import { ListOverlay } from './ListOverlay'
import { UserItem, ConnectedUserItem } from './UserItem'
import { IReactReduxProps } from 'types/redux-thunk'
Expand All @@ -17,9 +18,11 @@ import { localUserId } from '../../network'
import { assetUrl } from 'utils/appUrl'
import { SessionMode } from 'reducers/settings'
import { withNamespaces, WithNamespaces } from 'react-i18next'
import { setSetting } from 'actions/settings'

interface IProps {
className?: string
collapsible?: boolean
onInvite(): void
}

Expand All @@ -29,6 +32,7 @@ interface IConnectedProps {
isHost: boolean
isAdmin: boolean
sessionMode: SessionMode
collapsed: boolean
}

interface IState {
Expand Down Expand Up @@ -83,11 +87,20 @@ class _UserList extends Component<Props> {
<ListOverlay
ref={(e: any) => (this.listOverlay = e)}
id="userlist"
className={this.props.className}
className={cx(this.props.className, {
collapsed: this.props.collapsed
})}
title={t('users')}
tagline={this.userSlots}
action={this.renderActions()}
renderMenuOptions={this.renderMenuOptions}
onTitleClick={
this.props.collapsible
? () => {
this.props.dispatch(setSetting('userListCollapsed', collapsed => !collapsed))
}
: undefined
}
>
{this.props.users.invites.map(this.renderInvite)}
{this.state.sortedUsers.map(this.renderUser)}
Expand Down Expand Up @@ -118,6 +131,10 @@ class _UserList extends Component<Props> {
private renderUser = (user: IUser) => {
const requestApproval = user.pending && this.props.isAdmin

if (!requestApproval && this.props.collapsible && this.props.collapsed) {
return
}

return (
<ConnectedUserItem
key={user.id}
Expand Down Expand Up @@ -193,7 +210,8 @@ export const UserList = withNamespaces()(
users: state.users,
isAdmin: isAdmin(state),
isHost: isHost(state),
sessionMode: state.settings.sessionMode
sessionMode: state.settings.sessionMode,
collapsed: !!state.settings.userListCollapsed
}
}
)(_UserList)
Expand Down
7 changes: 5 additions & 2 deletions packages/metastream-app/src/components/sidebar/Sidebar.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,11 @@

.list {
flex: 0 1 auto;
height: 14rem;
min-height: 8rem;
max-height: 24%;
box-shadow: inset 0 -1px 0 0 var(--color-transparent-light-10);
}

.list:not(:global(.collapsed)) {
height: 14rem;
min-height: 8rem;
}
2 changes: 2 additions & 0 deletions packages/metastream-app/src/components/sidebar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const Sidebar: React.SFC<Props> = ({ className, popup }) => {
dispatchExtensionMessage('metastream-focus')
dispatch(setLobbyModal(LobbyModal.SessionSettings))
}}
collapsible
/>
<MediaList
className={styles.list}
Expand All @@ -38,6 +39,7 @@ export const Sidebar: React.SFC<Props> = ({ className, popup }) => {
dispatchExtensionMessage('metastream-focus')
dispatch(setLobbyModal(LobbyModal.MediaInfo))
}}
collapsible
/>
<PanelHeader title={t('chat')} action={popup ? null : <ChatLayoutButton />} />
<Chat className={styles.chat} showDockOption={false} />
Expand Down
2 changes: 2 additions & 0 deletions packages/metastream-app/src/reducers/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ export interface ISettingsState {
language: string
chatLocation: ChatLocation
chatTimestamp: boolean
userListCollapsed?: boolean
mediaListCollapsed?: boolean
autoFullscreen: boolean
theaterMode: boolean
safeBrowse: boolean
Expand Down
7 changes: 7 additions & 0 deletions packages/metastream-app/src/styles/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@
align-items: center;
}

.row-center {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
}

/*
Custom Scrollbar
*/
Expand Down

0 comments on commit 881e5cf

Please sign in to comment.