change(ui): extract some player components
This commit is contained in:
parent
a1ce424df9
commit
579586b56b
14 changed files with 432 additions and 106 deletions
|
|
@ -1,22 +1,23 @@
|
|||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import { connect } from 'react-redux';
|
||||
import { STORAGE_TYPES, selectStorageType } from 'Player';
|
||||
import { selectStorageType, STORAGE_TYPES } from 'Player';
|
||||
import { PlayButton, PlayingState, FullScreenButton } from 'Player/components'
|
||||
|
||||
import { Icon, Tooltip } from 'UI';
|
||||
import {
|
||||
fullscreenOn,
|
||||
fullscreenOff,
|
||||
toggleBottomBlock,
|
||||
OVERVIEW,
|
||||
CONSOLE,
|
||||
NETWORK,
|
||||
STACKEVENTS,
|
||||
STORAGE,
|
||||
PROFILER,
|
||||
PERFORMANCE,
|
||||
fullscreenOff,
|
||||
fullscreenOn,
|
||||
GRAPHQL,
|
||||
INSPECTOR,
|
||||
NETWORK,
|
||||
OVERVIEW,
|
||||
PERFORMANCE,
|
||||
PROFILER,
|
||||
STACKEVENTS,
|
||||
STORAGE,
|
||||
toggleBottomBlock,
|
||||
} from 'Duck/components/player';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
|
@ -138,53 +139,13 @@ function Controls(props: any) {
|
|||
};
|
||||
|
||||
const renderPlayBtn = () => {
|
||||
let label;
|
||||
let icon;
|
||||
if (completed) {
|
||||
icon = 'arrow-clockwise' as const;
|
||||
label = 'Replay this session';
|
||||
} else if (playing) {
|
||||
icon = 'pause-fill' as const;
|
||||
label = 'Pause';
|
||||
} else {
|
||||
icon = 'play-fill-new' as const;
|
||||
label = 'Pause';
|
||||
label = 'Play';
|
||||
}
|
||||
const state = completed ? PlayingState.Completed : playing ? PlayingState.Playing : PlayingState.Paused
|
||||
|
||||
return (
|
||||
<Tooltip title={label} className="mr-4">
|
||||
<div
|
||||
onClick={() => player.togglePlay()}
|
||||
className="hover-main color-main cursor-pointer rounded hover:bg-gray-light-shade"
|
||||
>
|
||||
<Icon name={icon} size="36" color="inherit" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
<PlayButton state={state} togglePlay={player.togglePlay} iconSize={36} />
|
||||
);
|
||||
};
|
||||
|
||||
const controlIcon = (
|
||||
icon: string,
|
||||
size: number,
|
||||
action: (args: any) => any,
|
||||
isBackwards: boolean,
|
||||
additionalClasses: string
|
||||
) => (
|
||||
<div
|
||||
onClick={action}
|
||||
className={cn('py-1 px-2 hover-main cursor-pointer bg-gray-lightest', additionalClasses)}
|
||||
style={{ transform: isBackwards ? 'rotate(180deg)' : '' }}
|
||||
>
|
||||
<Icon
|
||||
// @ts-ignore
|
||||
name={icon}
|
||||
size={size}
|
||||
color="inherit"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
const toggleBottomTools = (blockName: number) => {
|
||||
if (blockName === INSPECTOR) {
|
||||
// player.toggleInspectorMode(false);
|
||||
|
|
@ -210,7 +171,6 @@ function Controls(props: any) {
|
|||
toggleSpeed={() => player.toggleSpeed()}
|
||||
toggleSkip={() => player.toggleSkip()}
|
||||
playButton={renderPlayBtn()}
|
||||
controlIcon={controlIcon}
|
||||
skipIntervals={SKIP_INTERVALS}
|
||||
setSkipInterval={changeSkipInterval}
|
||||
currentInterval={skipInterval}
|
||||
|
|
@ -301,13 +261,11 @@ function Controls(props: any) {
|
|||
)}
|
||||
|
||||
<Tooltip title="Fullscreen" delay={0} placement="top-start" className="mx-4">
|
||||
{controlIcon(
|
||||
'arrows-angle-extend',
|
||||
16,
|
||||
props.fullscreenOn,
|
||||
false,
|
||||
'rounded hover:bg-gray-light-shade color-gray-medium'
|
||||
)}
|
||||
<FullScreenButton
|
||||
size={16}
|
||||
onClick={props.fullscreenOn}
|
||||
customClasses={'rounded hover:bg-gray-light-shade color-gray-medium'}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,25 +1,15 @@
|
|||
import React from 'react';
|
||||
import { Duration } from 'luxon';
|
||||
import styles from './time.module.css';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
const Time = ({ time, isCustom, format = 'm:ss', }) => (
|
||||
<div className={ !isCustom ? styles.time : undefined }>
|
||||
{ Duration.fromMillis(time).toFormat(format) }
|
||||
</div>
|
||||
)
|
||||
|
||||
Time.displayName = "Time";
|
||||
import { PlayTime } from 'Player/components'
|
||||
|
||||
const ReduxTime = observer(({ format, name, isCustom }) => {
|
||||
const { store } = React.useContext(PlayerContext)
|
||||
const time = store.get()[name]
|
||||
|
||||
return <Time format={format} time={time} isCustom={isCustom} />
|
||||
return <PlayTime format={format} time={time} isCustom={isCustom} />
|
||||
})
|
||||
|
||||
ReduxTime.displayName = "ReduxTime";
|
||||
|
||||
export default React.memo(Time);
|
||||
export { ReduxTime };
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
import React from 'react';
|
||||
import { PlayerContext } from 'App/components/Session/playerContext';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import styles from './timeTracker.module.css';
|
||||
import cn from 'classnames'
|
||||
import { ProgressBar } from 'Player/components'
|
||||
|
||||
const TimeTracker = ({ scale, live = false, left }) => {
|
||||
const { store } = React.useContext(PlayerContext)
|
||||
const time = store.get().time
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<span
|
||||
className={ cn(styles.playedTimeline, live && left > 99 ? styles.liveTime : null) }
|
||||
style={ { width: `${ time * scale }%` } }
|
||||
/>
|
||||
</React.Fragment>
|
||||
<ProgressBar
|
||||
scale={scale}
|
||||
live={live}
|
||||
left={left}
|
||||
time={time}
|
||||
/>
|
||||
);}
|
||||
|
||||
TimeTracker.displayName = 'TimeTracker';
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { memo, FC, useEffect, CSSProperties } from 'react';
|
|||
import type { DragSourceMonitor } from 'react-dnd'
|
||||
import { useDrag } from 'react-dnd'
|
||||
import { getEmptyImage } from 'react-dnd-html5-backend'
|
||||
import Circle from './Circle'
|
||||
import { ProgressCircle } from 'Player/components'
|
||||
|
||||
function getStyles(
|
||||
left: number,
|
||||
|
|
@ -41,7 +41,7 @@ const DraggableCircle: FC<Props> = memo(function DraggableCircle({
|
|||
live,
|
||||
onDrop,
|
||||
}) {
|
||||
const [{ isDragging, item }, dragRef, preview] = useDrag(
|
||||
const [{ isDragging }, dragRef, preview] = useDrag(
|
||||
() => ({
|
||||
type: ItemTypes.BOX,
|
||||
item: { left },
|
||||
|
|
@ -64,7 +64,7 @@ const DraggableCircle: FC<Props> = memo(function DraggableCircle({
|
|||
style={getStyles(left, isDragging)}
|
||||
role="DraggableBox"
|
||||
>
|
||||
<Circle isGreen={left > 99 && live} />
|
||||
<ProgressCircle isGreen={left > 99 && live} />
|
||||
</div>
|
||||
);
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import cn from 'classnames';
|
|||
import { ReduxTime } from '../Time';
|
||||
// @ts-ignore
|
||||
import styles from '../controls.module.css';
|
||||
import { SkipButton } from 'Player/components'
|
||||
|
||||
interface Props {
|
||||
skip: boolean;
|
||||
|
|
@ -17,13 +18,6 @@ interface Props {
|
|||
forthTenSeconds: () => void;
|
||||
toggleSpeed: () => void;
|
||||
toggleSkip: () => void;
|
||||
controlIcon: (
|
||||
icon: string,
|
||||
size: number,
|
||||
action: () => void,
|
||||
isBackwards: boolean,
|
||||
additionalClasses: string
|
||||
) => JSX.Element;
|
||||
}
|
||||
|
||||
function PlayerControls(props: Props) {
|
||||
|
|
@ -39,7 +33,6 @@ function PlayerControls(props: Props) {
|
|||
skipIntervals,
|
||||
setSkipInterval,
|
||||
currentInterval,
|
||||
controlIcon,
|
||||
} = props;
|
||||
const [showTooltip, setShowTooltip] = React.useState(false);
|
||||
const speedRef = React.useRef<HTMLButtonElement>(null);
|
||||
|
|
@ -98,13 +91,12 @@ function PlayerControls(props: Props) {
|
|||
ref={arrowBackRef}
|
||||
className="h-full bg-transparent"
|
||||
>
|
||||
{controlIcon(
|
||||
'skip-forward-fill',
|
||||
18,
|
||||
backTenSeconds,
|
||||
true,
|
||||
'hover:bg-active-blue-border color-main h-full flex items-center'
|
||||
)}
|
||||
<SkipButton
|
||||
size={18}
|
||||
onClick={backTenSeconds}
|
||||
isBackwards={true}
|
||||
customClasses={'hover:bg-active-blue-border color-main h-full flex items-center'}
|
||||
/>
|
||||
</button>
|
||||
</Tooltip>
|
||||
|
||||
|
|
@ -158,13 +150,11 @@ function PlayerControls(props: Props) {
|
|||
ref={arrowForwardRef}
|
||||
className="h-full bg-transparent"
|
||||
>
|
||||
{controlIcon(
|
||||
'skip-forward-fill',
|
||||
18,
|
||||
forthTenSeconds,
|
||||
false,
|
||||
'hover:bg-active-blue-border color-main h-full flex items-center'
|
||||
)}
|
||||
<SkipButton
|
||||
size={18}
|
||||
onClick={forthTenSeconds}
|
||||
customClasses={'hover:bg-active-blue-border color-main h-full flex items-center'}
|
||||
/>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
|
|
|
|||
25
frontend/app/player/components/FullScreenButton.tsx
Normal file
25
frontend/app/player/components/FullScreenButton.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react'
|
||||
import { Icon } from 'UI'
|
||||
import cn from 'classnames'
|
||||
|
||||
interface IProps {
|
||||
size: number;
|
||||
onClick: () => void;
|
||||
customClasses: string;
|
||||
}
|
||||
|
||||
export function FullScreenButton({ size = 18, onClick, customClasses }: IProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
className={cn('py-1 px-2 hover-main cursor-pointer bg-gray-lightest', customClasses)}
|
||||
>
|
||||
<Icon
|
||||
name="arrows-angle-extend"
|
||||
size={size}
|
||||
color="inherit"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
44
frontend/app/player/components/PlayButton.tsx
Normal file
44
frontend/app/player/components/PlayButton.tsx
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import React from 'react'
|
||||
import { Icon, Tooltip } from "UI";
|
||||
|
||||
export enum PlayingState {
|
||||
Playing,
|
||||
Paused,
|
||||
Completed
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
togglePlay: () => void;
|
||||
iconSize: number;
|
||||
state: PlayingState;
|
||||
}
|
||||
|
||||
const Values = {
|
||||
[PlayingState.Playing]: {
|
||||
icon: 'pause-fill' as const,
|
||||
label: 'Pause'
|
||||
},
|
||||
[PlayingState.Completed]: {
|
||||
icon: 'arrow-clockwise' as const,
|
||||
label: 'Replay this session',
|
||||
},
|
||||
[PlayingState.Paused]: {
|
||||
icon: 'play-fill-new' as const,
|
||||
label: 'Play'
|
||||
}
|
||||
}
|
||||
|
||||
export function PlayButton({ togglePlay, iconSize, state }: IProps) {
|
||||
const { icon, label } = Values[state];
|
||||
|
||||
return (
|
||||
<Tooltip title={label} className="mr-4">
|
||||
<div
|
||||
onClick={togglePlay}
|
||||
className="hover-main color-main cursor-pointer rounded hover:bg-gray-light-shade"
|
||||
>
|
||||
<Icon name={icon} size={iconSize} color="inherit" />
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
27
frontend/app/player/components/PlayTime.tsx
Normal file
27
frontend/app/player/components/PlayTime.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react'
|
||||
import { Duration } from 'luxon';
|
||||
|
||||
const styles = {
|
||||
padding: '0 12px',
|
||||
width: '70px',
|
||||
'text-align': 'center',
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
/** current time in ms */
|
||||
time: number;
|
||||
isCustom?: boolean;
|
||||
format?: string;
|
||||
}
|
||||
|
||||
/** Play time timer */
|
||||
export const PlayTime = ({ time, isCustom, format = 'm:ss', }: IProps) => (
|
||||
<div
|
||||
style={!isCustom ? styles : undefined}
|
||||
className={!isCustom ? 'color-gray-medium' : undefined}
|
||||
>
|
||||
{Duration.fromMillis(time).toFormat(format)}
|
||||
</div>
|
||||
)
|
||||
|
||||
PlayTime.displayName = "PlayTime";
|
||||
31
frontend/app/player/components/ProgressBar.tsx
Normal file
31
frontend/app/player/components/ProgressBar.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react';
|
||||
|
||||
interface IProps {
|
||||
scale: number;
|
||||
live?: boolean;
|
||||
left: number;
|
||||
time: number;
|
||||
}
|
||||
|
||||
const styles = {
|
||||
display: 'block',
|
||||
pointerEvents: 'none' as const,
|
||||
height: '10px',
|
||||
zIndex: 1,
|
||||
}
|
||||
const replayBg = '#d0d4f2' // active blue border
|
||||
const liveBg = 'rgba(66, 174, 94, 0.3)' // light green shade
|
||||
|
||||
/** Playtime progress bar */
|
||||
export const ProgressBar = ({ scale, live = false, left, time }: IProps) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
...styles,
|
||||
width: `${ time * scale }%`,
|
||||
backgroundColor: live && left > 99 ? liveBg : replayBg
|
||||
}}
|
||||
/>
|
||||
);}
|
||||
|
||||
ProgressBar.displayName = 'ProgressBar';
|
||||
16
frontend/app/player/components/ProgressCircle.tsx
Normal file
16
frontend/app/player/components/ProgressCircle.tsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import React, { memo } from 'react';
|
||||
import cn from 'classnames';
|
||||
import styles from './styles.module.css';
|
||||
|
||||
interface IProps {
|
||||
preview?: boolean;
|
||||
isGreen?: boolean;
|
||||
}
|
||||
|
||||
export const ProgressCircle = memo(({ preview, isGreen }: IProps) => (
|
||||
<div
|
||||
className={cn(styles.positionTracker, { [styles.greenTracker]: isGreen })}
|
||||
role={preview ? 'BoxPreview' : 'Box'}
|
||||
/>
|
||||
)
|
||||
)
|
||||
27
frontend/app/player/components/SkipButton.tsx
Normal file
27
frontend/app/player/components/SkipButton.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import React from 'react'
|
||||
import { Icon } from 'UI'
|
||||
import cn from 'classnames'
|
||||
|
||||
interface IProps {
|
||||
size: number;
|
||||
onClick: () => void;
|
||||
isBackwards?: boolean;
|
||||
customClasses: string;
|
||||
}
|
||||
|
||||
export function SkipButton({ size = 18, onClick, isBackwards, customClasses }: IProps) {
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
className={cn('py-1 px-2 hover-main cursor-pointer bg-gray-lightest', customClasses)}
|
||||
style={{ transform: isBackwards ? 'rotate(180deg)' : '' }}
|
||||
>
|
||||
<Icon
|
||||
name="skip-forward-fill"
|
||||
size={size}
|
||||
color="inherit"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
6
frontend/app/player/components/index.tsx
Normal file
6
frontend/app/player/components/index.tsx
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
export { PlayButton, PlayingState } from './PlayButton'
|
||||
export { SkipButton } from './SkipButton'
|
||||
export { FullScreenButton } from './FullScreenButton'
|
||||
export { PlayTime } from './PlayTime'
|
||||
export { ProgressBar } from './ProgressBar'
|
||||
export { ProgressCircle } from './ProgressCircle'
|
||||
213
frontend/app/player/components/styles.module.css
Normal file
213
frontend/app/player/components/styles.module.css
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
.positionTracker {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
box-shadow: 0 0 0 1px #2331A8;
|
||||
margin-left: -7px;
|
||||
border-radius: 50%;
|
||||
background-color: $main;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
z-index: 98;
|
||||
top: 3px;
|
||||
transition: all 0.2s ease-out;
|
||||
&:hover,
|
||||
&:focus {
|
||||
transition: all 0.1s ease-in;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
top: 1px;
|
||||
left: -2px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.greenTracker {
|
||||
background-color: #42AE5E!important;
|
||||
box-shadow: 0 0 0 1px #42AE5E;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 10px;
|
||||
padding: 8px 0;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.skipInterval {
|
||||
position: absolute;
|
||||
top: 3px;
|
||||
height: 10px;
|
||||
bottom: 0;
|
||||
background: repeating-linear-gradient( 125deg, #efefef, #efefef 3px, #ddd 3px, #efefef 5px );
|
||||
pointer-events: none;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
|
||||
.event {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 10px;
|
||||
background: $main;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
/* top: 0; */
|
||||
/* bottom: 0; */
|
||||
/* &:hover {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: -6px;
|
||||
z-index: 1;
|
||||
};*/
|
||||
}
|
||||
|
||||
/* .event.click, .event.input {
|
||||
background: $green;
|
||||
}
|
||||
.event.location {
|
||||
background: $blue;
|
||||
} */
|
||||
.redEvent {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 10px;
|
||||
background: $red;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
/* top: 0; */
|
||||
/* bottom: 0; */
|
||||
/* &:hover {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: -6px;
|
||||
z-index: 1;
|
||||
};*/
|
||||
}
|
||||
|
||||
.markup {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 8px;
|
||||
margin-left: -8px;
|
||||
&:hover {
|
||||
z-index: 9999;
|
||||
}
|
||||
}
|
||||
|
||||
/* .markup.log {
|
||||
background: $blue;
|
||||
}
|
||||
|
||||
.markup.error {
|
||||
background: $red;
|
||||
}
|
||||
|
||||
.markup.warning {
|
||||
background: $orange;
|
||||
} */
|
||||
|
||||
.markup.info {
|
||||
background: $blue2;
|
||||
}
|
||||
|
||||
.popup {
|
||||
max-width: 300px !important;
|
||||
/* max-height: 300px !important; */
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
& span {
|
||||
display: block;
|
||||
max-height: 200px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.timeline {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 10px;
|
||||
border: 1px solid $gray-light;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.clickRage {
|
||||
position: absolute;
|
||||
width: 2px;
|
||||
height: 8px;
|
||||
margin-left: -1px;
|
||||
/* background: $red; */
|
||||
}
|
||||
|
||||
.returningLocation {
|
||||
position: absolute;
|
||||
height: 20%;
|
||||
border-radius: 50%;
|
||||
/* background: $red; */
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.feedbackIcon {
|
||||
position: absolute;
|
||||
margin-top: -20px;
|
||||
margin-left: -9px;
|
||||
background-color: $gray-lightest;
|
||||
padding: 2px;
|
||||
box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1);
|
||||
|
||||
& .tooltipArrow {
|
||||
width: 50px;
|
||||
height: 25px;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
overflow: hidden;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
background: $gray-lightest;
|
||||
transform: translateX(-50%) translateY(50%) rotate(45deg);
|
||||
bottom: 100%;
|
||||
left: 50%;
|
||||
box-shadow: 0px 0px 0px 1px rgba(0,0,0,0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.timeTooltip {
|
||||
position: absolute;
|
||||
padding: 0.25rem;
|
||||
transition-property: all;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
background: black;
|
||||
top: -35px;
|
||||
color: white;
|
||||
|
||||
&:after {
|
||||
content:'';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 auto;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: solid 5px black;
|
||||
border-left: solid 5px transparent;
|
||||
border-right: solid 5px transparent;
|
||||
}
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@ const borderStyles = {
|
|||
left: 0,
|
||||
top: 0,
|
||||
position: 'fixed',
|
||||
'pointer-events': 'none',
|
||||
pointerEvents: 'none',
|
||||
}
|
||||
|
||||
const buttonStyles = {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue