Merge pull request #13500 from overleaf/ii-review-panel-migration-nav

[web] Create review panel navigation

GitOrigin-RevId: abed4171e9fd52de2f137a6cf7456791bc2ca161
This commit is contained in:
ilkin-overleaf
2023-06-19 17:07:51 +03:00
committed by Copybot
parent 2ab0779374
commit 423f2604db
10 changed files with 181 additions and 58 deletions

View File

@@ -175,6 +175,7 @@
"created": "",
"created_at": "",
"creating": "",
"current_file": "",
"current_password": "",
"currently_seeing_only_24_hrs_history": "",
"currently_subscribed_to_plan": "",
@@ -655,6 +656,7 @@
"overleaf": "",
"overleaf_history_system": "",
"overleaf_labs": "",
"overview": "",
"overwrite": "",
"owned_by_x": "",
"owner": "",

View File

@@ -3,34 +3,42 @@ import Container from './container'
function CurrentFileContainer() {
return (
<Container>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Et malesuada fames ac
turpis egestas integer eget aliquet nibh. Et leo duis ut diam quam nulla
porttitor massa id. Risus quis varius quam quisque id diam vel quam
elementum. Nibh venenatis cras sed felis. Sit amet commodo nulla facilisi
nullam vehicula ipsum a arcu. Dui ut ornare lectus sit amet est placerat
in. Aliquam ultrices sagittis orci a. Leo a diam sollicitudin tempor id eu
nisl nunc mi. Quis ipsum suspendisse ultrices gravida dictum fusce. Ut
etiam sit amet nisl purus in mollis nunc sed. Rhoncus est pellentesque
elit ullamcorper dignissim cras. Faucibus turpis in eu mi bibendum. Proin
libero nunc consequat interdum. Ac placerat vestibulum lectus mauris
ultrices eros in cursus turpis. Ac felis donec et odio. Nullam ac tortor
vitae purus faucibus. Consectetur lorem donec massa sapien faucibus et
molestie. Praesent elementum facilisis leo vel fringilla est ullamcorper
eget nulla. Adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus
urna. Cursus metus aliquam eleifend mi in nulla posuere sollicitudin
aliquam. Eget nullam non nisi est sit amet facilisis magna. Donec
adipiscing tristique risus nec feugiat in fermentum posuere. Gravida
rutrum quisque non tellus orci ac auctor augue. Euismod in pellentesque
massa placerat duis ultricies lacus. Pellentesque diam volutpat commodo
sed egestas. Tempus iaculis urna id volutpat lacus laoreet. Lorem ipsum
dolor sit amet consectetur. Tincidunt id aliquet risus feugiat in ante
metus. Risus ultricies tristique nulla aliquet enim tortor at auctor urna.
Purus in mollis nunc sed. In ante metus dictum at. Magna eget est lorem
ipsum dolor sit. Fusce id velit ut tortor pretium viverra. Augue neque
gravida in fermentum et sollicitudin ac. Et malesuada fames ac turpis.
Felis bibendum ut tristique et egestas quis ipsum suspendisse ultrices.
Varius vel pharetra vel turpis nunc eget.
<div
id="review-panel-current-file"
role="tabpanel"
tabIndex={0}
aria-labelledby="review-panel-tab-current-file"
>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Et malesuada fames
ac turpis egestas integer eget aliquet nibh. Et leo duis ut diam quam
nulla porttitor massa id. Risus quis varius quam quisque id diam vel
quam elementum. Nibh venenatis cras sed felis. Sit amet commodo nulla
facilisi nullam vehicula ipsum a arcu. Dui ut ornare lectus sit amet est
placerat in. Aliquam ultrices sagittis orci a. Leo a diam sollicitudin
tempor id eu nisl nunc mi. Quis ipsum suspendisse ultrices gravida
dictum fusce. Ut etiam sit amet nisl purus in mollis nunc sed. Rhoncus
est pellentesque elit ullamcorper dignissim cras. Faucibus turpis in eu
mi bibendum. Proin libero nunc consequat interdum. Ac placerat
vestibulum lectus mauris ultrices eros in cursus turpis. Ac felis donec
et odio. Nullam ac tortor vitae purus faucibus. Consectetur lorem donec
massa sapien faucibus et molestie. Praesent elementum facilisis leo vel
fringilla est ullamcorper eget nulla. Adipiscing vitae proin sagittis
nisl rhoncus mattis rhoncus urna. Cursus metus aliquam eleifend mi in
nulla posuere sollicitudin aliquam. Eget nullam non nisi est sit amet
facilisis magna. Donec adipiscing tristique risus nec feugiat in
fermentum posuere. Gravida rutrum quisque non tellus orci ac auctor
augue. Euismod in pellentesque massa placerat duis ultricies lacus.
Pellentesque diam volutpat commodo sed egestas. Tempus iaculis urna id
volutpat lacus laoreet. Lorem ipsum dolor sit amet consectetur.
Tincidunt id aliquet risus feugiat in ante metus. Risus ultricies
tristique nulla aliquet enim tortor at auctor urna. Purus in mollis nunc
sed. In ante metus dictum at. Magna eget est lorem ipsum dolor sit.
Fusce id velit ut tortor pretium viverra. Augue neque gravida in
fermentum et sollicitudin ac. Et malesuada fames ac turpis. Felis
bibendum ut tristique et egestas quis ipsum suspendisse ultrices. Varius
vel pharetra vel turpis nunc eget.
</div>
</Container>
)
}

View File

@@ -1,7 +1,49 @@
import { useTranslation } from 'react-i18next'
import classnames from 'classnames'
import Icon from '../../../../shared/components/icon'
import {
useReviewPanelValueContext,
useReviewPanelUpdaterFnsContext,
} from '../../context/review-panel/review-panel-context'
import { isCurrentFileView, isOverviewView } from '../../utils/sub-view'
function Nav() {
const { t } = useTranslation()
const { subView } = useReviewPanelValueContext()
const { handleSetSubview } = useReviewPanelUpdaterFnsContext()
return (
<div className="rp-nav" style={{ background: '#8eaeb6', padding: '5px' }}>
Nav
<div className="rp-nav" role="tablist">
<button
type="button"
id="review-panel-tab-current-file"
role="tab"
aria-selected={isCurrentFileView(subView)}
aria-controls="review-panel-current-file"
tabIndex={isCurrentFileView(subView) ? 0 : -1}
className={classnames('rp-nav-item', {
'rp-nav-item-active': isCurrentFileView(subView),
})}
onClick={() => handleSetSubview('cur_file')}
>
<Icon type="file-text-o" />
<span className="rp-nav-label">{t('current_file')}</span>
</button>
<button
type="button"
id="review-panel-tab-overview"
role="tab"
aria-selected={isOverviewView(subView)}
aria-controls="review-panel-overview"
tabIndex={isOverviewView(subView) ? 0 : -1}
className={classnames('rp-nav-item', {
'rp-nav-item-active': isOverviewView(subView),
})}
onClick={() => handleSetSubview('overview')}
>
<Icon type="list" />
<span className="rp-nav-label">{t('overview')}</span>
</button>
</div>
)
}

View File

@@ -3,7 +3,29 @@ import Container from './container'
function OverviewContainer() {
return (
<Container>
<em>ReviewPanelOverviewContainer</em>
<div
id="review-panel-overview"
role="tabpanel"
tabIndex={0}
aria-labelledby="review-panel-tab-overview"
>
Faucibus turpis in eu mi bibendum. Proin libero nunc consequat interdum.
Ac placerat vestibulum lectus mauris ultrices eros in cursus turpis. Ac
felis donec et odio. Nullam ac tortor vitae purus faucibus. Consectetur
lorem donec massa sapien faucibus et molestie. Praesent elementum
facilisis leo vel fringilla est ullamcorper eget nulla. Adipiscing vitae
proin sagittis nisl rhoncus mattis rhoncus urna. Cursus metus aliquam
eleifend mi in nulla posuere sollicitudin aliquam. Eget nullam non nisi
est sit amet facilisis magna. Donec adipiscing tristique risus nec
feugiat in fermentum posuere. Gravida rutrum quisque non tellus orci ac
auctor augue. Euismod in pellentesque massa placerat duis ultricies
lacus. Pellentesque diam volutpat commodo sed egestas. Tempus iaculis
urna id volutpat lacus laoreet. Lorem ipsum dolor sit amet consectetur.
Tincidunt id aliquet risus feugiat in ante metus. Risus ultricies
tristique nulla aliquet enim tortor at auctor urna. Purus in mollis nunc
sed. In ante metus dictum at. Magna eget est lorem ipsum dolor sit.
Fusce id velit ut tortor pretium viverra.
</div>
</Container>
)
}

View File

