feat(ui): player controls redesign

This commit is contained in:
sylenien 2022-05-25 17:04:30 +02:00 committed by Delirium
parent 35d258aa8c
commit dbae4fe353
13 changed files with 258 additions and 434 deletions

View file

@ -20,4 +20,4 @@
pointer-events: none;
height: 2px;
z-index: 1;
}
}

View file

@ -3,22 +3,33 @@ import cn from 'classnames';
import { Icon } from 'UI';
import stl from './controlButton.module.css';
const ControlButton = ({ label, icon, disabled=false, onClick, count = 0, hasErrors=false, active=false }) => (
const ControlButton = ({
label,
icon = '',
disabled=false,
onClick,
count = 0,
hasErrors=false,
active=false,
size = 20,
noLabel,
labelClassName,
containerClassName,
noIcon,
}) => (
<button
className={ cn(stl.controlButton, { [stl.disabled]: disabled, [stl.active]: active }) }
className={ cn(stl.controlButton, { [stl.disabled]: disabled, [stl.active]: active }, "relative", containerClassName) }
onClick={ onClick }
id={"control-button-" + label.toLowerCase()}
disabled={disabled}
>
<div className="relative">
{ count > 0 && <div className={ stl.countLabel }>{ count }</div>}
{ hasErrors && <div className={ stl.errorSymbol } /> }
<Icon name={ icon } size="20" color="gray-dark"/>
</div>
<span className={ stl.label }>{ label }</span>
{!noIcon && <Icon name={ icon } size={size} color="gray-dark"/>}
{!noLabel && <span className={ cn(stl.label, labelClassName) }>{ label }</span>}
</button>
);
ControlButton.displayName = 'ControlButton';
export default ControlButton;
export default ControlButton;

View file

@ -50,15 +50,15 @@ function getStorageIconName(type) {
function getStorageName(type) {
switch(type) {
case STORAGE_TYPES.REDUX:
return "Redux";
return "REDUX";
case STORAGE_TYPES.MOBX:
return "MobX";
return "MOBX";
case STORAGE_TYPES.VUEX:
return "Vuex";
return "VUEX";
case STORAGE_TYPES.NGRX:
return "NgRx";
return "NGRX";
case STORAGE_TYPES.NONE:
return "State";
return "STATE";
}
}
@ -204,25 +204,32 @@ export default class Controls extends React.Component {
let label;
let icon;
if (completed) {
label = 'Replay';
icon = 'redo';
} else if (playing) {
label = 'Pause';
icon = 'pause';
icon = 'play-fill-new';
} else {
label = 'Play';
icon = 'play';
icon = 'pause-fill';
}
return (
<ControlButton
disabled={ disabled }
onClick={ this.props.togglePlay }
icon={ icon }
label={ label }
/>
);
<div
onClick={this.props.togglePlay}
className="mr-2 hover-main color-gray-medium cursor-pointer rounded hover:bg-gray-light-shade"
>
<Icon name={icon} size="36" color="inherit" />
</div>
)
}
controlIcon = (icon, size, action, isBackwards, additionalClasses) =>
<div
onClick={ action }
className={cn("py-1 px-2 color-gray-medium hover-main cursor-pointer", additionalClasses)}
style={{ transform: isBackwards ? 'rotate(180deg)' : '' }}
>
<Icon name={icon} size={size} color="inherit" />
</div>
render() {
const {
bottomBlock,
@ -267,21 +274,42 @@ export default class Controls extends React.Component {
<div className={ styles.buttons } data-is-live={ live }>
<div>
{ !live && (
<div className={ styles.buttonsLeft }>
<div className="flex items-center">
{ this.renderPlayBtn() }
<ControlButton
onClick={ this.backTenSeconds }
disabled={ disabled }
label="Back"
icon="replay-10"
/>
{/* <ControlButton
disabled={ disabled }
onClick={ this.props.toggleSkipToIssue }
active={ skipToIssue }
label="Skip to Issue"
icon={skipToIssue ? 'skip-forward-fill' : 'skip-forward'}
/> */}
{ !live && (
<div className="flex items-center font-semibold">
<ReduxTime isCustom name="time" />
<span className="px-1">/</span>
<ReduxTime isCustom name="endTime" />
</div>
)}
<div className="rounded ml-4 bg-active-blue border border-active-blue-border flex items-stretch">
{this.controlIcon("skip-forward-fill", 18, this.backTenSeconds, true, 'hover:bg-active-blue-border')}
<div className='p-1 border-l border-r bg-active-blue-border border-active-blue-border'>10s</div>
{this.controlIcon("skip-forward-fill", 18, this.forthTenSeconds, false, 'hover:bg-active-blue-border')}
</div>
{!live &&
<div className='flex items-center mx-4'>
<button
className={ styles.speedButton }
onClick={ this.props.toggleSpeed }
data-disabled={ disabled }
>
<div>{ speed + 'x' }</div>
</button>
<button
className={ cn(styles.skipIntervalButton, { [styles.withCheckIcon]: skip }) }
onClick={ this.props.toggleSkip }
data-disabled={ disabled }
>
<span className={ styles.checkIcon } />
{ 'Skip Inactivity' }
</button>
</div>
}
</div>
)}
@ -294,50 +322,59 @@ export default class Controls extends React.Component {
)}
</div>
<div className={ styles.butonsRight }>
{!live &&
<React.Fragment>
<button
className={ styles.speedButton }
onClick={ this.props.toggleSpeed }
data-disabled={ disabled }
>
<div>{ speed + 'x' }</div>
</button>
<button
className={ cn(styles.skipIntervalButton, { [styles.withCheckIcon]: skip }) }
onClick={ this.props.toggleSkip }
data-disabled={ disabled }
>
<span className={ styles.checkIcon } />
{ 'Skip Inactivity' }
</button>
</React.Fragment>
}
{ !live && <div className={ styles.divider } /> }
<div className="flex items-center h-full">
{ !live && <div className={cn(styles.divider, 'h-full')} /> }
{!live && (
<ControlButton
disabled={ disabled && !inspectorMode }
active={ bottomBlock === INSPECTOR }
onClick={ toggleInspectorMode }
noIcon
labelClassName="text-base font-semibold"
label="INSPECT"
/>
)}
<ControlButton
disabled={ disabled }
onClick={ () => toggleBottomBlock(CONSOLE) }
active={ bottomBlock === CONSOLE }
label="CONSOLE"
noIcon
labelClassName="text-base font-semibold"
count={ logCount }
hasErrors={ logRedCount > 0 }
/>
{ !live &&
<ControlButton
disabled={ disabled }
onClick={ () => toggleBottomBlock(NETWORK) }
active={ bottomBlock === NETWORK }
label="Network"
// count={ redResourceCount }
label="NETWORK"
hasErrors={ resourceRedCount > 0 }
icon="wifi"
noIcon
labelClassName="text-base font-semibold"
/>
}
{ showFetch &&
{!live &&
<ControlButton
disabled={ disabled }
onClick={ () => toggleBottomBlock(PERFORMANCE) }
active={ bottomBlock === PERFORMANCE }
label="PERFORMANCE"
noIcon
labelClassName="text-base font-semibold"
/>
}
{showFetch &&
<ControlButton
disabled={disabled}
onClick={ ()=> toggleBottomBlock(FETCH) }
active={ bottomBlock === FETCH }
hasErrors={ fetchRedCount > 0 }
count={ fetchCount }
label="Fetch"
icon="fetch"
label="FETCH"
noIcon
labelClassName="text-base font-semibold"
/>
}
{ !live && showGraphql &&
@ -346,8 +383,9 @@ export default class Controls extends React.Component {
onClick={ ()=> toggleBottomBlock(GRAPHQL) }
active={ bottomBlock === GRAPHQL }
count={ graphqlCount }
label="GraphQL"
icon="vendors/graphql"
label="GRAPHQL"
noIcon
labelClassName="text-base font-semibold"
/>
}
{ !live && showStorage &&
@ -357,18 +395,8 @@ export default class Controls extends React.Component {
active={ bottomBlock === STORAGE }
count={ storageCount }
label={ getStorageName(storageType) }
icon={ getStorageIconName(storageType) }
/>
}
{
<ControlButton
disabled={ disabled }
onClick={ () => toggleBottomBlock(CONSOLE) }
active={ bottomBlock === CONSOLE }
label="Console"
icon="console"
count={ logCount }
hasErrors={ logRedCount > 0 }
noIcon
labelClassName="text-base font-semibold"
/>
}
{ showExceptions &&
@ -376,8 +404,9 @@ export default class Controls extends React.Component {
disabled={ disabled }
onClick={ () => toggleBottomBlock(EXCEPTIONS) }
active={ bottomBlock === EXCEPTIONS }
label="Exceptions"
icon="console/error"
label="EXCEPTIONS"
noIcon
labelClassName="text-base font-semibold"
count={ exceptionsCount }
hasErrors={ exceptionsCount > 0 }
/>
@ -387,8 +416,9 @@ export default class Controls extends React.Component {
disabled={ disabled }
onClick={ () => toggleBottomBlock(STACKEVENTS) }
active={ bottomBlock === STACKEVENTS }
label="Events"
icon="puzzle-piece"
label="EVENTS"
noIcon
labelClassName="text-base font-semibold"
count={ stackCount }
hasErrors={ stackRedCount > 0 }
/>
@ -399,51 +429,15 @@ export default class Controls extends React.Component {
onClick={ () => toggleBottomBlock(PROFILER) }
active={ bottomBlock === PROFILER }
count={ profilesCount }
label="Profiler"
icon="code"
label="PROFILER"
noIcon
labelClassName="text-base font-semibold"
/>
}
{
!live &&
<ControlButton
disabled={ disabled }
onClick={ () => toggleBottomBlock(PERFORMANCE) }
active={ bottomBlock === PERFORMANCE }
label="Performance"
icon="tachometer-slow"
/>
}
{/* { !live && showLongtasks &&
<ControlButton
disabled={ disabled }
onClick={ () => toggleBottomBlock(LONGTASKS) }
active={ bottomBlock === LONGTASKS }
label="Long Tasks"
icon="business-time"
/>
} */}
{ !live && <div className={cn(styles.divider, 'h-full')} /> }
{ !live &&
<React.Fragment>
<ControlButton
disabled={ fullscreenDisabled }
onClick={ this.props.fullscreenOn }
label="Full Screen"
icon="fullscreen"
/>
</React.Fragment>
this.controlIcon("arrows-angle-extend", 18, this.props.fullscreenOn, false, "rounded hover:bg-gray-light-shade")
}
{!live && (
<ControlButton
disabled={ disabled && !inspectorMode }
active={ bottomBlock === INSPECTOR }
onClick={ toggleInspectorMode }
icon={ inspectorMode ? 'close' : 'inspect' }
label="Inspect"
/>
)}
</div>
</div>
}

View file

@ -3,8 +3,8 @@ import { Duration } from 'luxon';
import { connectPlayer } from 'Player';
import styles from './time.module.css';
const Time = ({ time }) => (
<div className={ styles.time }>
const Time = ({ time, isCustom }) => (
<div className={ !isCustom && styles.time }>
{ Duration.fromMillis(time).toFormat('m:ss') }
</div>
)
@ -19,4 +19,4 @@ const ReduxTime = connectPlayer((state, { name }) => ({
ReduxTime.displayName = "ReduxTime";
export default Time;
export { ReduxTime };
export { ReduxTime };

View file

@ -2,7 +2,7 @@ import React from 'react';
import { connect } from 'react-redux';
import cn from 'classnames';
import { connectPlayer } from 'Player';
import { TimelinePointer } from 'UI';
import { Popup, TimelinePointer, Icon } from 'UI';
import TimeTracker from './TimeTracker';
import { ReduxTime } from './Time';
import stl from './timeline.module.css';
@ -11,20 +11,21 @@ import { setTimelinePointer } from 'Duck/sessions';
import DraggableCircle from './DraggableCircle';
import CustomDragLayer from './CustomDragLayer';
import { debounce } from 'App/utils';
import { Tooltip } from 'react-tippy';
const getPointerIcon = (type) => {
// exception,
// exception,
switch(type) {
case 'fetch':
return 'funnel/file-earmark-minus-fill';
case 'exception':
return 'funnel/exclamation-circle';
return 'funnel/exclamation-circle-fill';
case 'log':
return 'funnel/exclamation-circle';
return 'funnel/exclamation-circle-fill';
case 'stack':
return 'funnel/patch-exclamation-fill';
case 'resource':
return 'funnel/file-medical-alt';
return 'funnel/file-earmark-minus-fill';
case 'dead_click':
return 'funnel/dizzy';
@ -47,10 +48,10 @@ const getPointerIcon = (type) => {
case 'crash':
return 'funnel/file-exclamation';
case 'js_exception':
return 'funnel/exclamation-circle';
return 'funnel/exclamation-circle-fill';
}
return 'info';
return 'info';
}
@ -72,7 +73,7 @@ let deboucneJump = () => null;
fetchList: state.fetchList,
}))
@connect(state => ({
issues: state.getIn([ 'sessions', 'current', 'issues' ]),
issues: state.getIn([ 'sessions', 'current', 'issues' ]),
clickRageTime: state.getIn([ 'sessions', 'current', 'clickRage' ]) &&
state.getIn([ 'sessions', 'current', 'clickRageTime' ]),
returningLocationTime: state.getIn([ 'sessions', 'current', 'returningLocation' ]) &&
@ -143,10 +144,10 @@ export default class Timeline extends React.PureComponent {
const scale = 100 / endTime;
return (
<div
className={ cn("flex items-center") }
<div
className={ cn("flex items-center absolute w-full") }
style={{ top: '-5px', zIndex: 100}}
>
{ !live && <ReduxTime name="time" /> }
<div
className={ stl.progress }
onClick={ disabled ? null : this.seekProgress }
@ -176,219 +177,98 @@ export default class Timeline extends React.PureComponent {
}
{
issues.map(iss => (
<div
style={ {
<div
style={ {
left: `${ iss.time * scale }%`,
top: '-30px'
//width: `${ 2000 * scale }%`
} }
top: '0px',
zIndex: 11, width: 16, height: 16
} }
key={iss.key}
className={ stl.clickRage }
onClick={ this.createEventClickHandler(iss) }
>
<TimelinePointer
icon={iss.icon}
content={
<Tooltip
delay={0}
position="top"
html={
<div className={ stl.popup }>
<b>{ iss.name }</b>
</div>
}
/>
</div>
}
>
<Icon className="rounded-full p-px bg-white" name={iss.icon} size="16" />
</Tooltip>
</div>
))
}
{ events.filter(e => e.type === TYPES.CLICKRAGE).map(e => (
<div
style={ {
<div
style={ {
left: `${ e.time * scale }%`,
top: '-30px'
//width: `${ 2000 * scale }%`
} }
top: '0px',
zIndex: 11, width: 16, height: 16
} }
key={e.key}
className={ stl.clickRage }
onClick={ this.createEventClickHandler(e) }
>
<TimelinePointer
icon={getPointerIcon('click_rage')}
content={
<Tooltip
delay={0}
position="top"
html={
<div className={ stl.popup }>
<b>{ "Click Rage" }</b>
</div>
}
/>
</div>
}
>
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('click_rage')} size="16" />
</Tooltip>
</div>
// <Popup
// pinned
// offset="-19"
// trigger={
// <div
// style={ {
// left: `${ e.time * scale }%`,
// //width: `${ 2000 * scale }%`
// } }
// className={ stl.clickRage }
// />
// }
// content={
// <div className={ stl.popup }>
// <b>{ "Click Rage" }</b>
// </div>
// }
// />
))}
{ typeof clickRageTime === 'number' &&
<div
style={ {
{typeof clickRageTime === 'number' &&
<div
style={{
left: `${ clickRageTime * scale }%`,
top: '-30px'
//width: `${ 2000 * scale }%`
} }
className={ stl.clickRage }
top: '-0px',
zIndex: 11, width: 16, height: 16
}}
className={stl.clickRage}
>
<TimelinePointer
icon={getPointerIcon('click_rage')}
content={
<Tooltip
delay={0}
position="top"
html={
<div className={ stl.popup }>
<b>{ "Click Rage" }</b>
</div>
}
/>
</div>
}
>
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('click_rage')} size="16" />
</Tooltip>
</div>
// <Popup
// pinned
// offset="-19"
// trigger={
// <div
// style={ {
// left: `${ clickRageTime * scale }%`,
// //width: `${ 2000 * scale }%`
// } }
// className={ stl.clickRage }
// />
// }
// content={
// <div className={ stl.popup }>
// <b>{ "Click Rage" }</b>
// </div>
// }
// />
}
{ /* typeof returningLocationTime === 'number' &&
<Popup
pinned
offset="-19"
trigger={
<div
style={ {
left: `${ returningLocationTime * scale }%`,
//width: `${ 2000 * scale }%`
} }
className={ stl.returningLocation }
onClick={ this.createEventClickHandler(returningLocationTime) }
/>
}
content={
<div className={ stl.popup }>
<b>{ "Returning Location" }</b>
</div>
}
/>
*/ }
{ exceptionsList
.map(e => (
<div
key={ e.key }
className={ cn(stl.markup, stl.error) }
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
style={ { left: `${ e.time * scale }%`, top: '0px', zIndex: 10, width: 16, height: 16 } }
onClick={ this.createEventClickHandler(e) }
>
<TimelinePointer
icon={getPointerIcon('exception')}
content={
<Tooltip
delay={0}
position="top"
html={
<div className={ stl.popup } >
<b>{ "Exception" }</b>
<br/>
<span>{ e.message }</span>
</div>
}
/>
</div>
}
>
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('exception')} size="16" />
</Tooltip>
</div>
// <Popup
// key={ e.key }
// offset="-19"
// pinned
// className="error"
// trigger={
// <div
// key={ e.key }
// className={ cn(stl.markup, stl.error) }
// style={ { left: `${ e.time * scale }%` } }
// onClick={ this.createEventClickHandler(e.time) }
// />
// }
// content={
// <div className={ stl.popup } >
// <b>{ "Exception:" }</b>
// <br/>
// <span>{ e.message }</span>
// </div>
// }
// />
))
}
{ logList
.map(l => l.isRed() && (
<div
key={ l.key }
className={ cn(stl.markup, {
[ stl.error ]: l.isRed(),
//[ stl.warning ]: l.isYellow(),
//[ stl.info ]: !l.isYellow() && !l.isRed(),
}) }
style={ { left: `${ l.time * scale }%`, top: '-30px' } }
onClick={ this.createEventClickHandler(l) }
>
<TimelinePointer
icon={getPointerIcon('log')}
content={
<div className={ stl.popup } >
<b>{ "Console" }</b>
<br/>
<span>{ l.value }</span>
</div>
}
/>
</div>
// <Popup
// //on="click"
// key={ l.key }
// offset="-19"
// pinned
// className={ cn({
// "info": !l.isYellow() && !l.isRed(),
// "warn": l.isYellow(),
// "error": l.isRed(),
// })}
// trigger={
// <div
// key={ l.key }
// className={ cn(stl.markup, {
// [ stl.error ]: l.isRed(),
// //[ stl.warning ]: l.isYellow(),
// //[ stl.info ]: !l.isYellow() && !l.isRed(),
// }) }
// style={ { left: `${ l.time * scale }%` } }
// onClick={ this.createEventClickHandler(l.time) }
// />
// }
// content={
// <div className={ stl.popup } >
// <b>{ "Console:" }</b>
// <br/>
// <span>{ l.value }</span>
// </div>
// }
// />
))
}
{ resourceList
@ -396,49 +276,27 @@ export default class Timeline extends React.PureComponent {
.map(r => (
<div
key={ r.key }
className={ cn(stl.markup, {
className={ cn(stl.markup, {
[ stl.error ]: r.isRed(),
[ stl.warning ]: r.isYellow(),
}) }
style={ { left: `${ r.time * scale }%`, top: '-30px' } }
style={ { left: `${ r.time * scale }%`, top: '0px', zIndex: 10, width: 16, height: 16 } }
onClick={ this.createEventClickHandler(r) }
>
<TimelinePointer
icon={getPointerIcon('resource')}
content={
<Tooltip
delay={0}
position="top"
html={
<div className={ stl.popup }>
<b>{ r.success ? "Slow resource: " : "Missing resource:" }</b>
<br/>
{ r.name }
</div>
}
/>
</div>
}
>
<Icon className="rounded-full p-px bg-white" name={getPointerIcon('resource')} size="16" />
</Tooltip>
</div>
// <Popup
// key={ r.key }
// offset="-19"
// pinned
// trigger={
// <div
// key={ r.key }
// className={ cn(stl.markup, {
// [ stl.error ]: r.isRed(),
// [ stl.warning ]: r.isYellow(),
// }) }
// style={ { left: `${ r.time * scale }%` } }
// onClick={ this.createEventClickHandler(r.time) }
// >
// </div>
// }
// content={
// <div className={ stl.popup }>
// <b>{ r.success ? "Slow resource: " : "Missing resource:" }</b>
// <br/>
// { r.name }
// </div>
// }
// />
))
}
{ fetchList
@ -447,39 +305,20 @@ export default class Timeline extends React.PureComponent {
<div
key={ e.key }
className={ cn(stl.markup, stl.error) }
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
style={ { left: `${ e.time * scale }%`, top: '-5px' } }
onClick={ this.createEventClickHandler(e) }
>
<TimelinePointer
icon={getPointerIcon('fetch')}
content={
content={
<div className={ stl.popup }>
<b>{ "Failed Fetch" }</b>
<br/>
{ e.name }
</div>
</div>
}
/>
</div>
// <Popup
// offset="-19"
// pinned
// trigger={
// <div
// key={ e.key }
// className={ cn(stl.markup, stl.error) }
// style={ { left: `${ e.time * scale }%` } }
// onClick={ this.createEventClickHandler(e.time) }
// />
// }
// content={
// <div className={ stl.popup }>
// <b>{ "Failed Fetch:" }</b>
// <br/>
// { e.name }
// </div>
// }
// />
</div>
))
}
{ stackList
@ -488,43 +327,23 @@ export default class Timeline extends React.PureComponent {
<div
key={ e.key }
className={ cn(stl.markup, stl.error) }
style={ { left: `${ e.time * scale }%`, top: '-30px' } }
style={ { left: `${ e.time * scale }%`, top: '-5px' } }
onClick={ this.createEventClickHandler(e) }
>
<TimelinePointer
icon={getPointerIcon('stack')}
content={
content={
<div className={ stl.popup }>
<b> { "Stack Event" }</b>
<br/>
{ e.name }
</div>
</div>
}
/>
</div>
// <Popup
// offset="-19"
// pinned
// trigger={
// <div
// key={ e.key }
// className={ cn(stl.markup, stl.error) }
// style={ { left: `${ e.time * scale }%` } }
// onClick={ this.createEventClickHandler(e.time) }
// />
// }
// content={
// <div className={ stl.popup }>
// <b> { "Stack Event:" }</b>
// <br/>
// { e.name }
// </div>
// }
// />
))
}
</div>
{ !live && <ReduxTime name="endTime" /> }
</div>
);
}

View file

@ -19,15 +19,15 @@
height: 6px;
border-radius: 3px;
background-color: red;
top: 12px;
left: 23px;
bottom: 0px;
right: 0px;
position: absolute;
}
& .countLabel {
position: absolute;
top: -6px;
left: 12px;
right: -6px;
background-color: $gray-dark;
color: white;
font-size: 9px;
@ -52,4 +52,4 @@
pointer-events: none;
opacity: 0.5;
}
}
}

View file

@ -7,17 +7,15 @@
}
.controls {
/* margin-top: 10px; */
border-top: solid thin $gray-light;
padding-top: 36px;
padding-bottom: 10px;
padding-top: 10px;
position: relative;
}
.buttons {
display: flex;
justify-content: space-between;
margin-top: 7px;
align-items: center;
height: 65px;
padding: 0 30px;
&[data-is-live=true] {
padding: 0;
@ -115,4 +113,4 @@
animation: fade 1s infinite;
}
}
}
}

View file

@ -16,9 +16,8 @@
.playedTimeline {
display: block;
height: 100%;
border-radius: 4px;
background-color: $teal;
background-color: $active-blue-border;
pointer-events: none;
height: 2px;
height: 10px;
z-index: 1;
}
}

View file

@ -1,22 +1,22 @@
.positionTracker {
width: 15px;
height: 15px;
outline: solid 1px $teal;
outline: solid 1px $teal-dark;
outline-style: inset;
margin-left: -7px;
border-radius: 50%;
background-color: $active-blue;
background-color: $main;
position: absolute;
left: 0;
z-index: 98;
top: 0;
top: 3px;
transition: all 0.2s ease-out;
&:hover,
&:focus {
transition: all 0.1s ease-in;
width: 20px;
height: 20px;
top: -2px;
top: 1px;
left: -2px;
}
@ -24,8 +24,7 @@
.progress {
height: 10px;
border-radius: 1px;
background: transparent;
padding: 8px 0;
cursor: pointer;
width: 100%;
position: relative;
@ -36,22 +35,20 @@
.skipInterval {
position: absolute;
top: 0;
top: 3px;
height: 10px;
bottom: 0;
border-radius: 4px;
background-color: rgba(0, 0, 0, 0.15);
background-color: $gray-light;
pointer-events: none;
z-index: 2;
}
.event {
position: absolute;
width: 8px;
height: 8px;
border: solid 1px white;
margin-left: -4px;
border-radius: 50%;
background: rgba(136, 136, 136, 0.8);
width: 2px;
height: 10px;
background: $main;
pointer-events: none;
/* top: 0; */
/* bottom: 0; */
@ -74,7 +71,6 @@
position: absolute;
width: 2px;
height: 8px;
border-radius: 2px;
margin-left: -15px;
&:hover {
z-index: 9999;
@ -112,13 +108,13 @@
}
.timeline {
border-radius: 5px;
overflow: hidden;
position: absolute;
left: 0;
right: 0;
height: 2px;
background-color: $gray-light;
height: 10px;
border-top: 1px solid $gray-light;
border-bottom: 1px solid $gray-light;
display: flex;
align-items: center;
}
@ -127,7 +123,6 @@
position: absolute;
width: 2px;
height: 8px;
border-radius: 2px;
margin-left: -1px;
/* background: $red; */
}
@ -146,7 +141,6 @@
margin-left: -9px;
background-color: $gray-lightest;
padding: 2px;
border-radius: 3px;
box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1);
& .tooltipArrow {
@ -169,4 +163,4 @@
box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1);
}
}
}
}

View file

@ -119,12 +119,12 @@ export default class PlayerBlockHeader extends React.PureComponent {
<div className={cn("ml-auto flex items-center h-full", { 'hidden' : closedLive })}>
{ live && !isAssist && (
<>
<div className={stl.liveSwitchButton}>
<div className={cn(stl.liveSwitchButton, 'pr-4')}>
<Link to={withSiteId(liveSessionRoute(sessionId), siteId)}>
This Session is Now Continuing Live
</Link>
</div>
<div className={ stl.divider } />
{_metaList.length > 0 && <div className={ stl.divider } />}
</>
)}

View file

@ -0,0 +1,3 @@
<svg viewBox="0 0 27 27" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.80392 17.1429C9.64551 16.9846 9.43069 16.8956 9.2067 16.8956C8.98271 16.8956 8.76789 16.9846 8.60948 17.1429L1.68946 24.0629V19.3865C1.68946 19.1625 1.60046 18.9476 1.44204 18.7892C1.28363 18.6308 1.06876 18.5418 0.844729 18.5418C0.620693 18.5418 0.405833 18.6308 0.247415 18.7892C0.088998 18.9476 0 19.1625 0 19.3865V26.1021C0 26.3262 0.088998 26.541 0.247415 26.6994C0.405833 26.8579 0.620693 26.9469 0.844729 26.9469H7.56032C7.78436 26.9469 7.99922 26.8579 8.15764 26.6994C8.31605 26.541 8.40505 26.3262 8.40505 26.1021C8.40505 25.8781 8.31605 25.6632 8.15764 25.5048C7.99922 25.3464 7.78436 25.2574 7.56032 25.2574H2.8839L9.80392 18.3374C9.96229 18.179 10.0512 17.9641 10.0512 17.7402C10.0512 17.5162 9.96229 17.3013 9.80392 17.1429ZM17.1429 9.80392C17.3013 9.96229 17.5162 10.0512 17.7402 10.0512C17.9641 10.0512 18.179 9.96229 18.3374 9.80392L25.2574 2.8839V7.56032C25.2574 7.78436 25.3464 7.99922 25.5048 8.15764C25.6632 8.31605 25.8781 8.40505 26.1021 8.40505C26.3262 8.40505 26.541 8.31605 26.6994 8.15764C26.8579 7.99922 26.9469 7.78436 26.9469 7.56032V0.844729C26.9469 0.620693 26.8579 0.405833 26.6994 0.247415C26.541 0.088998 26.3262 0 26.1021 0H19.3865C19.1625 3.3384e-09 18.9476 0.088998 18.7892 0.247415C18.6308 0.405833 18.5418 0.620693 18.5418 0.844729C18.5418 1.06876 18.6308 1.28363 18.7892 1.44204C18.9476 1.60046 19.1625 1.68946 19.3865 1.68946H24.0629L17.1429 8.60948C16.9846 8.76789 16.8956 8.98271 16.8956 9.2067C16.8956 9.43069 16.9846 9.64551 17.1429 9.80392Z" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path d="M5.5 3.5A1.5 1.5 0 0 1 7 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5zm5 0A1.5 1.5 0 0 1 12 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 222 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<path d="m11.596 8.697-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.393z"/>
</svg>

After

Width:  |  Height:  |  Size: 207 B