diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index dbb16c6bda..90abf207b9 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -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": "", diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx index c1b4f08143..78df6da40b 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx +++ b/services/web/frontend/js/features/source-editor/components/review-panel/current-file-container.tsx @@ -3,34 +3,42 @@ import Container from './container' function CurrentFileContainer() { return ( - 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. +
+ 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. +
) } diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/nav.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/nav.tsx index d5c146bb11..bd267dcec9 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/nav.tsx +++ b/services/web/frontend/js/features/source-editor/components/review-panel/nav.tsx @@ -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 ( -
- Nav +
+ +
) } diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/overview-container.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/overview-container.tsx index 744d34c4d2..ca61d4c728 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/overview-container.tsx +++ b/services/web/frontend/js/features/source-editor/components/review-panel/overview-container.tsx @@ -3,7 +3,29 @@ import Container from './container' function OverviewContainer() { return ( - ReviewPanelOverviewContainer +
+ 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. +
) } diff --git a/services/web/frontend/js/features/source-editor/components/review-panel/review-panel.tsx b/services/web/frontend/js/features/source-editor/components/review-panel/review-panel.tsx index ce006c450f..d6547820d8 100644 --- a/services/web/frontend/js/features/source-editor/components/review-panel/review-panel.tsx +++ b/services/web/frontend/js/features/source-editor/components/review-panel/review-panel.tsx @@ -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) ? ( ) : ( diff --git a/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts b/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts index 93ef3ea4de..030ba1deef 100644 --- a/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts +++ b/services/web/frontend/js/features/source-editor/context/review-panel/hooks/use-angular-review-panel-state.ts @@ -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>( @@ -50,6 +52,14 @@ function useAngularReviewPanelState(): ReviewPanelState { const [toggleReviewPanel] = useScopeValue>('toggleReviewPanel') + const handleSetSubview = useCallback( + (subView: SubView) => { + setSubView(subView) + sendMB('rp-subview-change', { subView }) + }, + [setSubView] + ) + const values = useMemo( () => ({ collapsed, @@ -87,11 +97,11 @@ function useAngularReviewPanelState(): ReviewPanelState { const updaterFns = useMemo( () => ({ - setSubView, + handleSetSubview, setCollapsed, setShouldCollapse, }), - [setSubView, setCollapsed, setShouldCollapse] + [handleSetSubview, setCollapsed, setShouldCollapse] ) return { values, updaterFns } diff --git a/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts b/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts index caf1a7b76a..b2a12add75 100644 --- a/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts +++ b/services/web/frontend/js/features/source-editor/context/review-panel/types/review-panel-state.ts @@ -27,12 +27,10 @@ export interface ReviewPanelState { toggleReviewPanel: () => void } updaterFns: { + handleSetSubview: (subView: SubView) => void setCollapsed: React.Dispatch< React.SetStateAction > - setSubView: React.Dispatch< - React.SetStateAction - > setShouldCollapse: React.Dispatch< React.SetStateAction > diff --git a/services/web/frontend/js/features/source-editor/utils/sub-view.ts b/services/web/frontend/js/features/source-editor/utils/sub-view.ts new file mode 100644 index 0000000000..b1a952dd57 --- /dev/null +++ b/services/web/frontend/js/features/source-editor/utils/sub-view.ts @@ -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' diff --git a/services/web/frontend/stylesheets/app/editor/review-panel.less b/services/web/frontend/stylesheets/app/editor/review-panel.less index d5bf443e28..db3fb2b41f 100644 --- a/services/web/frontend/stylesheets/app/editor/review-panel.less +++ b/services/web/frontend/stylesheets/app/editor/review-panel.less @@ -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; } diff --git a/services/web/test/frontend/features/review-panel/review-panel.spec.tsx b/services/web/test/frontend/features/review-panel/review-panel.spec.tsx index 778fed13f3..dbed086cfa 100644 --- a/services/web/test/frontend/features/review-panel/review-panel.spec.tsx +++ b/services/web/test/frontend/features/review-panel/review-panel.spec.tsx @@ -131,4 +131,39 @@ describe('', 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' + ) + }) + }) + }) })