feat(ui): change events tab design, move action buttons to subheader
This commit is contained in:
parent
aff6f54397
commit
c584b0f653
17 changed files with 280 additions and 155 deletions
|
|
@ -2,7 +2,7 @@ import React, { useState } from 'react'
|
|||
import EventsBlock from '../Session_/EventsBlock';
|
||||
import PageInsightsPanel from '../Session_/PageInsightsPanel/PageInsightsPanel'
|
||||
import { Controls as PlayerControls } from 'Player';
|
||||
import { Tabs } from 'UI';
|
||||
import Tabs from './Tabs';
|
||||
import { connectPlayer } from 'Player';
|
||||
import NewBadge from 'Shared/NewBadge';
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ export default function RightBlock() {
|
|||
}
|
||||
}
|
||||
return (
|
||||
<div style={{ width: '270px', height: 'calc(100vh- 50px)'}} className="flex flex-col">
|
||||
<div style={{ width: '270px', height: 'calc(100vh- 50px)'}} className="flex flex-col bg-white border-l">
|
||||
<div className="relative">
|
||||
<Tabs
|
||||
tabs={ TABS }
|
||||
|
|
@ -40,8 +40,8 @@ export default function RightBlock() {
|
|||
<div className="absolute" style={{ left: '160px', top: '13px' }}>{ <NewBadge />}</div>
|
||||
</div>
|
||||
{
|
||||
renderActiveTab(activeTab)
|
||||
}
|
||||
renderActiveTab(activeTab)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
32
frontend/app/components/Session/Tabs/Tabs.tsx
Normal file
32
frontend/app/components/Session/Tabs/Tabs.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import stl from './tabs.css';
|
||||
|
||||
interface Props {
|
||||
tabs: Array<any>;
|
||||
active: string;
|
||||
onClick: (key: any) => void;
|
||||
border?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Tabs = ({ tabs, active, onClick, border = true, className }: Props) => (
|
||||
<div className={ cn(stl.tabs, className, { [ stl.bordered ]: border }) } role="tablist" >
|
||||
{ tabs.map(({ key, text, hidden = false, disabled = false }) => (
|
||||
<div
|
||||
key={ key }
|
||||
className={ cn(stl.tab, { [ stl.active ]: active === key, [ stl.disabled ]: disabled }) }
|
||||
data-hidden={ hidden }
|
||||
onClick={ onClick && (() => onClick(key)) }
|
||||
role="tab"
|
||||
data-openreplay-label={text}
|
||||
>
|
||||
{ text }
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
Tabs.displayName = 'Tabs';
|
||||
|
||||
export default Tabs;
|
||||
1
frontend/app/components/Session/Tabs/index.ts
Normal file
1
frontend/app/components/Session/Tabs/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export { default } from './Tabs'
|
||||
32
frontend/app/components/Session/Tabs/tabs.css
Normal file
32
frontend/app/components/Session/Tabs/tabs.css
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
.tabs {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
&.bordered {
|
||||
border-bottom: solid thin $gray-light;
|
||||
}
|
||||
}
|
||||
|
||||
.tab {
|
||||
padding: 14px 15px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
color: $gray-darkest;
|
||||
border-bottom: solid thin transparent;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: $teal;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: $teal;
|
||||
border-bottom: solid thin $teal;
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ import { useEffect } from 'react';
|
|||
import { connect } from 'react-redux';
|
||||
import { Loader } from 'UI';
|
||||
import { toggleFullscreen, closeBottomBlock } from 'Duck/components/player';
|
||||
import {
|
||||
import {
|
||||
PlayerProvider,
|
||||
connectPlayer,
|
||||
init as initPlayer,
|
||||
|
|
@ -20,26 +20,33 @@ import PlayerBlock from '../Session_/PlayerBlock';
|
|||
import styles from '../Session_/session.module.css';
|
||||
|
||||
|
||||
const InitLoader = connectPlayer(state => ({
|
||||
const InitLoader = connectPlayer(state => ({
|
||||
loading: !state.initialized
|
||||
}))(Loader);
|
||||
|
||||
const PlayerContentConnected = connectPlayer(state => ({
|
||||
const PlayerContentConnected = connectPlayer(state => ({
|
||||
showEvents: !state.showEvents
|
||||
}))(PlayerContent);
|
||||
|
||||
|
||||
function PlayerContent({ live, fullscreen, showEvents }) {
|
||||
function PlayerContent({ live, fullscreen }) {
|
||||
return (
|
||||
<div className={ cn(styles.session, 'relative') } data-fullscreen={fullscreen}>
|
||||
<PlayerBlock />
|
||||
{ showEvents && !live && !fullscreen && <RightBlock /> }
|
||||
<PlayerBlock />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function RightMenu({ showEvents, live, fullscreen }) {
|
||||
console.log(!live, !fullscreen, showEvents)
|
||||
return showEvents && !live && !fullscreen && <RightBlock />
|
||||
}
|
||||
|
||||
const ConnectedMenu = connectPlayer(state => ({
|
||||
showEvents: !state.showEvents}))(RightMenu)
|
||||
|
||||
function WebPlayer (props) {
|
||||
const { session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt} = props;
|
||||
const { session, toggleFullscreen, closeBottomBlock, live, fullscreen, jwt, config, showEvents } = props;
|
||||
|
||||
useEffect(() => {
|
||||
initPlayer(session, jwt);
|
||||
|
|
@ -60,8 +67,13 @@ function WebPlayer (props) {
|
|||
return (
|
||||
<PlayerProvider>
|
||||
<InitLoader className="flex-1">
|
||||
<PlayerBlockHeader fullscreen={fullscreen}/>
|
||||
<PlayerContentConnected fullscreen={fullscreen} live={live} />
|
||||
<div className="flex">
|
||||
<div className="w-full">
|
||||
<PlayerBlockHeader fullscreen={fullscreen}/>
|
||||
<PlayerContentConnected fullscreen={fullscreen} live={live} />
|
||||
</div>
|
||||
<ConnectedMenu fullscreen={fullscreen} live={live} />
|
||||
</div>
|
||||
</InitLoader>
|
||||
</PlayerProvider>
|
||||
);
|
||||
|
|
@ -72,6 +84,7 @@ export default connect(state => ({
|
|||
jwt: state.get('jwt'),
|
||||
// config: state.getIn([ 'user', 'account', 'iceServers' ]),
|
||||
fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]),
|
||||
showEvents: state.get('showEvents'),
|
||||
}), {
|
||||
toggleFullscreen,
|
||||
closeBottomBlock,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import React, { useEffect } from 'react'
|
|||
import { connect } from 'react-redux'
|
||||
import { setAutoplayValues } from 'Duck/sessions'
|
||||
import { session as sessionRoute } from 'App/routes';
|
||||
import { Link, Icon, Toggler, Popup } from 'UI';
|
||||
import { Link, Icon, Slider, Toggler } from 'UI';
|
||||
import { connectPlayer } from 'Player/store';
|
||||
import { Controls as PlayerControls } from 'Player';
|
||||
|
||||
|
|
@ -15,20 +15,21 @@ function Autoplay(props) {
|
|||
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<Link to={ sessionRoute(previousId) } disabled={!previousId}>
|
||||
<Icon name="prev1" size="20" color="teal" />
|
||||
</Link>
|
||||
<Popup content={'Autoplay'} distance={22} >
|
||||
<div onClick={props.toggleAutoplay} className="cursor-pointer flex items-center mr-2">
|
||||
<Toggler
|
||||
name="sessionsLive"
|
||||
onChange={ props.toggleAutoplay }
|
||||
checked={ autoplay }
|
||||
style={{ margin: '0px 10px 0px 12px'}}
|
||||
name="sessionsLive"
|
||||
onChange={ props.toggleAutoplay }
|
||||
checked={ autoplay }
|
||||
plain
|
||||
/>
|
||||
</Popup>
|
||||
|
||||
<span className="ml-2">Auto-Play</span>
|
||||
</div>
|
||||
|
||||
<Link to={ sessionRoute(previousId) } disabled={!previousId}>
|
||||
<Icon name="prev1" size="16" color="teal" />
|
||||
</Link>
|
||||
<Link to={ sessionRoute(nextId) } disabled={!nextId}>
|
||||
<Icon name="next1" size="20" color="teal" />
|
||||
<Icon name="next1" size="16" color="teal" />
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -41,6 +42,6 @@ const connectAutoplay = connect(state => ({
|
|||
|
||||
export default connectAutoplay(connectPlayer(state => ({
|
||||
autoplay: state.autoplay,
|
||||
}), {
|
||||
toggleAutoplay: PlayerControls.toggleAutoplay
|
||||
}), {
|
||||
toggleAutoplay: PlayerControls.toggleAutoplay
|
||||
})(Autoplay))
|
||||
|
|
|
|||
|
|
@ -5,48 +5,44 @@ export default function EventSearch(props) {
|
|||
const { onChange, clearSearch, value, header } = props;
|
||||
const [showSearch, setShowSearch] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearSearch()
|
||||
}
|
||||
}, [])
|
||||
|
||||
const toggleSearch = () => {
|
||||
setShowSearch(!showSearch)
|
||||
clearSearch();
|
||||
}
|
||||
return (
|
||||
<div className="flex items-center w-full">
|
||||
<div className="flex flex-1 relative items-center" style={{ height: '32px' }}>
|
||||
{ showSearch ?
|
||||
<div className="flex items-center">
|
||||
<div className="flex items-center w-full relative">
|
||||
<div className="flex flex-1 flex-col">
|
||||
<div className='flex flex-center justify-between'>
|
||||
<span>{header}</span>
|
||||
<div
|
||||
onClick={() => toggleSearch()}
|
||||
className=" flex items-center justify-center bg-white cursor-pointer"
|
||||
>
|
||||
<Icon name={ showSearch ? 'close' : 'search'} size="18" />
|
||||
</div>
|
||||
</div>
|
||||
{showSearch && (
|
||||
<div className="flex items-center mt-2">
|
||||
<Input
|
||||
autoFocus
|
||||
type="text"
|
||||
placeholder="Filter Events"
|
||||
className="absolute inset-0 w-full"
|
||||
className="inset-0 w-full"
|
||||
name="query"
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
style={{ height: '32px' }}
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div
|
||||
onClick={() => { setShowSearch(!showSearch); clearSearch() }}
|
||||
className="flex items-center justify-center cursor-pointer absolute right-0"
|
||||
style={{ height: '30px', width: '32px' }}
|
||||
>
|
||||
<Icon name={'close'} size="16" color="teal" />
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
header
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
{ !showSearch &&
|
||||
<div
|
||||
onClick={() => setShowSearch(!showSearch)}
|
||||
className="border rounded flex items-center justify-center bg-white cursor-pointer"
|
||||
style={{ height: '32px', width: '32px' }}
|
||||
>
|
||||
<Icon name={ showSearch ? 'close' : 'search'} size="12" color="teal" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -190,20 +190,20 @@ export default class EventsBlock extends React.PureComponent {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div className={ cn(styles.header, 'p-3') }>
|
||||
<div className={ cn(styles.header, 'p-4') }>
|
||||
<div className={ cn(styles.hAndProgress, 'mt-3') }>
|
||||
<EventSearch
|
||||
onChange={this.write}
|
||||
clearSearch={this.clearSearch}
|
||||
value={query}
|
||||
header={
|
||||
<div className="text-lg">{ `User Events (${ events.size })` }</div>
|
||||
<div className="text-xl">User Events <span className="color-gray-medium">{ events.size }</span></div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={ cn("flex-1 px-3 pb-3", styles.eventsList) }
|
||||
className={ cn("flex-1 px-4 pb-4", styles.eventsList) }
|
||||
id="eventList"
|
||||
data-openreplay-masked
|
||||
onMouseOver={ this.onMouseOver }
|
||||
|
|
|
|||
|
|
@ -1,55 +1,45 @@
|
|||
import React, { useCallback, useState } from 'react';
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { NoContent, IconButton, Popup } from 'UI';
|
||||
import withToggle from 'HOCs/withToggle';
|
||||
import MetadataItem from './MetadataItem';
|
||||
import stl from './metadata.module.css';
|
||||
import cn from 'classnames';
|
||||
|
||||
export default connect(state => ({
|
||||
metadata: state.getIn([ 'sessions', 'current', 'metadata' ]),
|
||||
}))(function Metadata ({ metadata }) {
|
||||
const [ visible, setVisible ] = useState(false);
|
||||
metadata = {
|
||||
test: 'a',
|
||||
dealership: 'very test wow',
|
||||
"bklajsdlkas-123": 123123,
|
||||
test: 'a',
|
||||
dealership: 'very test wow',
|
||||
"bklajsdlkas-123": 123123,
|
||||
test: 'a',
|
||||
dealership: 'very test wow',
|
||||
"bklajsdlkas-123": 123123,
|
||||
test: 'a',
|
||||
dealership: 'very test wow',
|
||||
"bklajsdlkas-123": 123123,
|
||||
test: 'a',
|
||||
dealership: 'very test wow',
|
||||
"bklajsdlkas-123": 123123,
|
||||
test: 'a',
|
||||
dealership: 'very test wow',
|
||||
"bklajsdlkas-123": 123123,
|
||||
}
|
||||
|
||||
const metaLenth = Object.keys(metadata).length;
|
||||
const toggle = useCallback(() => metaLenth > 0 && setVisible(v => !v), []);
|
||||
|
||||
|
||||
if (metaLenth === 0) {
|
||||
return (
|
||||
(<span className="text-sm color-gray-medium">Check <a href="https://docs.openreplay.com/installation/metadata" target="_blank" className="link">how to use Metadata</a> if you haven’t yet done so.</span>)
|
||||
)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Popup
|
||||
content={
|
||||
<div className="p-2">
|
||||
Check <a href="https://docs.openreplay.com/installation/metadata" target="_blank" className="link">how to use Metadata</a> if you haven’t yet done so.
|
||||
</div>
|
||||
}
|
||||
on="click"
|
||||
disabled={metaLenth > 0}
|
||||
size="tiny"
|
||||
inverted
|
||||
position="top center"
|
||||
>
|
||||
<IconButton
|
||||
className={cn("w-full", { 'opacity-25' : metaLenth === 0 })}
|
||||
onClick={ toggle }
|
||||
icon="id-card"
|
||||
plain
|
||||
label="Metadata"
|
||||
primaryText
|
||||
active={ visible }
|
||||
id="metadata-button"
|
||||
// disabled={ metadata.length === 0 }
|
||||
/>
|
||||
</Popup>
|
||||
{ visible &&
|
||||
<div className={ stl.modal } >
|
||||
<NoContent show={ metaLenth === 0 } size="small">
|
||||
{ Object.keys(metadata).map((key) => {
|
||||
// const key = Object.keys(i)[0]
|
||||
const value = metadata[key]
|
||||
return <MetadataItem item={ { value, key } } key={ key } />
|
||||
}) }
|
||||
</NoContent>
|
||||
</div>
|
||||
}
|
||||
</>
|
||||
<div>
|
||||
{ Object.keys(metadata).map((key) => {
|
||||
// const key = Object.keys(i)[0]
|
||||
const value = metadata[key]
|
||||
return <MetadataItem item={ { value, key } } key={ key } />
|
||||
}) }
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
.eventsBlock {
|
||||
width: 270px;
|
||||
/* padding: 0 10px; */
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.header {
|
||||
/* height: 40px; */
|
||||
/* margin-bottom: 15px; */
|
||||
padding-left: 2px;
|
||||
/* padding-right: 0px; */
|
||||
|
||||
|
||||
& .hAndProgress {
|
||||
display:flex;
|
||||
justify-content: space-between;
|
||||
|
|
@ -23,7 +19,7 @@
|
|||
background: #ffcc99;
|
||||
}
|
||||
& :global(.progress) {
|
||||
font-size: 9px;
|
||||
font-size: 9px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -70,5 +66,3 @@
|
|||
color: $gray-medium;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ export default class Player extends React.PureComponent {
|
|||
{!live && !fullscreen && <EventsToggleButton /> }
|
||||
<div className="relative flex-1 overflow-hidden">
|
||||
<Overlay nextId={nextId} togglePlay={PlayerControls.togglePlay} closedLive={closedLive} />
|
||||
<div
|
||||
<div
|
||||
className={ stl.screenWrapper }
|
||||
ref={ this.screenWrapper }
|
||||
ref={ this.screenWrapper }
|
||||
/>
|
||||
</div>
|
||||
<Controls
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import React from 'react';
|
||||
import cn from "classnames";
|
||||
import { connect } from 'react-redux';
|
||||
import { scale as scalePlayerScreen } from 'Player';
|
||||
import {
|
||||
import { scale as scalePlayerScreen } from 'Player';
|
||||
import {
|
||||
NONE,
|
||||
CONSOLE,
|
||||
NETWORK,
|
||||
|
|
@ -28,26 +28,32 @@ import Fetch from './Fetch';
|
|||
import Exceptions from './Exceptions/Exceptions';
|
||||
import LongTasks from './LongTasks';
|
||||
import Inspector from './Inspector';
|
||||
import styles from './playerBlock.module.css';
|
||||
|
||||
import styles from './playerBlock.css';
|
||||
import SubHeader from "./SubHeader";
|
||||
|
||||
@connect(state => ({
|
||||
fullscreen: state.getIn([ 'components', 'player', 'fullscreen' ]),
|
||||
bottomBlock: state.getIn([ 'components', 'player', 'bottomBlock' ]),
|
||||
sessionId: state.getIn([ 'sessions', 'current', 'sessionId' ]),
|
||||
disabled: state.getIn([ 'components', 'targetDefiner', 'inspectorMode' ]),
|
||||
}))
|
||||
export default class PlayerBlock extends React.PureComponent {
|
||||
componentDidUpdate(prevProps) {
|
||||
if ([ prevProps.bottomBlock, this.props.bottomBlock ].includes(NONE) ||
|
||||
if ([ prevProps.bottomBlock, this.props.bottomBlock ].includes(NONE) ||
|
||||
prevProps.fullscreen !== this.props.fullscreen) {
|
||||
scalePlayerScreen();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { fullscreen, bottomBlock } = this.props;
|
||||
const { fullscreen, bottomBlock, sessionId, disabled } = this.props;
|
||||
|
||||
return (
|
||||
<div className={ cn(styles.playerBlock, "flex flex-col") }>
|
||||
<SubHeader
|
||||
sessionId={sessionId}
|
||||
disabled={disabled}
|
||||
/>
|
||||
<Player
|
||||
className="flex-1"
|
||||
bottomBlockIsActive={ !fullscreen && bottomBlock !== NONE }
|
||||
|
|
@ -60,7 +66,7 @@ export default class PlayerBlock extends React.PureComponent {
|
|||
{ bottomBlock === NETWORK &&
|
||||
<Network />
|
||||
}
|
||||
{ bottomBlock === STACKEVENTS &&
|
||||
{ bottomBlock === STACKEVENTS &&
|
||||
<StackEvents />
|
||||
}
|
||||
{ bottomBlock === STORAGE &&
|
||||
|
|
@ -72,10 +78,10 @@ export default class PlayerBlock extends React.PureComponent {
|
|||
{ bottomBlock === PERFORMANCE &&
|
||||
<ConnectedPerformance />
|
||||
}
|
||||
{ bottomBlock === GRAPHQL &&
|
||||
{ bottomBlock === GRAPHQL &&
|
||||
<GraphQL />
|
||||
}
|
||||
{ bottomBlock === FETCH &&
|
||||
{ bottomBlock === FETCH &&
|
||||
<Fetch />
|
||||
}
|
||||
{ bottomBlock === EXCEPTIONS &&
|
||||
|
|
|
|||
|
|
@ -124,33 +124,8 @@ export default class PlayerBlockHeader extends React.PureComponent {
|
|||
|
||||
<SessionMetaList className="" metaList={_metaList} maxLength={2} />
|
||||
|
||||
<div className={ stl.divider } />
|
||||
{ isAssist && <AssistActions userId={userId} /> }
|
||||
{ !isAssist && (
|
||||
<>
|
||||
<Autoplay />
|
||||
<div className={ stl.divider } />
|
||||
<Bookmark sessionId={sessionId} favorite={favorite} />
|
||||
<div className={ stl.divider } />
|
||||
<SharePopup
|
||||
entity="sessions"
|
||||
id={ sessionId }
|
||||
showCopyLink={true}
|
||||
trigger={
|
||||
<Button
|
||||
// className="mr-2"
|
||||
// tooltip="Share Session"
|
||||
// tooltipPosition="top right"
|
||||
disabled={ disabled }
|
||||
icon={ 'share-alt' }
|
||||
variant="text-primary"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* { !isAssist && jiraConfig && jiraConfig.token && <Issues sessionId={ sessionId } /> } */}
|
||||
{ <Issues sessionId={ sessionId } /> }
|
||||
{ !isAssist && jiraConfig && jiraConfig.token && <Issues sessionId={ sessionId } /> }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
46
frontend/app/components/Session_/Subheader.tsx
Normal file
46
frontend/app/components/Session_/Subheader.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import React from 'react';
|
||||
import { Icon } from 'UI';
|
||||
import Autoplay from './Autoplay';
|
||||
import Bookmark from 'Shared/Bookmark'
|
||||
import SharePopup from '../shared/SharePopup/SharePopup';
|
||||
|
||||
function SubHeader(props) {
|
||||
const isAssist = window.location.pathname.includes('/assist/');
|
||||
|
||||
if (isAssist) return null;
|
||||
return (
|
||||
<div className="w-full p-4">
|
||||
<div className="ml-auto flex items-center color-gray-medium" style={{ width: 'max-content' }}>
|
||||
<div className="cursor-pointer">
|
||||
<SharePopup
|
||||
entity="sessions"
|
||||
id={ props.sessionId }
|
||||
showCopyLink={true}
|
||||
trigger={
|
||||
<div className="flex items-center">
|
||||
<Icon
|
||||
className="mr-2"
|
||||
disabled={ props.disabled }
|
||||
name="share-alt"
|
||||
size="16"
|
||||
plain
|
||||
/>
|
||||
<span>Share</span>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mx-4">
|
||||
<Bookmark />
|
||||
</div>
|
||||
<div>
|
||||
<Autoplay />
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default React.memo(SubHeader)
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import { Popup, Button } from 'UI'
|
||||
import { Popup, Button, Icon } from 'UI'
|
||||
import { toggleFavorite } from 'Duck/sessions'
|
||||
import { connect } from 'react-redux'
|
||||
import { toast } from 'react-toastify';
|
||||
|
|
@ -10,11 +10,11 @@ interface Props {
|
|||
sessionId: any,
|
||||
isEnterprise: Boolean
|
||||
}
|
||||
function Bookmark(props : Props ) {
|
||||
function Bookmark(props : Props ) {
|
||||
const { sessionId, favorite, isEnterprise } = props;
|
||||
const [isFavorite, setIsFavorite] = useState(favorite);
|
||||
const ADDED_MESSAGE = isEnterprise ? 'Session added to vault' : 'Session added to your favorites';
|
||||
const REMOVED_MESSAGE = isEnterprise ? 'Session removed from vault' : 'Session removed from your favorites';
|
||||
const REMOVED_MESSAGE = isEnterprise ? 'Session removed from vault' : 'Session removed from your favorites';
|
||||
const TOOLTIP_TEXT_ADD = isEnterprise ? 'Add to vault' : 'Add to favorites';
|
||||
const TOOLTIP_TEXT_REMOVE = isEnterprise ? 'Remove from vault' : 'Remove from favorites';
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ function Bookmark(props : Props ) {
|
|||
}
|
||||
|
||||
return (
|
||||
<Popup
|
||||
<Popup
|
||||
delay={500}
|
||||
content={isFavorite ? TOOLTIP_TEXT_REMOVE : TOOLTIP_TEXT_ADD}
|
||||
hideOnClick={true}
|
||||
|
|
@ -42,9 +42,11 @@ function Bookmark(props : Props ) {
|
|||
>
|
||||
<Button
|
||||
onClick={ toggleFavorite }
|
||||
variant="text-primary"
|
||||
icon={isFavorite ? ACTIVE_ICON : INACTIVE_ICON}
|
||||
/>
|
||||
data-favourite={ isFavorite }
|
||||
>
|
||||
<Icon name={ isFavorite ? ACTIVE_ICON : INACTIVE_ICON } color={isFavorite ? "teal" : undefined} size="16" />
|
||||
<span className="ml-2">{isEnterprise ? 'Vault' : 'Bookmark'}</span>
|
||||
</Button>
|
||||
</Popup>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,18 @@ export default ({
|
|||
className = '',
|
||||
checked,
|
||||
label = '',
|
||||
plain,
|
||||
}) => (
|
||||
<div className={ className }>
|
||||
<label className={styles.label}>
|
||||
<div className={ styles.switch }>
|
||||
<div className={ plain ? styles.switchPlain : styles.switch }>
|
||||
<input
|
||||
type={ styles.checkbox }
|
||||
onClick={ onChange }
|
||||
name={ name }
|
||||
checked={ checked }
|
||||
/>
|
||||
<span className={ `${ styles.slider } ${ checked ? styles.checked : '' }` } />
|
||||
<span className={ `${ plain ? styles.sliderPlain : styles.slider } ${ checked ? styles.checked : '' }` } />
|
||||
</div>
|
||||
{ label && <span>{ label }</span> }
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -59,3 +59,39 @@
|
|||
.slider.checked:before {
|
||||
/* transform: translateX(15px); */
|
||||
}
|
||||
|
||||
.switchPlain {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 25px;
|
||||
height: 12px;
|
||||
}
|
||||
.switchPlain input {
|
||||
display:none;
|
||||
}
|
||||
.sliderPlain {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: #ccc !important; /* postss reset is bad */
|
||||
transition: .4s;
|
||||
border-radius: 34px !important;
|
||||
}
|
||||
.sliderPlain:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
left: 2px;
|
||||
bottom: 1px;
|
||||
background: white;
|
||||
transition: .4s;
|
||||
border-radius: 50%;
|
||||
}
|
||||
.sliderPlain.checked:before {
|
||||
transform: translateX(11px);
|
||||
background: $teal;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue