Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI: Add bottom navigation on mobile #24228

Merged
merged 31 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
e917749
Bring back mobile drawers
cdedreuille Sep 18, 2023
6302b90
Add menu icon
cdedreuille Sep 18, 2023
246fbe4
Merge branch 'charles-sb-mobile' into charles-mobile-menu-drawers
cdedreuille Sep 18, 2023
3fbb783
Improve icons in mobile navigation
cdedreuille Sep 18, 2023
216c208
Merge branch 'charles-sb-mobile' into charles-mobile-menu-drawers
cdedreuille Sep 18, 2023
ca9c691
Merge branch 'charles-mobile-1' into charles-mobile-2
cdedreuille Sep 19, 2023
294b1b5
Merge branch 'new-layout' into charles-mobile-2
cdedreuille Sep 19, 2023
b8f57dc
Merge branch 'new-layout' into charles-mobile-2
cdedreuille Sep 19, 2023
5e9e94c
Add the About for mobile
cdedreuille Sep 19, 2023
471dd5c
About is now working
cdedreuille Sep 20, 2023
86fd48c
Replace mobile components
cdedreuille Sep 20, 2023
cab08c5
Fix dark mode on mobile
cdedreuille Sep 20, 2023
3f5c5fb
Improved upgradeBlock
cdedreuille Sep 20, 2023
07f423c
Update About page to take the new upgrade block
cdedreuille Sep 20, 2023
faa5fb1
Update MobileAbout.tsx
cdedreuille Sep 20, 2023
56feda8
Fix issue when clicking on search
cdedreuille Sep 20, 2023
7a105d2
Fix CI errors
cdedreuille Sep 20, 2023
5218bab
Update Panel.tsx
cdedreuille Sep 20, 2023
d41bc20
Move sidebar and panel outside of each components
cdedreuille Sep 20, 2023
82a98d8
use context for layout states
JReinhold Sep 20, 2023
65127d9
improve closing about page
JReinhold Sep 20, 2023
568215d
add mobile stories
JReinhold Sep 20, 2023
d599393
cleanup
JReinhold Sep 20, 2023
1eec03b
disable mobile panel button in docs mode
JReinhold Sep 20, 2023
efa3aed
improve mobile stories
JReinhold Sep 20, 2023
1fd83dd
viewport in mobile about
JReinhold Sep 20, 2023
da1fbd5
fix types
JReinhold Sep 20, 2023
c950a98
fix drag handles when existing mobile
JReinhold Sep 20, 2023
ff336a1
fix about stories
JReinhold Sep 20, 2023
7bb3e8b
Merge branch 'new-layout' of github.com:storybookjs/storybook into ch…
JReinhold Sep 20, 2023
3ab7738
remove fullscreen button in mobile view
JReinhold Sep 20, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion code/builders/builder-manager/templates/template.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8" />

<title><%= typeof title !== 'undefined'? title : 'Storybook'%></title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />

