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

Mobile device view: toggling stories panel with ☰ button #3337

Merged
merged 8 commits into from Apr 17, 2018

Conversation

denzenin
Copy link
Contributor

@denzenin denzenin commented Apr 1, 2018

Issue:

What I did

  • adapted Header component to have ☰ button when on mobile device
  • make stories-panel toggled by clicking ☰ button
  • added helper to detect whether the storybook is open on mobile device (this is done through userAgent of window)
  • adjusted styles

Now on mobile devices the layout looks something like this when storybook is rendered:
image

How to test

Open storybook on mobile device

Is this testable with Jest or Chromatic screenshots?
yes (I added some new tests)
Does this need a new example in the kitchen sink apps?
no
Does this need an update to the documentation?
not sure
If your answer is yes to any of these, please make sure to include it in your PR.

* add separate Header component
* add isMobileDevice helper
* initially place addonPanel at the bottom if storybook is open on mobile device
* add first part of tests
@@ -0,0 +1,7 @@
export default userAgent => {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need javascript for this? Can we just show/hide things using media queries instead?

Copy link
Contributor Author

@denzenin denzenin Apr 1, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it to avoid changes to layout in general.
Depending on whether it is mobile device, the header is rendered outside of stories-panel as a standalone component and visibility of stories-panel is just toggled with the existing mechanism (to hide when app first loaded on mobile device) :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK makes sense

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in the media query camp as well. If on desktop, a user scales the window smaller so they can code and render in the browser side by side, they should be able to use the mobile view as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@danielduan with current version of Storybook there is nothing stopping users from hiding stories-panel on desktop (with shortcuts) and then resize the browser window as it is needed for your particular case. I want to emphasize that this pull request solves the problem with testing components on physical mobile devices :)
And I tried to affect as little of desktop version as possible on purpose. Cause this is a whole separate task related to layouts in general.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that you don't want to expand the scope of this change so this sounds fine with me.

It's still a broader issue that we'll need to address at some point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's take it 1 step at a time? I don't fancy userAgent sniffing either, but it does solve an issue and down-scopes this PR well.

Let's improve the manager head for desktop after.

<h3 style={headingStyle}>{name}</h3>
</a>
<button style={shortcutIconStyle} onClick={openShortcutsHelp}>
<button style={iconStyle(isMobileDevice)} onClick={openShortcutsHelp}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this button is useless on mobiles, it shows keyboard shortcuts

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can actually make those things clickable and perform the action.. but once the left panel is gone (either by toggling it, or by going full-screen, you can't go back)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that some people use USB keyboards with mobile devices, so I wouldn't necessarily just remove it because of mobile.

@@ -98,7 +98,11 @@ const defaultSizes = {
},
};

