From 95a0859f0f2956e1ec11b7bdd66272d11ce51d8b Mon Sep 17 00:00:00 2001 From: andreastanderen <71079896+standeren@users.noreply.github.com> Date: Wed, 6 Nov 2024 10:48:15 +0100 Subject: [PATCH] feat: Use StudioContentMenu in ContentLibrary (#13927) --- .../AppContentLibrary.test.tsx | 5 +- frontend/language/src/nb.json | 3 +- .../ContentLibrary/ContentLibrary.module.css | 12 +--- .../ContentLibrary/ContentLibrary.test.tsx | 7 ++- .../src/ContentLibrary/ContentLibrary.tsx | 23 ++------ .../InfoBox/InfoBox.module.css | 3 +- .../InfoBox/InfoBox.test.tsx | 2 +- .../{ => LibraryBody}/InfoBox/InfoBox.tsx | 2 +- .../{ => LibraryBody}/InfoBox/index.ts | 0 .../InfoBox/infoBoxConfigs.ts | 4 +- .../LibraryBody/LibraryBody.module.css | 9 +++ .../LibraryBody/LibraryBody.tsx | 58 +++++++++++++++++++ .../PagesRouter/PagesRouter.test.tsx | 28 ++++----- .../LibraryBody/PagesRouter/PagesRouter.tsx | 32 ++++++++++ .../LibraryBody/PagesRouter/index.ts | 1 + .../src/ContentLibrary/LibraryBody/index.ts | 1 + .../pages/CodeList/CodeList.test.tsx | 0 .../pages/CodeList/CodeList.tsx | 0 .../{ => LibraryBody}/pages/CodeList/index.ts | 0 .../pages/Images/Images.test.tsx | 0 .../{ => LibraryBody}/pages/Images/Images.tsx | 0 .../{ => LibraryBody}/pages/Images/index.ts | 0 .../pages/LandingPage/LandingPage.module.css | 0 .../pages/LandingPage/LandingPage.test.tsx | 0 .../pages/LandingPage/LandingPage.tsx | 0 .../pages/LandingPage/index.ts | 0 .../LibraryHeader/LibraryHeader.module.css | 11 ++-- .../LibraryHeader/LibraryHeader.test.tsx | 24 ++------ .../LibraryHeader/LibraryHeader.tsx | 20 +------ .../PagesRouter/PagesRouter.module.css | 24 -------- .../PagesRouter/PagesRouter.tsx | 58 ------------------- .../src/ContentLibrary/PagesRouter/index.ts | 2 - .../PagesRouter/pagesRouterConfigs.tsx | 29 ---------- .../ContentResourceLibraryImpl.test.tsx | 6 +- .../src/hooks/useLibraryMenuContentTabs.tsx | 36 ++++++++++++ .../src/types/PagesProps.ts | 16 ++--- .../src/utils/router/QueryParamsRouter.ts | 2 +- .../utils/router/RouterRouteMapper.test.ts | 4 +- .../src/utils/router/RouterRouteMapper.ts | 6 +- .../test-utils/renderWithBrowserRouter.tsx | 9 +++ 40 files changed, 212 insertions(+), 225 deletions(-) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/InfoBox/InfoBox.module.css (90%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/InfoBox/InfoBox.test.tsx (95%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/InfoBox/InfoBox.tsx (94%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/InfoBox/index.ts (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/InfoBox/infoBoxConfigs.ts (83%) create mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.module.css create mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.tsx rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/PagesRouter/PagesRouter.test.tsx (57%) create mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.tsx create mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/index.ts create mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/index.ts rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/CodeList/CodeList.test.tsx (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/CodeList/CodeList.tsx (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/CodeList/index.ts (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/Images/Images.test.tsx (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/Images/Images.tsx (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/Images/index.ts (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/LandingPage/LandingPage.module.css (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/LandingPage/LandingPage.test.tsx (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/LandingPage/LandingPage.tsx (100%) rename frontend/libs/studio-content-library/src/ContentLibrary/{ => LibraryBody}/pages/LandingPage/index.ts (100%) delete mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.module.css delete mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.tsx delete mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/index.ts delete mode 100644 frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/pagesRouterConfigs.tsx create mode 100644 frontend/libs/studio-content-library/src/hooks/useLibraryMenuContentTabs.tsx create mode 100644 frontend/libs/studio-content-library/test-utils/renderWithBrowserRouter.tsx diff --git a/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx b/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx index b917a7fd5d9..224ead7e4bb 100644 --- a/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx +++ b/frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import { AppContentLibrary } from './AppContentLibrary'; import { textMock } from '@studio/testing/mocks/i18nMock'; +import { renderWithProviders } from '../../test/mocks'; describe('AppContentLibrary', () => { it('renders the AppContentLibrary with codeLists and images resources', () => { @@ -20,5 +21,5 @@ describe('AppContentLibrary', () => { }); const renderAppContentLibrary = () => { - render(); + renderWithProviders()(); }; diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index 88dfac00386..1f4a276c1d9 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -21,8 +21,9 @@ "app_content_library.images.page_name": "Bilder", "app_content_library.info_box.title": "En kort beskrivelse om bruk av og hensikt med ressursen i bibliotket.", "app_content_library.landing_page.description": "Når du utvikler skjemaer, er det nyttig å samle ulike filer og ressurser på ett sted. I biblioteket kan du laste opp ting andre har laget som du har bruk for, eller selv lage det du trenger til de tjenestene du utvikler.", - "app_content_library.landing_page.page_name": "Bibliotek", + "app_content_library.landing_page.page_name": "Om biblioteket", "app_content_library.landing_page.title": "Med biblioteket kan du effektivt utvikle mer konsekvente tjenester", + "app_content_library.library_heading": "Bibliotek", "app_create_release.build_version": "Bygg versjon", "app_create_release.check_status": "Sjekker status på appen din...", "app_create_release.loading": "Laster...", diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.module.css b/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.module.css index dd78555d772..74694c96d71 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.module.css +++ b/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.module.css @@ -9,19 +9,9 @@ .libraryContainer { background-color: var(--fds-semantic-background-default); border-radius: var(--fds-border_radius-xlarge); - border-bottom: solid 1px var(--fds-semantic-border-neutral-subtle); + border: solid 1px var(--fds-semantic-border-neutral-subtle); overflow: hidden; min-height: 80%; max-height: 100%; width: 100%; } - -.component { - padding: var(--fds-spacing-10); -} - -.libraryContent { - display: grid; - grid-template-columns: 0.7fr 3.3fr 1fr; - height: 100%; -} diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.test.tsx index 76ed63ecd6c..8311f02d373 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.test.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.test.tsx @@ -1,11 +1,12 @@ import React from 'react'; import { ContentLibrary } from './ContentLibrary'; -import { render, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { mockPagesConfig } from '../../mocks/mockPagesConfig'; import { textMock } from '@studio/testing/mocks/i18nMock'; import { RouterContext } from '../contexts/RouterContext'; import type { PageName } from '../types/PageName'; +import { renderWithBrowserRouter } from '../../test-utils/renderWithBrowserRouter'; const navigateMock = jest.fn(); @@ -13,7 +14,7 @@ describe('ContentLibrary', () => { it('renders the ContentLibrary with landingPage by default', () => { renderContentLibrary(); const libraryHeader = screen.getByRole('heading', { - name: textMock('app_content_library.landing_page.page_name'), + name: textMock('app_content_library.library_heading'), }); const landingPageTitle = screen.getByRole('heading', { name: textMock('app_content_library.landing_page.title'), @@ -51,7 +52,7 @@ describe('ContentLibrary', () => { }); const renderContentLibrary = (currentPage: PageName = undefined) => { - render( + renderWithBrowserRouter( , diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.tsx index 04933f99c47..113b97ee6ec 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/ContentLibrary.tsx @@ -4,11 +4,10 @@ import type { PageComponent } from '../utils/router/RouterRouteMapper'; import { RouterRouteMapperImpl } from '../utils/router/RouterRouteMapper'; import type { PagePropsMap, PagesConfig } from '../types/PagesProps'; import classes from './ContentLibrary.module.css'; -import { InfoBox } from './InfoBox'; -import { PagesRouter } from './PagesRouter'; import { LibraryHeader } from './LibraryHeader'; import { StudioHeading } from '@studio/components'; import type { PageName } from '../types/PageName'; +import { LibraryBody } from './LibraryBody'; type ContentLibraryProps = { pages: PagesConfig; @@ -19,37 +18,25 @@ export function ContentLibrary({ pages }: ContentLibraryProps): React.ReactEleme return ; } -type ContentLibraryForPageProps = { +type ContentLibraryForPageProps = { pages: PagesConfig; currentPage: T; }; -function ContentLibraryForPage({ +function ContentLibraryForPage({ pages, currentPage, }: ContentLibraryForPageProps): React.ReactElement { const router = new RouterRouteMapperImpl(pages); - const Component: PageComponent[T]> = - router.configuredRoutes.get(currentPage); + const Component: PageComponent> = router.configuredRoutes.get(currentPage); if (!Component) return 404 Page Not Found; // Show the NotFound page from app-dev instead - const componentPropsAreExternal = currentPage !== 'landingPage'; - - const componentProps: Required[T] = - componentPropsAreExternal && (pages[currentPage].props as Required[T]); - return (
-
- -
- -
- -
+ Component={Component} pages={pages} currentPage={currentPage} />
); diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.module.css b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.module.css similarity index 90% rename from frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.module.css rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.module.css index 2703923cc80..61866751098 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.module.css +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.module.css @@ -1,10 +1,9 @@ .infoBoxContainer { border-radius: var(--fds-border_radius-large); border: 1px solid var(--fds-semantic-border-neutral-subtle); - width: 15vw; overflow: hidden; height: fit-content; - margin: var(--fds-spacing-10); + margin: var(--fds-spacing-8); } .infoBoxContainer img { diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.test.tsx similarity index 95% rename from frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.test.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.test.tsx index a597e5ea34a..2927a6de35f 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.test.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { InfoBox } from './InfoBox'; import { render, screen } from '@testing-library/react'; import { textMock } from '@studio/testing/mocks/i18nMock'; -import type { PageName } from '../../types/PageName'; +import type { PageName } from '../../../types/PageName'; import { infoBoxConfigs } from './infoBoxConfigs'; const pageNameMock: PageName = 'codeList'; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.tsx similarity index 94% rename from frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.tsx index b5099ac13be..0bf4c903fdb 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/InfoBox.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/InfoBox.tsx @@ -2,7 +2,7 @@ import React from 'react'; import classes from './InfoBox.module.css'; import { StudioParagraph } from '@studio/components'; import { useTranslation } from 'react-i18next'; -import type { PageName } from '../../types/PageName'; +import type { PageName } from '../../../types/PageName'; import { infoBoxConfigs } from './infoBoxConfigs'; type InfoBoxProps = { diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/index.ts similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/index.ts rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/index.ts diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/infoBoxConfigs.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/infoBoxConfigs.ts similarity index 83% rename from frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/infoBoxConfigs.ts rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/infoBoxConfigs.ts index 1e345fb75a1..22123dad905 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/InfoBox/infoBoxConfigs.ts +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/InfoBox/infoBoxConfigs.ts @@ -1,5 +1,5 @@ -import type { PageName } from '../../types/PageName'; -import type { InfoBoxProps } from '../../types/InfoBoxProps'; +import type { PageName } from '../../../types/PageName'; +import type { InfoBoxProps } from '../../../types/InfoBoxProps'; export type InfoBoxConfigs = Partial<{ [T in PageName]: InfoBoxProps }>; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.module.css b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.module.css new file mode 100644 index 00000000000..fece04268e1 --- /dev/null +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.module.css @@ -0,0 +1,9 @@ +.libraryContent { + display: grid; + grid-template-columns: 2fr 7fr 3fr; + height: 100%; +} + +.component { + padding: var(--fds-spacing-10); +} diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.tsx new file mode 100644 index 00000000000..f098e4d8e81 --- /dev/null +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/LibraryBody.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import classes from './LibraryBody.module.css'; +import { PagesRouter } from './PagesRouter'; +import { InfoBox } from './InfoBox'; +import type { PagePropsMap, PagesConfig } from '../../types/PagesProps'; +import type { PageName } from '../../types/PageName'; +import type { PageComponent } from '../../utils/router/RouterRouteMapper'; + +type LibraryBodyProps = { + Component: PageComponent>; + pages: PagesConfig; + currentPage: T; +}; + +export function LibraryBody({ + Component, + pages, + currentPage, +}: LibraryBodyProps) { + const componentProps: PagePropsMap = getComponentProps(pages, currentPage); + + return ( +
+ + Component={Component} componentProps={componentProps} currentPage={currentPage} /> +
+ ); +} + +type PageProps = { + Component: PageComponent>; + componentProps: PagePropsMap; + currentPage: T; +}; + +function Page({ Component, componentProps, currentPage }: PageProps) { + return ( + <> +
+ +
+ + + ); +} + +const getComponentProps = ( + pages: PagesConfig, + currentPage: T, +): PagePropsMap => { + if (currentPage === 'landingPage') return {} as PagePropsMap; + return pages[currentPage].props; +}; + +const getAllPageNamesFromPagesConfig = (pages: PagesConfig): PageName[] => { + const customPages = Object.keys(pages) as PageName[]; + return ['landingPage', ...customPages]; +}; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.test.tsx similarity index 57% rename from frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.test.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.test.tsx index 711ac30d150..c25079939fc 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.test.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.test.tsx @@ -1,18 +1,23 @@ import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { PagesRouter } from './PagesRouter'; import { textMock } from '@studio/testing/mocks/i18nMock'; -import { RouterContext } from '../../contexts/RouterContext'; -import type { PageName } from '../../types/PageName'; +import { RouterContext } from '../../../contexts/RouterContext'; +import type { PageName } from '../../../types/PageName'; +import { renderWithBrowserRouter } from '../../../../test-utils/renderWithBrowserRouter'; const navigateMock = jest.fn(); describe('PagesRouter', () => { it('renders the pages as navigation titles', () => { renderPagesRouter(); - const codeListNavTitle = screen.getByText(textMock('app_content_library.code_lists.page_name')); - const imagesNavTitle = screen.getByText(textMock('app_content_library.images.page_name')); + const codeListNavTitle = screen.getByRole('tab', { + name: textMock('app_content_library.code_lists.page_name'), + }); + const imagesNavTitle = screen.getByRole('tab', { + name: textMock('app_content_library.images.page_name'), + }); expect(codeListNavTitle).toBeInTheDocument(); expect(imagesNavTitle).toBeInTheDocument(); }); @@ -20,22 +25,17 @@ describe('PagesRouter', () => { it('calls navigate from RouterContext when clicking on a page that is not selected', async () => { const user = userEvent.setup(); renderPagesRouter(); - const imagesNavTitle = screen.getByText(textMock('app_content_library.images.page_name')); + const imagesNavTitle = screen.getByRole('tab', { + name: textMock('app_content_library.images.page_name'), + }); await user.click(imagesNavTitle); expect(navigateMock).toHaveBeenCalledTimes(1); expect(navigateMock).toHaveBeenCalledWith('images'); }); - - it('returns null if trying to render an unknown pageName', () => { - const pageName: string = 'unknownPageName'; - renderPagesRouter([pageName as PageName]); - const navTitle = screen.queryByText(pageName); - expect(navTitle).not.toBeInTheDocument(); - }); }); const renderPagesRouter = (pageNames: PageName[] = ['codeList', 'images']) => { - render( + renderWithBrowserRouter( , diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.tsx new file mode 100644 index 00000000000..64c855ff184 --- /dev/null +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/PagesRouter.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import { useRouterContext } from '../../../contexts/RouterContext'; +import type { PageName } from '../../../types/PageName'; +import { useContentTabs } from '../../../hooks/useLibraryMenuContentTabs'; +import { StudioContentMenu } from '@studio/components'; + +type PagesRouterProps = { + pageNames: PageName[]; +}; + +export function PagesRouter({ pageNames }: PagesRouterProps): React.ReactElement { + const { navigate, currentPage } = useRouterContext(); + const contentTabs = useContentTabs(); + + const handleNavigation = (pageToNavigateTo: PageName) => { + navigate(pageToNavigateTo); + }; + + return ( + + {pageNames.map((pageName) => ( + + ))} + + ); +} diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/index.ts new file mode 100644 index 00000000000..a2a2b9baf0b --- /dev/null +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/PagesRouter/index.ts @@ -0,0 +1 @@ +export { PagesRouter } from './PagesRouter'; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/index.ts new file mode 100644 index 00000000000..159e8cfa63e --- /dev/null +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/index.ts @@ -0,0 +1 @@ +export { LibraryBody } from './LibraryBody'; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/CodeList/CodeList.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeList/CodeList.test.tsx similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/CodeList/CodeList.test.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeList/CodeList.test.tsx diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/CodeList/CodeList.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeList/CodeList.tsx similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/CodeList/CodeList.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeList/CodeList.tsx diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/CodeList/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeList/index.ts similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/CodeList/index.ts rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeList/index.ts diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/Images/Images.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/Images/Images.test.tsx similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/Images/Images.test.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/Images/Images.test.tsx diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/Images/Images.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/Images/Images.tsx similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/Images/Images.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/Images/Images.tsx diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/Images/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/Images/index.ts similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/Images/index.ts rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/Images/index.ts diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/LandingPage.module.css b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/LandingPage.module.css similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/LandingPage.module.css rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/LandingPage.module.css diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/LandingPage.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/LandingPage.test.tsx similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/LandingPage.test.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/LandingPage.test.tsx diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/LandingPage.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/LandingPage.tsx similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/LandingPage.tsx rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/LandingPage.tsx diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/index.ts similarity index 100% rename from frontend/libs/studio-content-library/src/ContentLibrary/pages/LandingPage/index.ts rename to frontend/libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/LandingPage/index.ts diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.module.css b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.module.css index 7b0751c64e6..25d5304ea77 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.module.css +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.module.css @@ -1,12 +1,13 @@ .libraryHeading { + display: flex; + align-items: center; + gap: var(--fds-spacing-1); padding: var(--fds-spacing-4); border-bottom: solid 1px var(--fds-semantic-border-neutral-subtle); } -.libraryLandingPageNavigation { +.headingIcon { display: flex; - align-items: center; - gap: var(--fds-spacing-1); - cursor: pointer; - width: fit-content; + color: var(--fds-semantic-text-neutral-default); + font-size: var(--fds-sizing-10); } diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.test.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.test.tsx index 85dbbfa2553..eca2675279e 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.test.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.test.tsx @@ -2,31 +2,19 @@ import React from 'react'; import { textMock } from '@studio/testing/mocks/i18nMock'; import { LibraryHeader } from './LibraryHeader'; import { render, screen } from '@testing-library/react'; -import userEvent from '@testing-library/user-event'; import { RouterContext } from '../../contexts/RouterContext'; const navigateMock = jest.fn(); describe('LibraryHeader', () => { - it('renders the landingPage header', () => { + it('renders the content library header', () => { renderLibraryHeader(); - const landingPageIcon = screen.getByRole('img'); - const landingPageHeader = screen.getByRole('heading', { - name: textMock('app_content_library.landing_page.page_name'), + const libraryIcon = screen.getByRole('img'); + const libraryHeader = screen.getByRole('heading', { + name: textMock('app_content_library.library_heading'), }); - expect(landingPageIcon).toBeInTheDocument(); - expect(landingPageHeader).toBeInTheDocument(); - }); - - it('calls navigate from useRouterContext when clicking on the header', async () => { - const user = userEvent.setup(); - renderLibraryHeader(); - const landingPageHeader = screen.getByRole('heading', { - name: textMock('app_content_library.landing_page.page_name'), - }); - await user.click(landingPageHeader); - expect(navigateMock).toHaveBeenCalledTimes(1); - expect(navigateMock).toHaveBeenCalledWith('landingPage'); + expect(libraryIcon).toBeInTheDocument(); + expect(libraryHeader).toBeInTheDocument(); }); }); diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.tsx index e59df0f2d9e..299ac11b248 100644 --- a/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.tsx +++ b/frontend/libs/studio-content-library/src/ContentLibrary/LibraryHeader/LibraryHeader.tsx @@ -1,30 +1,16 @@ import React from 'react'; import classes from './LibraryHeader.module.css'; -import { pagesRouterConfigs } from '../PagesRouter'; -import type { PageName } from '../../types/PageName'; -import { useRouterContext } from '../../contexts/RouterContext'; import { StudioHeading } from '@studio/components'; import { useTranslation } from 'react-i18next'; +import { BookIcon } from '@studio/icons'; export function LibraryHeader(): React.ReactElement { - const { navigate } = useRouterContext(); const { t } = useTranslation(); - const handleNavigation = (pageToNavigateTo: PageName) => { - navigate(pageToNavigateTo); - }; - return (
-
handleNavigation('landingPage')} - > - {pagesRouterConfigs['landingPage'].icon} - - {t(pagesRouterConfigs['landingPage'].pageTitleTextKey)} - -
+ + {t('app_content_library.library_heading')}
); } diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.module.css b/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.module.css deleted file mode 100644 index 6511b0c60f9..00000000000 --- a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.module.css +++ /dev/null @@ -1,24 +0,0 @@ -.pagesRouterContainer { - background-color: var(--fds-semantic-surface-action-second-subtle); -} - -.pageIsSelected, -.pageNavigation { - display: flex; - align-items: center; - gap: var(--fds-spacing-2); - border: solid 1px var(--fds-semantic-border-action-second-subtle); - padding: var(--fds-spacing-3); - cursor: pointer; -} - -.pageIsSelected { - border-left: 3px solid var(--semantic-surface-action-default, #0062ba); - background-color: white; -} - -.pageNavigation:hover, -.pageIsSelected:hover { - border-left: 3px solid var(--semantic-surface-action-default, #0062ba); - background-color: white; -} diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.tsx deleted file mode 100644 index c61185247b9..00000000000 --- a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/PagesRouter.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import classes from './PagesRouter.module.css'; -import { useRouterContext } from '../../contexts/RouterContext'; -import type { PageName } from '../../types/PageName'; -import { pagesRouterConfigs } from './pagesRouterConfigs'; -import { useTranslation } from 'react-i18next'; -import { StudioParagraph } from '@studio/components'; - -type PagesRouterProps = { - pageNames: PageName[]; -}; - -export function PagesRouter({ pageNames }: PagesRouterProps): React.ReactElement { - const { navigate, currentPage } = useRouterContext(); - - const handleNavigation = (pageToNavigateTo: PageName) => { - navigate(pageToNavigateTo); - }; - - return ( -
- {pageNames.map((pageName) => ( - - ))} -
- ); -} - -type PageNavigationTileProps = { - currentPage: PageName; - pageName: PageName; - onClick: (newPage: PageName) => void; -}; - -function PageNavigationTile({ - currentPage, - pageName, - onClick, -}: PageNavigationTileProps): React.ReactElement { - const { t } = useTranslation(); - - if (!pagesRouterConfigs[pageName]) return null; - - return ( -
onClick(pageName)} - > - {pagesRouterConfigs[pageName].icon} - {t(pagesRouterConfigs[pageName].pageTitleTextKey)} -
- ); -} diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/index.ts b/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/index.ts deleted file mode 100644 index 49a7c6f8f2a..00000000000 --- a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { PagesRouter } from './PagesRouter'; -export { pagesRouterConfigs } from './pagesRouterConfigs'; diff --git a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/pagesRouterConfigs.tsx b/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/pagesRouterConfigs.tsx deleted file mode 100644 index 0e323134291..00000000000 --- a/frontend/libs/studio-content-library/src/ContentLibrary/PagesRouter/pagesRouterConfigs.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React, { type ReactNode } from 'react'; -import type { PageName } from '../../types/PageName'; -import { BookIcon, CodeListsIcon, ImageIcon } from '@studio/icons'; - -type RouterPageProps = { - icon: ReactNode; - pageName: PageName; - pageTitleTextKey: string; -}; - -type PagesRouterConfigs = { [T in PageName]: RouterPageProps }; - -export const pagesRouterConfigs: PagesRouterConfigs = { - landingPage: { - pageName: 'landingPage', - pageTitleTextKey: 'app_content_library.landing_page.page_name', - icon: , - }, - codeList: { - icon: , - pageName: 'codeList', - pageTitleTextKey: 'app_content_library.code_lists.page_name', - }, - images: { - icon: , - pageName: 'images', - pageTitleTextKey: 'app_content_library.images.page_name', - }, -}; diff --git a/frontend/libs/studio-content-library/src/config/ContentResourceLibraryImpl.test.tsx b/frontend/libs/studio-content-library/src/config/ContentResourceLibraryImpl.test.tsx index 131bd3bedb4..25e068df168 100644 --- a/frontend/libs/studio-content-library/src/config/ContentResourceLibraryImpl.test.tsx +++ b/frontend/libs/studio-content-library/src/config/ContentResourceLibraryImpl.test.tsx @@ -1,8 +1,8 @@ -import React from 'react'; -import { render, screen } from '@testing-library/react'; +import { screen } from '@testing-library/react'; import type { PagesConfig } from '../types/PagesProps'; import { ResourceContentLibraryImpl } from './ContentResourceLibraryImpl'; import { textMock } from '@studio/testing/mocks/i18nMock'; +import { renderWithBrowserRouter } from '../../test-utils/renderWithBrowserRouter'; describe('ContentResourceLibraryImpl', () => { it('renders ContentResourceLibraryImpl with given pages', () => { @@ -51,5 +51,5 @@ describe('ContentResourceLibraryImpl', () => { const renderContentResourceLibraryImpl = (pages: PagesConfig) => { const contentResourceLibraryImpl = new ResourceContentLibraryImpl({ pages }); const { getContentResourceLibrary } = contentResourceLibraryImpl; - render(
{getContentResourceLibrary()}
); + renderWithBrowserRouter(getContentResourceLibrary()); }; diff --git a/frontend/libs/studio-content-library/src/hooks/useLibraryMenuContentTabs.tsx b/frontend/libs/studio-content-library/src/hooks/useLibraryMenuContentTabs.tsx new file mode 100644 index 00000000000..0a18886a374 --- /dev/null +++ b/frontend/libs/studio-content-library/src/hooks/useLibraryMenuContentTabs.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import type { PageName } from '../types/PageName'; +import { BookIcon, CodeListsIcon, ImageIcon } from '@studio/icons'; +import type { StudioContentMenuLinkTabProps } from '@studio/components'; +import { useTranslation } from 'react-i18next'; +import { Link } from 'react-router-dom'; +import { pageRouterQueryParamKey } from '../utils/router/QueryParamsRouter'; + +type TabDictionary = { + [Key in PageName]: StudioContentMenuLinkTabProps; +}; + +export const useContentTabs = (): TabDictionary => { + const { t } = useTranslation(); + + return { + landingPage: { + tabName: t('app_content_library.landing_page.page_name'), + tabId: 'landingPage', + icon: , + renderTab: (props) => , + }, + codeList: { + tabName: t('app_content_library.code_lists.page_name'), + tabId: 'codeList', + icon: , + renderTab: (props) => , + }, + images: { + tabName: t('app_content_library.images.page_name'), + tabId: 'images', + icon: , + renderTab: (props) => , + }, + }; +}; diff --git a/frontend/libs/studio-content-library/src/types/PagesProps.ts b/frontend/libs/studio-content-library/src/types/PagesProps.ts index 6e7760f5c81..07aea20e47d 100644 --- a/frontend/libs/studio-content-library/src/types/PagesProps.ts +++ b/frontend/libs/studio-content-library/src/types/PagesProps.ts @@ -1,19 +1,19 @@ -import type { CodeListProps } from '../ContentLibrary/pages/CodeList'; +import type { CodeListProps } from '../ContentLibrary/LibraryBody/pages/CodeList'; import type { PageName } from './PageName'; -import type { ImagesProps } from '../ContentLibrary/pages/Images'; +import type { ImagesProps } from '../ContentLibrary/LibraryBody/pages/Images'; -export type PagePropsMap = { - landingPage?: {}; - codeList?: CodeListProps; - images?: ImagesProps; -}; +export type PagePropsMap

= { + landingPage: {}; + codeList: CodeListProps; + images: ImagesProps; +}[P]; type GlobalPageConfig = { props: T; }; type AllPagesConfig = { - [K in PageName]: GlobalPageConfig; + [K in PageName]: GlobalPageConfig>; }; export type PagesConfig = Partial; diff --git a/frontend/libs/studio-content-library/src/utils/router/QueryParamsRouter.ts b/frontend/libs/studio-content-library/src/utils/router/QueryParamsRouter.ts index 23c21e495da..3ebdb611691 100644 --- a/frontend/libs/studio-content-library/src/utils/router/QueryParamsRouter.ts +++ b/frontend/libs/studio-content-library/src/utils/router/QueryParamsRouter.ts @@ -1,6 +1,6 @@ import type { PageName } from '../../types/PageName'; -const pageRouterQueryParamKey: string = 'currentLibraryRoute'; +export const pageRouterQueryParamKey: string = 'currentLibraryRoute'; export interface QueryParamsRouter { currentRoute: PageName; diff --git a/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.test.ts b/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.test.ts index f5d0c9e9752..e5de2eb3655 100644 --- a/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.test.ts +++ b/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.test.ts @@ -1,6 +1,6 @@ import { RouterRouteMapperImpl } from './RouterRouteMapper'; -import { LandingPage } from '../../ContentLibrary/pages/LandingPage'; -import { CodeList } from '../../ContentLibrary/pages/CodeList'; +import { LandingPage } from '../../ContentLibrary/LibraryBody/pages/LandingPage'; +import { CodeList } from '../../ContentLibrary/LibraryBody/pages/CodeList'; import { mockPagesConfig } from '../../../mocks/mockPagesConfig'; describe('RouterRouteMapperImpl', () => { diff --git a/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.ts b/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.ts index e05fca14698..211a5ef5c69 100644 --- a/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.ts +++ b/frontend/libs/studio-content-library/src/utils/router/RouterRouteMapper.ts @@ -1,9 +1,9 @@ import { type ComponentProps, type ReactElement } from 'react'; -import { CodeList } from '../../ContentLibrary/pages/CodeList'; +import { CodeList } from '../../ContentLibrary/LibraryBody/pages/CodeList'; import type { PageName } from '../../types/PageName'; -import { LandingPage } from '../../ContentLibrary/pages/LandingPage'; +import { LandingPage } from '../../ContentLibrary/LibraryBody/pages/LandingPage'; import type { PagesConfig } from '../../types/PagesProps'; -import { Images } from '../../ContentLibrary/pages/Images'; +import { Images } from '../../ContentLibrary/LibraryBody/pages/Images'; type PageProps = | ComponentProps diff --git a/frontend/libs/studio-content-library/test-utils/renderWithBrowserRouter.tsx b/frontend/libs/studio-content-library/test-utils/renderWithBrowserRouter.tsx new file mode 100644 index 00000000000..a0e21c65ad9 --- /dev/null +++ b/frontend/libs/studio-content-library/test-utils/renderWithBrowserRouter.tsx @@ -0,0 +1,9 @@ +import type { ReactNode } from 'react'; +import React from 'react'; +import { BrowserRouter } from 'react-router-dom'; +import type { RenderResult } from '@testing-library/react'; +import { render } from '@testing-library/react'; + +export function renderWithBrowserRouter(component: ReactNode): RenderResult { + return render({component}); +}