@@ -6,6 +6,7 @@ import {
} from '../../context/review-panel/review-panel-context'
import CurrentFileContainer from './current-file-container'
import OverviewContainer from './overview-container'
import { isCurrentFileView } from '../../utils/sub-view'
type ReviewPanelViewProps = {
parentDomNode: Element
@@ -16,7 +17,7 @@ function ReviewPanelView({ parentDomNode }: ReviewPanelViewProps) {
return ReactDOM.createPortal(
<>
{subView === 'cur_file' ? (
{isCurrentFileView(subView) ? (
<CurrentFileContainer />
) : (
<OverviewContainer />

View File

@@ -1,7 +1,9 @@
import { useMemo } from 'react'
import { useMemo, useCallback } from 'react'
import useScopeValue from '../../../../../shared/hooks/use-scope-value'
import { ReviewPanelState } from '../types/review-panel-state'
import { sendMB } from '../../../../../infrastructure/event-tracking'
import * as ReviewPanel from '../types/review-panel-state'
import { SubView } from '../../../../../../../types/review-panel'
function useAngularReviewPanelState(): ReviewPanelState {
const [subView, setSubView] = useScopeValue<ReviewPanel.Value<'subView'>>(
@@ -50,6 +52,14 @@ function useAngularReviewPanelState(): ReviewPanelState {
const [toggleReviewPanel] =
useScopeValue<ReviewPanel.Value<'toggleReviewPanel'>>('toggleReviewPanel')
const handleSetSubview = useCallback(
(subView: SubView) => {
setSubView(subView)
sendMB('rp-subview-change', { subView })
},
[setSubView]
)
const values = useMemo<ReviewPanelState['values']>(
() => ({
collapsed,
@@ -87,11 +97,11 @@ function useAngularReviewPanelState(): ReviewPanelState {
const updaterFns = useMemo<ReviewPanelState['updaterFns']>(
() => ({
setSubView,
handleSetSubview,
setCollapsed,
setShouldCollapse,
}),
[setSubView, setCollapsed, setShouldCollapse]
[handleSetSubview, setCollapsed, setShouldCollapse]
)
return { values, updaterFns }

View File

@@ -27,12 +27,10 @@ export interface ReviewPanelState {
toggleReviewPanel: () => void
}
updaterFns: {
handleSetSubview: (subView: SubView) => void
setCollapsed: React.Dispatch<
React.SetStateAction<ReviewPanelState['values']['collapsed']>
>
setSubView: React.Dispatch<
React.SetStateAction<ReviewPanelState['values']['subView']>
>
setShouldCollapse: React.Dispatch<
React.SetStateAction<ReviewPanelState['values']['shouldCollapse']>
>

View File

@@ -0,0 +1,4 @@
import { SubView } from '../../../../../types/review-panel'
export const isCurrentFileView = (view: SubView) => view === 'cur_file'
export const isOverviewView = (view: SubView) => view === 'overview'

View File

@@ -56,7 +56,7 @@
}
.rp-collapse-arrow() {
display: inline-block;
display: inline-flex;
transform: rotateZ(0deg);
transition: transform 0.15s ease;
&-on {
@@ -1214,14 +1214,6 @@ button when (@is-overleaf-light = true) {
box-sizing: content-box;
flex-direction: column;
.review-panel-toolbar {
& .review-panel-toolbar-collapse-button {
border: none;
background: none;
padding: 0;
}
}
.review-panel-toggler {
display: flex;
flex-direction: column;
@@ -1235,6 +1227,22 @@ button when (@is-overleaf-light = true) {
}
}
.review-panel-toolbar {
position: sticky;
top: 0;
.review-panel-toolbar-collapse-button {
border: none;
background: none;
padding: 0;
}
}
.rp-nav {
position: sticky;
bottom: 0;
}
.rp-state-current-file & {
.review-panel-tools {
display: flex;
@@ -1246,19 +1254,9 @@ button when (@is-overleaf-light = true) {
left: 0;
right: 0;
}
.review-panel-toolbar {
position: sticky;
top: 0;
}
.rp-nav {
position: sticky;
bottom: 0;
}
}
.rp-state-overview {
.rp-state-overview & {
position: sticky;
top: 0;
display: flex;
@@ -1266,6 +1264,9 @@ button when (@is-overleaf-light = true) {
}
.rp-nav-item {
border-right: 0;
border-bottom: 0;
border-left: 0;
background: none;
}

View File

@@ -131,4 +131,39 @@ describe('<ReviewPanel />', function () {
})
})
})
describe('navigation', function () {
it('renders navigation', function () {
cy.get('@review-panel').within(() => {
cy.findByRole('tab', { name: /current file/i })
cy.findByRole('tab', { name: /overview/i })
})
})
it('selects the active tab', function () {
cy.get('@review-panel').within(() => {
cy.findByRole('tab', { name: /current file/i }).should(
'have.attr',
'aria-selected',
'true'
)
cy.findByRole('tab', { name: /overview/i }).should(
'have.attr',
'aria-selected',
'false'
)
cy.findByRole('tab', { name: /overview/i }).click()
cy.findByRole('tab', { name: /current file/i }).should(
'have.attr',
'aria-selected',
'false'
)
cy.findByRole('tab', { name: /overview/i }).should(
'have.attr',
'aria-selected',
'true'
)
})
})
})
})