const saveSizes = sizes => {
const saveSizes = (sizes, isMobileDevice) => {
if (isMobileDevice) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add some inline comment explaining why do we need to skip saving here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see two ways of refactoring this part:

Extract the saveSizes and getSavedSizes to a separate file and do not change their functionality.
Change only the Layout component to be coupled to the isMobileDevice.

As an alternative, you can store mobile sizes in a sperate entry of the storage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igor-dv I like the second option

Copy link
Member

@Hypnosphi Hypnosphi Apr 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I don't really get the point of separate storage entries. Different devices cannot share the same localStorage AFAIK

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Hypnosphi initially I avoided saving dimensions on mobile as the resizing worked not perfectly when I firstly tried it (I did not face issues that you have found later, but still resizing seemed to be a hard task to perform. So I wanted to avoid situations when you somehow resized the pane and did not like the results but the new unwanted sizes are saved in localStorage, so you cannot reset the layout by refreshing the page.

Maybe I misunderstood Igor's comment above about separation of saved dimensions, if it is not needed, but we still want to save sizes on mobile – let's just drop the changes and leave this part as it is in master right now?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I talked more about the browser emulators. I think in this case the storage is shared.

} = this.props;
const { previewPanelDimensions } = this.state;

const addonPanelInRight = isMobileDevice ? 0 : this.props.addonPanelInRight;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why number not boolean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missed it, thanks :)

@Hypnosphi
Copy link
Member

It breaks in a weird manner when I try to resize stories panel on mobile: https://deploy-preview-3337--storybooks-official.netlify.com/?selectedKind=ui%2FAddonPanel&selectedStory=default&full=0&addons=1&stories=0&panelRight=0&addonPanel=storybook%2Factions%2Factions-panel

@ndelangen
Copy link
Member

@denzenin Thank you for this amazing first PR, thank you!

const Header = ({ openShortcutsHelp, onBurgerButtonClick, name, url, isMobileDevice }) => (
<div style={wrapperStyle(isMobileDevice)}>
{isMobileDevice && (
<button style={burgerIconStyle} onClick={onBurgerButtonClick}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't just show this button always? I don't see any cons to it in a web mode, and having it in both modes will reduce complexity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me, when I see a ☰ button on mobile websites, I expect it to "always be there for me" :)
in this particular case, if we leave it on Desktop version and have the same behaviour (toggling story-panel, it will be hidden once story-panel is hidden)

but I have no issue with keeping the button, so if you advise to get rid of the check above – I'll remove it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can have something like this when it's closed (in both modes):

image

The floating button (with opacity). It will open the stories panel with the header in it. This way we can reuse most of the UI between web and mweb.

Copy link
Contributor Author

@denzenin denzenin Apr 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume there is a disadvantage in mobile view with floating button. In case of this floating element you will have to always keep it in mind when writing stories of the components. We would need to add some additional containers/spacing in stories to test the component without visual/touch interference with floating element. In my opinion header is OK and quite simple solution for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

Copy link
Member

@ndelangen ndelangen Apr 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@igor-dv I prefer this:

both visually and UX, you should not overlay anything over the preview.

@@ -98,7 +98,11 @@ const defaultSizes = {
},
};

const saveSizes = sizes => {
const saveSizes = (sizes, isMobileDevice) => {
if (isMobileDevice) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see two ways of refactoring this part:

Extract the saveSizes and getSavedSizes to a separate file and do not change their functionality.
Change only the Layout component to be coupled to the isMobileDevice.

As an alternative, you can store mobile sizes in a sperate entry of the storage.

@denzenin
Copy link
Contributor Author

denzenin commented Apr 2, 2018

@Hypnosphi regarding breaking on resize. yes, it is weird indeed. It seems that resizing of SplitPane works far from smooth on mobile. Tried it on master branch. Even when I had succeeded to resize story-panel I could resize it again (after first resize) only once in a bunch of tries.

@denzenin
Copy link
Contributor Author

denzenin commented Apr 2, 2018

@ndelangen thank you for the kind words :)

@codecov
Copy link

codecov bot commented Apr 2, 2018

Codecov Report

Merging #3337 into master will decrease coverage by 0.01%.
The diff coverage is 42.68%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3337      +/-   ##
==========================================
- Coverage   37.21%   37.19%   -0.02%     
==========================================
  Files         463      465       +2     
  Lines       10241    10300      +59     
  Branches      914      923       +9     
==========================================
+ Hits         3811     3831      +20     
- Misses       5892     5906      +14     
- Partials      538      563      +25
Impacted Files Coverage Δ
...i/src/modules/ui/components/stories_panel/index.js 20.63% <0%> (-1.04%) ⬇️
lib/ui/src/modules/ui/routes.js 0% <0%> (ø) ⬆️
lib/ui/src/modules/ui/components/header.stories.js 100% <100%> (ø)
addons/notes/src/index.js 90% <100%> (ø) ⬆️
...dules/ui/components/stories_panel/index.stories.js 91.66% <100%> (+0.75%) ⬆️
lib/ui/src/modules/ui/containers/stories_panel.js 25% <16.66%> (-1.32%) ⬇️
lib/ui/src/modules/ui/containers/header.js 27.58% <33.33%> (ø)
lib/ui/src/modules/ui/components/header.js 25.71% <42.85%> (ø)
lib/ui/src/modules/ui/containers/layout.js 20% <44.44%> (+7.5%) ⬆️
lib/ui/src/modules/ui/components/layout/index.js 29.33% <50%> (+1.14%) ⬆️
... and 88 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a504a08...0773a14. Read the comment docs.

@Hypnosphi
Copy link
Member

So should we maybe disable resizing on mobile at all?

@denzenin
Copy link
Contributor Author

Good day to all, could you please advise what changes should I make to my pull request to move it forward? Maybe one step at a time but still I need to know those steps :)

@Hypnosphi
Copy link
Member

What do you think about this?

should we maybe disable resizing on mobile at all?

You also need to resolve conflicts, feel free to ask for help if you need one

@denzenin
Copy link
Contributor Author

@Hypnosphi I am totally ok with that. If it's ok with you and @igor-dv – will do as it was initially in PR:

const saveSizes = (sizes, isMobileDevice) => {
  if (isMobileDevice) {
    return true;
  }
...
}

const getSavedSizes = (sizes, isMobileDevice) => {
  if (isMobileDevice) {
    return sizes;
  }
...
}

and will add some inline comments about why the sizes are not saved/loaded for mobile.

@Hypnosphi
Copy link
Member

Hypnosphi commented Apr 10, 2018

It would be more explicit if we would just pass allowResize={false} on mobile

@ndelangen
Copy link
Member

Would love to see this merged soon! 🙇

@denzenin
Copy link
Contributor Author

@Hypnosphi good evening. Fixed the resizing as you proposed.
Also fixed conflicts and would appreciate if you have a look at the merge commit.

@@ -130,7 +130,7 @@ class Layout extends React.Component {
constructor(props) {
super(props);

this.layerSizes = getSavedSizes(defaultSizes);
this.layerSizes = getSavedSizes(defaultSizes, props.isMobileDevice);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this second argument isn't used anymore

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, you are right ) please advise how could I clean it up?

@Hypnosphi Hypnosphi merged commit b6178a2 into storybookjs:master Apr 17, 2018
@ndelangen
Copy link
Member

Awesome work @denzenin ! 💪

@denzenin
Copy link
Contributor Author

yay! thank you all for your help and support :)

@Aarbel
Copy link
Contributor

Aarbel commented Aug 26, 2018

hi ! in which storybook version this PR has been included ? thanks !

@Hypnosphi
Copy link
Member

@Aarbel try latest alpha, 4.0.0-alpha.20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants