diff --git a/src/frontend/apps/e2e/__tests__/app-impress/left-pannel.spec.ts b/src/frontend/apps/e2e/__tests__/app-impress/left-pannel.spec.ts index 648f08198..576cf8b0f 100644 --- a/src/frontend/apps/e2e/__tests__/app-impress/left-pannel.spec.ts +++ b/src/frontend/apps/e2e/__tests__/app-impress/left-pannel.spec.ts @@ -7,6 +7,7 @@ test.describe('Left panel desktop', () => { test('checks all the elements are visible', async ({ page }) => { await expect(page.getByTestId('left-panel-desktop')).toBeVisible(); + await expect(page.getByTestId('left-panel-mobile')).toBeHidden(); await expect(page.getByRole('button', { name: 'house' })).toBeVisible(); await expect(page.getByRole('button', { name: 'New doc' })).toBeVisible(); }); @@ -19,7 +20,29 @@ test.describe('Left panel mobile', () => { await page.goto('/'); }); - test('checks all the desktop elements are hidden', async ({ page }) => { + test('checks all the desktop elements are hidden and all mobile elements are visible', async ({ + page, + }) => { await expect(page.getByTestId('left-panel-desktop')).toBeHidden(); + await expect(page.getByTestId('left-panel-mobile')).not.toBeInViewport(); + + const header = page.locator('header').first(); + const homeButton = page.getByRole('button', { name: 'house' }); + const newDocButton = page.getByRole('button', { name: 'New doc' }); + const languageButton = page.getByRole('combobox', { name: 'Language' }); + const logoutButton = page.getByRole('button', { name: 'Logout' }); + + await expect(homeButton).not.toBeInViewport(); + await expect(newDocButton).not.toBeInViewport(); + await expect(languageButton).not.toBeInViewport(); + await expect(logoutButton).not.toBeInViewport(); + + await header.getByLabel('Open the header menu').click(); + + await expect(page.getByTestId('left-panel-mobile')).toBeInViewport(); + await expect(homeButton).toBeInViewport(); + await expect(newDocButton).toBeInViewport(); + await expect(languageButton).toBeInViewport(); + await expect(logoutButton).toBeInViewport(); }); }); diff --git a/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx b/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx new file mode 100644 index 000000000..6a07c8dda --- /dev/null +++ b/src/frontend/apps/impress/src/components/separators/HorizontalSeparator.tsx @@ -0,0 +1,34 @@ +import { useCunninghamTheme } from '@/cunningham'; + +import { Box } from '../Box'; + +export enum SeparatorVariant { + LIGHT = 'light', + DARK = 'dark', +} + +type Props = { + variant?: SeparatorVariant; +}; + +export const HorizontalSeparator = ({ + variant = SeparatorVariant.LIGHT, +}: Props) => { + const { colorsTokens, themeTokens } = useCunninghamTheme(); + const colors = colorsTokens(); + const spacings = themeTokens().spacings; + return ( + + ); +}; diff --git a/src/frontend/apps/impress/src/features/left-pannel/components/LeftPanel.tsx b/src/frontend/apps/impress/src/features/left-pannel/components/LeftPanel.tsx index 06c4edc12..4bcfbee7e 100644 --- a/src/frontend/apps/impress/src/features/left-pannel/components/LeftPanel.tsx +++ b/src/frontend/apps/impress/src/features/left-pannel/components/LeftPanel.tsx @@ -4,27 +4,33 @@ import { PropsWithChildren, ReactNode } from 'react'; import { useTranslation } from 'react-i18next'; import { Box, Icon } from '@/components'; +import { HorizontalSeparator } from '@/components/separators/HorizontalSeparator'; import { SeparatedSection } from '@/components/separators/SeparatedSection'; +import { ButtonLogin } from '@/core'; import { useCunninghamTheme } from '@/cunningham'; import { useCreateDoc } from '@/features/docs'; import { HEADER_HEIGHT } from '@/features/header/conf'; +import { LanguagePicker } from '@/features/language'; import { useResponsiveStore } from '@/stores'; export const LeftPanel = ({ children }: PropsWithChildren) => { const { t } = useTranslation(); const router = useRouter(); - const { isResponsive } = useResponsiveStore(); + const { isResponsive, isMobileMenuOpen, toggleMobileMenu } = + useResponsiveStore(); const theme = useCunninghamTheme(); const colors = theme.colorsTokens(); const { mutate: createDoc } = useCreateDoc({ onSuccess: (doc) => { router.push(`/docs/${doc.id}`); + toggleMobileMenu(); }, }); const goToHome = () => { router.push('/'); + toggleMobileMenu(); }; const createNewDoc = () => { @@ -72,6 +78,37 @@ export const LeftPanel = ({ children }: PropsWithChildren) => { {getContent()} )} + {isResponsive && ( + + {getContent()} + + + {children && } + + + + + )} ); }; diff --git a/src/frontend/apps/impress/src/layouts/MainLayout.tsx b/src/frontend/apps/impress/src/layouts/MainLayout.tsx index fe81cff39..d068e81fd 100644 --- a/src/frontend/apps/impress/src/layouts/MainLayout.tsx +++ b/src/frontend/apps/impress/src/layouts/MainLayout.tsx @@ -1,10 +1,11 @@ -import { PropsWithChildren } from 'react'; +import { PropsWithChildren, ReactNode } from 'react'; import { Box } from '@/components'; import { useCunninghamTheme } from '@/cunningham'; import { Header } from '@/features/header'; import { HEADER_HEIGHT } from '@/features/header/conf'; import { LeftPanel } from '@/features/left-pannel/components/LeftPanel'; +import { useResponsiveStore } from '@/stores'; export enum MainLayoutBackgroundColor { WHITE = 'white', @@ -13,12 +14,15 @@ export enum MainLayoutBackgroundColor { type MainLayoutProps = { backgroundColor?: MainLayoutBackgroundColor; + leftPanelContent?: ReactNode; }; export function MainLayout({ children, backgroundColor = MainLayoutBackgroundColor.WHITE, + leftPanelContent, }: PropsWithChildren) { + const { isResponsive } = useResponsiveStore(); const { themeTokens, colorsTokens } = useCunninghamTheme(); const tokens = themeTokens(); const colors = colorsTokens(); @@ -27,17 +31,24 @@ export function MainLayout({
- + {leftPanelContent} void; + toggleMobileMenu: () => void; isResponsive: boolean; initializeResizeListener: () => () => void; } const initialState = { isMobile: false, - isSmallMobile: false, isTablet: false, + isSmallMobile: false, isResponsive: false, + isMobileMenuOpen: false, screenSize: 'desktop' as ScreenSize, screenWidth: 0, }; @@ -27,9 +30,13 @@ export const useResponsiveStore = create((set) => ({ isTablet: initialState.isTablet, isSmallMobile: initialState.isSmallMobile, screenSize: initialState.screenSize, + isMobileMenuOpen: initialState.isMobileMenuOpen, screenWidth: initialState.screenWidth, setScreenSize: (size: ScreenSize) => set(() => ({ screenSize: size })), isResponsive: initialState.isResponsive, + toggleMobileMenu: () => { + set((old) => ({ isMobileMenuOpen: !old.isMobileMenuOpen })); + }, initializeResizeListener: () => { const resizeHandler = () => { const width = window.innerWidth;