<% if (favicon.endsWith('.svg')) {%>
<link rel="icon" type="image/svg+xml" href="./<%= favicon %>" />
Expand Down
2 changes: 2 additions & 0 deletions code/ui/manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"@storybook/theming": "workspace:*",
"@storybook/types": "workspace:*",
"@testing-library/react": "^11.2.2",
"@types/react-transition-group": "^4",
"@types/semver": "^7.3.4",
"browser-dtector": "^3.4.0",
"copy-to-clipboard": "^3.3.1",
Expand All @@ -80,6 +81,7 @@
"react-draggable": "^4.4.3",
"react-helmet-async": "^1.0.7",
"react-resize-detector": "^7.1.2",
"react-transition-group": "^4.4.5",
"resolve-from": "^5.0.0",
"semver": "^7.3.7",
"store2": "^2.14.2",
Expand Down
5 changes: 4 additions & 1 deletion code/ui/manager/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Preview from './container/Preview';
import Panel from './container/Panel';

import { Layout } from './components/layout/Layout';
import { useMobileLayoutContext } from './components/mobile/MobileLayoutProvider';

type Props = {
managerLayoutState: ComponentProps<typeof Layout>['managerLayoutState'];
Expand All @@ -19,6 +20,8 @@ type Props = {
};

export const App = ({ managerLayoutState, setManagerLayoutState, pages }: Props) => {
const { setMobileAboutOpen } = useMobileLayoutContext();

return (
<>
<Global styles={createGlobal} />
Expand All @@ -31,7 +34,7 @@ export const App = ({ managerLayoutState, setManagerLayoutState, pages }: Props)
<Preview id="main" withLoader />
</Route>
}
slotSidebar={<Sidebar />}
slotSidebar={<Sidebar onMenuClick={() => setMobileAboutOpen((state) => !state)} />}
slotPanel={<Panel />}
slotPages={pages.map(({ id, render: Content }) => (
<Content key={id} />
Expand Down
52 changes: 25 additions & 27 deletions code/ui/manager/src/components/layout/Layout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import React, { useState } from 'react';

import { styled } from '@storybook/theming';
import type { Meta, StoryObj } from '@storybook/react';
import { ManagerContext } from '@storybook/manager-api';
import { Layout } from './Layout';
import { MobileLayoutProvider } from '../mobile/MobileLayoutProvider';

const PlaceholderBlock = styled.div({
width: '100%',
Expand Down Expand Up @@ -61,6 +63,23 @@ const meta = {
theme: 'light',
layout: 'fullscreen',
},
decorators: [
(storyFn) => (
<ManagerContext.Provider
value={
{
api: {
getCurrentStoryData: () => ({
title: 'Some Story Title',
}),
},
} as any
}
>
<MobileLayoutProvider>{storyFn()}</MobileLayoutProvider>
</ManagerContext.Provider>
),
],
render: (args) => {
const [managerLayoutState, setManagerLayoutState] = useState(args.managerLayoutState);

Expand Down Expand Up @@ -111,38 +130,17 @@ export const Mobile = {
chromatic: { viewports: [320] },
},
};
export const MobileHorizontal = {
args: {
state: { ...defaultState, panelPosition: 'right' },
},
export const MobileDark = {
...Mobile,
parameters: {
viewport: {
defaultViewport: 'mobile1',
},
chromatic: { viewports: [320] },
...Mobile.parameters,
theme: 'dark',
},
};

export const MobileDocs = {
...Mobile,
args: {
state: { ...defaultState, viewMode: 'docs' },
},
parameters: {
viewport: {
defaultViewport: 'mobile1',
},
chromatic: { viewports: [320] },
},
};

export const MobileCustom = {
args: {
state: { ...defaultState, viewMode: 'custom' },
},
parameters: {
viewport: {
defaultViewport: 'mobile1',
},
chromatic: { viewports: [320] },
managerLayoutState: { ...defaultState, viewMode: 'docs' },
},
};
30 changes: 19 additions & 11 deletions code/ui/manager/src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { styled } from '@storybook/theming';
import type { API_Layout, API_ViewMode } from '@storybook/types';
import { useDragging } from './useDragging';
import { useMediaQuery } from '../hooks/useMedia';
import { MobileNavigation } from '../mobile-navigation/MobileNavigation';
import { MobileNavigation } from '../mobile/navigation/MobileNavigation';
import { BREAKPOINT_MIN_600 } from '../../constants';

interface InternalLayoutState {
Expand Down Expand Up @@ -39,10 +39,15 @@ const layoutStateIsEqual = (state: ManagerLayoutState, other: ManagerLayoutState
* Also syncs the layout state from the global manager store to the internal state
* here when necessary
*/
const useLayoutSyncingState = (
managerLayoutState: Props['managerLayoutState'],
setManagerLayoutState: Props['setManagerLayoutState']
) => {
const useLayoutSyncingState = ({
managerLayoutState,
setManagerLayoutState,
isDesktop,
}: {
managerLayoutState: Props['managerLayoutState'];
setManagerLayoutState: Props['setManagerLayoutState'];
isDesktop: boolean;
}) => {
// ref to keep track of previous managerLayoutState, to check if the props change
const prevManagerLayoutStateRef = React.useRef<ManagerLayoutState>(managerLayoutState);

Expand Down Expand Up @@ -91,10 +96,11 @@ const useLayoutSyncingState = (
managerLayoutState.viewMode !== 'story' && managerLayoutState.viewMode !== 'docs';
const isPanelShown = managerLayoutState.viewMode === 'story';

const { panelResizerRef, sidebarResizerRef } = useDragging(
setInternalDraggingSizeState,
isPanelShown
);
const { panelResizerRef, sidebarResizerRef } = useDragging({
setState: setInternalDraggingSizeState,
isPanelShown,
isDesktop,
});
const { navSize, rightPanelWidth, bottomPanelHeight } = internalDraggingSizeState.isDragging
? internalDraggingSizeState
: managerLayoutState;
Expand Down Expand Up @@ -126,7 +132,7 @@ export const Layout = ({ managerLayoutState, setManagerLayoutState, ...slots }:
showPages,
showPanel,
isDragging,
} = useLayoutSyncingState(managerLayoutState, setManagerLayoutState);
} = useLayoutSyncingState({ managerLayoutState, setManagerLayoutState, isDesktop });

return (
<LayoutContainer
Expand Down Expand Up @@ -157,7 +163,9 @@ export const Layout = ({ managerLayoutState, setManagerLayoutState, ...slots }:
)}
</>
)}
{isMobile && <MobileNavigation />}
{isMobile && (
<MobileNavigation menu={slots.slotSidebar} panel={slots.slotPanel} showPanel={showPanel} />
)}
</LayoutContainer>
);
};
Expand Down
17 changes: 12 additions & 5 deletions code/ui/manager/src/components/layout/useDragging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ function interpolate(relativeValue: number, min: number, max: number): number {
return min + (max - min) * relativeValue;
}

export function useDragging(
setState: Dispatch<SetStateAction<LayoutState>>,
isPanelShown: boolean
) {
export function useDragging({
setState,
isPanelShown,
isDesktop,
}: {
setState: Dispatch<SetStateAction<LayoutState>>;
isPanelShown: boolean;
isDesktop: boolean;
}) {
const panelResizerRef = useRef<HTMLDivElement>(null);
const sidebarResizerRef = useRef<HTMLDivElement>(null);

Expand Down Expand Up @@ -176,7 +181,9 @@ export function useDragging(
previewIframe?.removeAttribute('style');
};
}, [
isPanelShown, // we need to rerun this effect when the panel is shown/hidden to re-attach the event listeners
// we need to rerun this effect when the panel is shown/hidden or when changing between mobile/desktop to re-attach the event listeners
isPanelShown,
isDesktop,
setState,
]);

Expand Down

This file was deleted.

31 changes: 31 additions & 0 deletions code/ui/manager/src/components/mobile/MobileLayoutProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { FC } from 'react';
import React, { createContext, useContext, useState } from 'react';

type MobileLayoutContextType = {
isMobileAboutOpen: boolean;
setMobileAboutOpen: React.Dispatch<React.SetStateAction<boolean>>;
isMobilePanelOpen: boolean;
setMobilePanelOpen: React.Dispatch<React.SetStateAction<boolean>>;
};

const MobileLayoutContext = createContext<MobileLayoutContextType>({
isMobileAboutOpen: false,
setMobileAboutOpen: () => {},
isMobilePanelOpen: false,
setMobilePanelOpen: () => {},
});

export const MobileLayoutProvider: FC = ({ children }) => {
const [isMobileAboutOpen, setMobileAboutOpen] = useState(false);
const [isMobilePanelOpen, setMobilePanelOpen] = useState(false);

return (
<MobileLayoutContext.Provider
value={{ isMobileAboutOpen, setMobileAboutOpen, isMobilePanelOpen, setMobilePanelOpen }}
>
{children}
</MobileLayoutContext.Provider>
);
};

export const useMobileLayoutContext = () => useContext(MobileLayoutContext);
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ManagerContext } from '@storybook/manager-api';
import React, { useEffect } from 'react';
import { within } from '@storybook/testing-library';
import { MobileAbout } from './MobileAbout';
import { MobileLayoutProvider, useMobileLayoutContext } from '../MobileLayoutProvider';

/**
* A helper component to open the about page via the MobileLayoutContext
*/
const OpenAboutHelper = ({ children }: { children: any }) => {
const { setMobileAboutOpen } = useMobileLayoutContext();
useEffect(() => {
setMobileAboutOpen(true);
}, [setMobileAboutOpen]);
return children;
};

const meta = {
component: MobileAbout,
title: 'Mobile/About',
parameters: {
layout: 'fullscreen',
theme: 'light',
viewport: {
defaultViewport: 'mobile1',
},
chromatic: { viewports: [320] },
},
decorators: [
(storyFn) => {
return (
<ManagerContext.Provider
value={
{
api: {
getCurrentVersion: () => ({
version: '7.2.0',
}),
},
} as any
}
>
<MobileLayoutProvider>
<OpenAboutHelper>{storyFn()}</OpenAboutHelper>
</MobileLayoutProvider>
</ManagerContext.Provider>
);
},
],
} satisfies Meta<typeof MobileAbout>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Default: Story = {};
export const Dark: Story = {
parameters: { theme: 'dark' },
};

export const Closed: Story = {
play: async ({ canvasElement }) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
const closeButton = await within(canvasElement).getByTitle('Close about section');
await closeButton.click();
},
};
Loading