mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-14 06:03:45 +01:00
Merge pull request #35534 from overleaf/cd-share-sidenav-bar-with-library
[web] Share the dashboard sidebar with the library page GitOrigin-RevId: 5595746fef6698bee6a35ee7fc8be15743e2c620
This commit is contained in:
@@ -1027,6 +1027,7 @@ module.exports = {
|
||||
//
|
||||
createFileModes: [],
|
||||
devToolbar: [],
|
||||
dsNavLibraryLink: [],
|
||||
gitBridge: [],
|
||||
publishModalDropdownButton: [],
|
||||
publishModalToolbarButton: [],
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { OLDropdownItem } from '@/shared/components/ol/ol-dropdown-menu'
|
||||
import { ActivePage } from '../../util/navigation-state'
|
||||
|
||||
type Props = {
|
||||
activePage: 'library' | 'projects'
|
||||
activePage: ActivePage
|
||||
onProjectsClick?: () => void
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ export function Item({ filter, text, leadingIcon, onClick }: ItemProps) {
|
||||
}
|
||||
|
||||
return (
|
||||
<ProjectsFilterMenu filter={filter}>
|
||||
<ProjectsFilterMenu filter={filter} activePage="projects">
|
||||
{isActive => (
|
||||
<OLDropdownItem
|
||||
as="button"
|
||||
|
||||
@@ -95,7 +95,7 @@ export function ProjectListDsNav() {
|
||||
showCloseIcon
|
||||
/>
|
||||
<div className="project-list-wrapper">
|
||||
<SidebarDsNav />
|
||||
<SidebarDsNav activePage="projects" />
|
||||
<div className="project-ds-nav-content-and-messages">
|
||||
<div className="project-ds-nav-content">
|
||||
<div className="project-ds-nav-main">
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
import { Filter, useProjectListContext } from '../context/project-list-context'
|
||||
import { ActivePage } from '../util/navigation-state'
|
||||
|
||||
type ProjectsMenuFilterType = {
|
||||
children: (isActive: boolean) => React.ReactElement
|
||||
filter: Filter
|
||||
activePage: ActivePage
|
||||
}
|
||||
|
||||
function ProjectsFilterMenu({ children, filter }: ProjectsMenuFilterType) {
|
||||
function ProjectsFilterMenu({
|
||||
children,
|
||||
filter,
|
||||
activePage,
|
||||
}: ProjectsMenuFilterType) {
|
||||
const { filter: activeFilter, selectedTagId } = useProjectListContext()
|
||||
const isActive = selectedTagId === undefined && filter === activeFilter
|
||||
const isActive =
|
||||
selectedTagId === undefined &&
|
||||
filter === activeFilter &&
|
||||
activePage === 'projects'
|
||||
|
||||
return children(isActive)
|
||||
}
|
||||
|
||||
+28
-24
@@ -1,3 +1,4 @@
|
||||
import { JSXElementConstructor } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import classnames from 'classnames'
|
||||
import { Trash } from '@phosphor-icons/react'
|
||||
@@ -9,15 +10,20 @@ import { useScrolled } from '@/features/project-list/components/sidebar/use-scro
|
||||
import { SurveyWidgetDsNav } from '@/features/project-list/components/survey-widget-ds-nav'
|
||||
import { SidebarLowerSection } from '@/shared/components/sidebar/sidebar-lower-section'
|
||||
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
|
||||
import { DsNavPageSwitcher } from '@/shared/components/sidebar/ds-nav-page-switcher'
|
||||
import { DsNavOverleafLogo } from '@/shared/components/sidebar/ds-nav-overleaf-logo'
|
||||
import { useProjectListContext } from '@/features/project-list/context/project-list-context'
|
||||
import importOverleafModules from '../../../../../macros/import-overleaf-module.macro'
|
||||
import { ActivePage } from '../../util/navigation-state'
|
||||
|
||||
function SidebarDsNav() {
|
||||
function SidebarDsNav({ activePage }: { activePage: ActivePage }) {
|
||||
const { t } = useTranslation()
|
||||
const { show: showAddAffiliationWidget } = useAddAffiliation()
|
||||
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
|
||||
const { filter, selectedTagId, selectFilter } = useProjectListContext()
|
||||
const isTrashActive = selectedTagId === undefined && filter === 'trashed'
|
||||
const [dsNavLibraryLinkModule] = importOverleafModules('dsNavLibraryLink')
|
||||
const DsNavLibraryLink: JSXElementConstructor<{ active?: boolean }> =
|
||||
dsNavLibraryLinkModule?.import.default
|
||||
const { mousePos, getHandleProps, getTargetProps } = usePersistedResize({
|
||||
name: 'project-sidebar',
|
||||
})
|
||||
@@ -32,16 +38,7 @@ function SidebarDsNav() {
|
||||
},
|
||||
})}
|
||||
>
|
||||
{isLibraryEnabled && (
|
||||
<>
|
||||
<DsNavPageSwitcher
|
||||
activePage={isTrashActive ? undefined : 'projects'}
|
||||
showLogo={false}
|
||||
onProjectsClick={() => selectFilter('all')}
|
||||
/>
|
||||
<hr className="ds-nav-page-switcher-divider" />
|
||||
</>
|
||||
)}
|
||||
{isLibraryEnabled && activePage === 'library' && <DsNavOverleafLogo />}
|
||||
<nav
|
||||
className="flex-grow flex-shrink"
|
||||
aria-label={t('project_categories_tags')}
|
||||
@@ -57,7 +54,7 @@ function SidebarDsNav() {
|
||||
ref={containerRef}
|
||||
data-testid="project-list-sidebar-scroll"
|
||||
>
|
||||
<SidebarFilters />
|
||||
<SidebarFilters activePage={activePage} />
|
||||
{showAddAffiliationWidget && <hr />}
|
||||
<AddAffiliation />
|
||||
</div>
|
||||
@@ -70,17 +67,24 @@ function SidebarDsNav() {
|
||||
>
|
||||
<SidebarLowerSection showThemeToggle>
|
||||
{isLibraryEnabled && (
|
||||
<button
|
||||
type="button"
|
||||
className={classnames('ds-nav-page-switcher-item', {
|
||||
active: isTrashActive,
|
||||
})}
|
||||
aria-current={isTrashActive ? 'page' : undefined}
|
||||
onClick={() => selectFilter('trashed')}
|
||||
>
|
||||
<Trash size={24} />
|
||||
<span>{t('trash')}</span>
|
||||
</button>
|
||||
<>
|
||||
{DsNavLibraryLink && (
|
||||
<DsNavLibraryLink active={activePage === 'library'} />
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className={classnames('ds-nav-page-switcher-item', {
|
||||
active: isTrashActive,
|
||||
})}
|
||||
aria-current={isTrashActive ? 'page' : undefined}
|
||||
onClick={() => selectFilter('trashed')}
|
||||
>
|
||||
<Trash size={24} />
|
||||
<span className="ds-nav-page-switcher-item-label">
|
||||
{t('trash')}
|
||||
</span>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
<div className="project-list-sidebar-survey-wrapper">
|
||||
<SurveyWidgetDsNav />
|
||||
|
||||
+51
-9
@@ -1,4 +1,5 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import classNames from 'classnames'
|
||||
import {
|
||||
Filter,
|
||||
useProjectListContext,
|
||||
@@ -6,20 +7,36 @@ import {
|
||||
import TagsList from './tags-list'
|
||||
import ProjectsFilterMenu from '../projects-filter-menu'
|
||||
import { isSplitTestEnabled } from '@/utils/splitTestUtils'
|
||||
import { Folder } from '@phosphor-icons/react'
|
||||
import { ActivePage } from '../../util/navigation-state'
|
||||
|
||||
type SidebarFilterProps = {
|
||||
filter: Filter
|
||||
text: React.ReactNode
|
||||
activePage: ActivePage
|
||||
icon?: React.ReactNode
|
||||
}
|
||||
|
||||
export function SidebarFilter({ filter, text }: SidebarFilterProps) {
|
||||
export function SidebarFilter({
|
||||
filter,
|
||||
text,
|
||||
icon,
|
||||
activePage,
|
||||
}: SidebarFilterProps) {
|
||||
const { selectFilter } = useProjectListContext()
|
||||
|
||||
return (
|
||||
<ProjectsFilterMenu filter={filter}>
|
||||
<ProjectsFilterMenu filter={filter} activePage={activePage}>
|
||||
{isActive => (
|
||||
<li className={isActive ? 'active' : ''}>
|
||||
<button type="button" onClick={() => selectFilter(filter)}>
|
||||
<button
|
||||
className={classNames('sidebar-filter-button', {
|
||||
'sidebar-filter-button-with-icon': !!icon,
|
||||
})}
|
||||
type="button"
|
||||
onClick={() => selectFilter(filter)}
|
||||
>
|
||||
{icon && <span className="icon">{icon}</span>}
|
||||
{text}
|
||||
</button>
|
||||
</li>
|
||||
@@ -28,17 +45,42 @@ export function SidebarFilter({ filter, text }: SidebarFilterProps) {
|
||||
)
|
||||
}
|
||||
|
||||
export default function SidebarFilters() {
|
||||
export default function SidebarFilters({
|
||||
activePage,
|
||||
}: {
|
||||
activePage: ActivePage
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const isLibraryEnabled = isSplitTestEnabled('overleaf-library')
|
||||
return (
|
||||
<ul className="list-unstyled project-list-filters">
|
||||
<SidebarFilter filter="all" text={t('all_projects')} />
|
||||
<SidebarFilter filter="owned" text={t('your_projects')} />
|
||||
<SidebarFilter filter="shared" text={t('shared_with_you')} />
|
||||
<SidebarFilter filter="archived" text={t('archived_projects')} />
|
||||
<SidebarFilter
|
||||
activePage={activePage}
|
||||
filter="all"
|
||||
text={isLibraryEnabled ? t('projects') : t('all_projects')}
|
||||
icon={isLibraryEnabled && <Folder size={24} />}
|
||||
/>
|
||||
<SidebarFilter
|
||||
activePage={activePage}
|
||||
filter="owned"
|
||||
text={t('your_projects')}
|
||||
/>
|
||||
<SidebarFilter
|
||||
activePage={activePage}
|
||||
filter="shared"
|
||||
text={t('shared_with_you')}
|
||||
/>
|
||||
<SidebarFilter
|
||||
activePage={activePage}
|
||||
filter="archived"
|
||||
text={t('archived_projects')}
|
||||
/>
|
||||
{!isLibraryEnabled && (
|
||||
<SidebarFilter filter="trashed" text={t('trashed_projects')} />
|
||||
<SidebarFilter
|
||||
activePage={activePage}
|
||||
filter="trashed"
|
||||
text={t('trashed_projects')}
|
||||
/>
|
||||
)}
|
||||
<li aria-hidden="true">
|
||||
<hr />
|
||||
|
||||
@@ -34,6 +34,7 @@ import {
|
||||
getNavigationState,
|
||||
getNavigationUrl,
|
||||
migrateLegacyNavigationState,
|
||||
NavigationState,
|
||||
} from '../util/navigation-state'
|
||||
import {
|
||||
isArchivedOrTrashed,
|
||||
@@ -41,6 +42,7 @@ import {
|
||||
isLeavableProject,
|
||||
} from '../util/project'
|
||||
import { debugConsole } from '@/utils/debugging'
|
||||
import { useLocation } from '@/shared/hooks/use-location'
|
||||
|
||||
const MAX_PROJECT_PER_PAGE = 20
|
||||
|
||||
@@ -116,11 +118,18 @@ export const ProjectListContext = createContext<
|
||||
ProjectListContextValue | undefined
|
||||
>(undefined)
|
||||
|
||||
export type NavigationMode = 'filter-projects' | 'redirect-to-filtered-projects'
|
||||
|
||||
type ProjectListProviderProps = {
|
||||
children: ReactNode
|
||||
navigationMode?: NavigationMode
|
||||
}
|
||||
|
||||
export function ProjectListProvider({ children }: ProjectListProviderProps) {
|
||||
export function ProjectListProvider({
|
||||
children,
|
||||
navigationMode = 'filter-projects',
|
||||
}: ProjectListProviderProps) {
|
||||
const location = useLocation()
|
||||
const prefetchedProjectsBlob = getMeta('ol-prefetchedProjectsBlob')
|
||||
const [loadedProjects, setLoadedProjects] = useState<Project[]>(
|
||||
prefetchedProjectsBlob?.projects ?? []
|
||||
@@ -140,7 +149,12 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
|
||||
by: 'lastUpdated',
|
||||
order: 'desc',
|
||||
})
|
||||
const [initialNavigationState] = useState(getInitialNavigationState)
|
||||
const [initialNavigationState] = useState<NavigationState>(() => {
|
||||
if (navigationMode !== 'filter-projects') {
|
||||
return { type: 'filter', filter: 'all' }
|
||||
}
|
||||
return getInitialNavigationState()
|
||||
})
|
||||
const [filter, setFilter] = useState<Filter>(
|
||||
initialNavigationState.type === 'filter'
|
||||
? initialNavigationState.filter
|
||||
@@ -265,6 +279,7 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
|
||||
}, [sort])
|
||||
|
||||
useEffect(() => {
|
||||
if (navigationMode !== 'filter-projects') return
|
||||
const handlePopState = () => {
|
||||
const navigationState = getNavigationState(window.location.pathname)
|
||||
if (navigationState.type === 'tag') {
|
||||
@@ -278,13 +293,17 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
|
||||
}
|
||||
window.addEventListener('popstate', handlePopState)
|
||||
return () => window.removeEventListener('popstate', handlePopState)
|
||||
}, [])
|
||||
}, [navigationMode])
|
||||
|
||||
// Temporary: migrate the legacy local-storage navigation state to the URL on
|
||||
// first load. Safe to remove around September 2026 (see navigation-state.ts).
|
||||
// Only in 'filter-projects' mode: migrateLegacyNavigationState() clears the
|
||||
// stored state unconditionally, so running it on the library page would wipe
|
||||
// the dashboard's remembered filter before the migration could apply it.
|
||||
useEffect(() => {
|
||||
if (navigationMode !== 'filter-projects') return
|
||||
migrateLegacyNavigationState()
|
||||
}, [])
|
||||
}, [navigationMode])
|
||||
|
||||
const showAllProjects = useCallback(() => {
|
||||
setLoadMoreCount(0)
|
||||
@@ -361,30 +380,38 @@ export function ProjectListProvider({ children }: ProjectListProviderProps) {
|
||||
|
||||
const selectFilter = useCallback(
|
||||
(filter: Filter) => {
|
||||
const url = getNavigationUrl({ type: 'filter', filter })
|
||||
if (navigationMode === 'redirect-to-filtered-projects') {
|
||||
location.assign(url)
|
||||
return
|
||||
}
|
||||
setFilter(filter)
|
||||
setSelectedTagId(undefined)
|
||||
const selected = false
|
||||
selectOrUnselectAllProjects(selected)
|
||||
window.history.pushState(
|
||||
null,
|
||||
'',
|
||||
getNavigationUrl({ type: 'filter', filter })
|
||||
)
|
||||
window.history.pushState(null, '', url)
|
||||
},
|
||||
[selectOrUnselectAllProjects, setFilter, setSelectedTagId]
|
||||
[
|
||||
navigationMode,
|
||||
location,
|
||||
selectOrUnselectAllProjects,
|
||||
setFilter,
|
||||
setSelectedTagId,
|
||||
]
|
||||
)
|
||||
|
||||
const selectTag = useCallback(
|
||||
(tagId: string) => {
|
||||
const url = getNavigationUrl({ type: 'tag', tag: tagId })
|
||||
if (navigationMode === 'redirect-to-filtered-projects') {
|
||||
location.assign(url)
|
||||
return
|
||||
}
|
||||
setFilter('all')
|
||||
setSelectedTagId(tagId)
|
||||
window.history.pushState(
|
||||
null,
|
||||
'',
|
||||
getNavigationUrl({ type: 'tag', tag: tagId })
|
||||
)
|
||||
window.history.pushState(null, '', url)
|
||||
},
|
||||
[setSelectedTagId, setFilter]
|
||||
[navigationMode, location, setSelectedTagId, setFilter]
|
||||
)
|
||||
|
||||
const addTag = useCallback((tag: Tag) => {
|
||||
|
||||
@@ -3,6 +3,8 @@ import customLocalStorage from '../../../infrastructure/local-storage'
|
||||
|
||||
export const DASHBOARD_PATH = '/project'
|
||||
|
||||
export type ActivePage = 'library' | 'projects'
|
||||
|
||||
export type NavigationState =
|
||||
| { type: 'filter'; filter: Filter }
|
||||
| { type: 'tag'; tag: string }
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
|
||||
import getMeta from '@/utils/meta'
|
||||
import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg'
|
||||
import overleafLogoDark from '@/shared/svgs/overleaf-a-ds-solution-mallard-dark.svg'
|
||||
|
||||
export function DsNavOverleafLogo() {
|
||||
const appName = getMeta('ol-ExposedSettings')?.appName ?? 'Overleaf'
|
||||
const activeOverallTheme = useActiveOverallTheme()
|
||||
|
||||
return (
|
||||
<div className="ds-nav-page-switcher-logo">
|
||||
<a href="/" aria-label={appName}>
|
||||
<img
|
||||
src={activeOverallTheme === 'dark' ? overleafLogoDark : overleafLogo}
|
||||
alt="Overleaf, A Digital Science Solution"
|
||||
height="59"
|
||||
width="130"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { BookBookmark, Folder } from '@phosphor-icons/react'
|
||||
import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme'
|
||||
import getMeta from '@/utils/meta'
|
||||
import overleafLogo from '@/shared/svgs/overleaf-a-ds-solution-mallard.svg'
|
||||
import overleafLogoDark from '@/shared/svgs/overleaf-a-ds-solution-mallard-dark.svg'
|
||||
|
||||
type ActivePage = 'library' | 'projects'
|
||||
|
||||
export function DsNavPageSwitcher({
|
||||
activePage,
|
||||
showLogo = true,
|
||||
onLibraryClick,
|
||||
onProjectsClick,
|
||||
}: {
|
||||
activePage: ActivePage | undefined
|
||||
showLogo?: boolean
|
||||
onLibraryClick?: React.MouseEventHandler
|
||||
onProjectsClick?: React.MouseEventHandler
|
||||
}) {
|
||||
const { t } = useTranslation()
|
||||
const appName = getMeta('ol-ExposedSettings')?.appName ?? 'Overleaf'
|
||||
const activeOverallTheme = useActiveOverallTheme()
|
||||
|
||||
return (
|
||||
<>
|
||||
{showLogo && (
|
||||
<div className="ds-nav-page-switcher-logo">
|
||||
<a href="/" aria-label={appName}>
|
||||
<img
|
||||
src={
|
||||
activeOverallTheme === 'dark' ? overleafLogoDark : overleafLogo
|
||||
}
|
||||
alt="Overleaf, A Digital Science Solution"
|
||||
height="59"
|
||||
width="130"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<ul
|
||||
className={`list-unstyled ds-nav-page-switcher-items${!showLogo ? ' ds-nav-page-switcher-items--no-logo' : ''}`}
|
||||
>
|
||||
<li>
|
||||
<a
|
||||
href="/library"
|
||||
className={`ds-nav-page-switcher-item${activePage === 'library' ? ' active' : ''}`}
|
||||
aria-current={activePage === 'library' ? 'page' : undefined}
|
||||
onClick={
|
||||
onLibraryClick
|
||||
? e => {
|
||||
e.preventDefault()
|
||||
onLibraryClick(e)
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<BookBookmark size={24} />
|
||||
<span className="ds-nav-page-switcher-item-label">
|
||||
{t('library')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="/project"
|
||||
className={`ds-nav-page-switcher-item${activePage === 'projects' ? ' active' : ''}`}
|
||||
aria-current={activePage === 'projects' ? 'page' : undefined}
|
||||
onClick={
|
||||
onProjectsClick
|
||||
? e => {
|
||||
e.preventDefault()
|
||||
onProjectsClick(e)
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Folder size={24} />
|
||||
<span className="ds-nav-page-switcher-item-label">
|
||||
{t('projects')}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -114,20 +114,28 @@ body {
|
||||
.project-list-wrapper .project-list-sidebar-wrapper-react {
|
||||
padding-top: calc(var(--spacing-08) - 1px);
|
||||
|
||||
.ds-nav-page-switcher-divider {
|
||||
margin: var(--spacing-05) 0;
|
||||
}
|
||||
|
||||
.project-list-sidebar-scroll {
|
||||
padding-top: 0;
|
||||
padding-right: var(--spacing-05);
|
||||
}
|
||||
|
||||
ul.project-list-filters {
|
||||
> li > button {
|
||||
margin-top: var(--spacing-05);
|
||||
|
||||
.sidebar-filter-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: calc(var(--spacing-05) + 24px + var(--spacing-05));
|
||||
}
|
||||
|
||||
.sidebar-filter-button-with-icon {
|
||||
padding-left: var(--spacing-05);
|
||||
|
||||
svg {
|
||||
margin-right: var(--spacing-05);
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
padding-left: calc(var(--spacing-06) + 24px + var(--spacing-05));
|
||||
}
|
||||
@@ -212,7 +220,7 @@ body {
|
||||
}
|
||||
|
||||
.ds-nav-page-switcher-logo {
|
||||
padding: 0 var(--spacing-08) var(--spacing-07);
|
||||
padding: 0 var(--spacing-08) var(--spacing-04);
|
||||
|
||||
img {
|
||||
width: 130px;
|
||||
@@ -220,24 +228,12 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
.ds-nav-page-switcher-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-02);
|
||||
padding: 0 var(--spacing-05);
|
||||
margin: 0;
|
||||
|
||||
&--no-logo {
|
||||
padding-top: var(--spacing-05);
|
||||
}
|
||||
}
|
||||
|
||||
.ds-nav-page-switcher-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: var(--spacing-05);
|
||||
padding: var(--spacing-05);
|
||||
padding: var(--spacing-04) var(--spacing-05);
|
||||
border: none;
|
||||
border-radius: var(--border-radius-medium);
|
||||
background: none;
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
import { DsNavPageSwitcher } from '../../../../../frontend/js/shared/components/sidebar/ds-nav-page-switcher'
|
||||
import { SplitTestProvider } from '@/shared/context/split-test-context'
|
||||
import { UserSettingsProvider } from '@/shared/context/user-settings-context'
|
||||
|
||||
function mountDsNavPageSwitcher(
|
||||
props: React.ComponentProps<typeof DsNavPageSwitcher>
|
||||
) {
|
||||
cy.mount(
|
||||
<SplitTestProvider>
|
||||
<UserSettingsProvider>
|
||||
<DsNavPageSwitcher {...props} />
|
||||
</UserSettingsProvider>
|
||||
</SplitTestProvider>
|
||||
)
|
||||
}
|
||||
|
||||
describe('<DsNavPageSwitcher />', function () {
|
||||
describe('activePage="library"', function () {
|
||||
beforeEach(function () {
|
||||
mountDsNavPageSwitcher({ activePage: 'library' })
|
||||
})
|
||||
|
||||
it('marks the Library link as active', function () {
|
||||
cy.findByRole('link', { name: /library/i }).should('have.class', 'active')
|
||||
})
|
||||
|
||||
it('does not mark the Projects link as active', function () {
|
||||
cy.findByRole('link', { name: /projects/i }).should(
|
||||
'not.have.class',
|
||||
'active'
|
||||
)
|
||||
})
|
||||
|
||||
it('sets aria-current on the Library link', function () {
|
||||
cy.findByRole('link', { name: /library/i }).should(
|
||||
'have.attr',
|
||||
'aria-current',
|
||||
'page'
|
||||
)
|
||||
})
|
||||
|
||||
it('does not set aria-current on the Projects link', function () {
|
||||
cy.findByRole('link', { name: /projects/i }).should(
|
||||
'not.have.attr',
|
||||
'aria-current'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders the logo', function () {
|
||||
cy.get('.ds-nav-page-switcher-logo img').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('activePage="projects"', function () {
|
||||
beforeEach(function () {
|
||||
mountDsNavPageSwitcher({ activePage: 'projects' })
|
||||
})
|
||||
|
||||
it('marks the Projects link as active', function () {
|
||||
cy.findByRole('link', { name: /projects/i }).should(
|
||||
'have.class',
|
||||
'active'
|
||||
)
|
||||
})
|
||||
|
||||
it('does not mark the Library link as active', function () {
|
||||
cy.findByRole('link', { name: /library/i }).should(
|
||||
'not.have.class',
|
||||
'active'
|
||||
)
|
||||
})
|
||||
|
||||
it('renders the logo', function () {
|
||||
cy.get('.ds-nav-page-switcher-logo img').should('exist')
|
||||
})
|
||||
})
|
||||
|
||||
describe('link hrefs', function () {
|
||||
beforeEach(function () {
|
||||
mountDsNavPageSwitcher({ activePage: 'library' })
|
||||
})
|
||||
|
||||
it('Library link points to /library', function () {
|
||||
cy.findByRole('link', { name: /library/i }).should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'/library'
|
||||
)
|
||||
})
|
||||
|
||||
it('Projects link points to /project', function () {
|
||||
cy.findByRole('link', { name: /projects/i }).should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'/project'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe('showLogo={false}', function () {
|
||||
beforeEach(function () {
|
||||
mountDsNavPageSwitcher({ activePage: 'projects', showLogo: false })
|
||||
})
|
||||
|
||||
it('does not render the logo', function () {
|
||||
cy.get('.ds-nav-page-switcher-logo').should('not.exist')
|
||||
})
|
||||
|
||||
it('still renders both nav links', function () {
|
||||
cy.findByRole('link', { name: /library/i }).should('exist')
|
||||
cy.findByRole('link', { name: /projects/i }).should('exist')
|
||||
})
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user