diff --git a/packages/desktop-client/src/components/FloatableSidebar.js b/packages/desktop-client/src/components/FloatableSidebar.js index a14fedeff16abc677ede51c0a66a5b464669cc48..cf9f2bc8abd596efd9ac0ebe746a0a75019f9ecc 100644 --- a/packages/desktop-client/src/components/FloatableSidebar.js +++ b/packages/desktop-client/src/components/FloatableSidebar.js @@ -2,11 +2,13 @@ import React, { useState, useEffect, useContext } from 'react'; import { connect } from 'react-redux'; import { withRouter } from 'react-router-dom'; +import { useViewportSize } from '@react-aria/utils'; import mitt from 'mitt'; import * as actions from 'loot-core/src/client/actions'; import { colors } from '../style'; +import { breakpoints } from '../tokens'; import { View } from './common'; import { SIDEBAR_WIDTH } from './sidebar'; @@ -21,6 +23,7 @@ export function SidebarProvider({ children }) { value={{ show: () => emitter.emit('show'), hide: () => emitter.emit('hide'), + toggle: () => emitter.emit('toggle'), on: (name, listener) => { emitter.on(name, listener); return () => emitter.off(name, listener); @@ -40,7 +43,10 @@ function Sidebar({ floatingSidebar }) { let [hidden, setHidden] = useState(true); let sidebar = useSidebar(); - if (!floatingSidebar && hidden) { + let windowWidth = useViewportSize().width; + let sidebarShouldFloat = floatingSidebar || windowWidth < breakpoints.medium; + + if (!sidebarShouldFloat && hidden) { setHidden(false); } @@ -48,6 +54,7 @@ function Sidebar({ floatingSidebar }) { let cleanups = [ sidebar.on('show', () => setHidden(false)), sidebar.on('hide', () => setHidden(true)), + sidebar.on('toggle', () => setHidden(hidden => !hidden)), ]; return () => { cleanups.forEach(fn => fn()); @@ -56,7 +63,7 @@ function Sidebar({ floatingSidebar }) { return ( <> - {floatingSidebar && ( + {sidebarShouldFloat && ( <View onMouseOver={() => setHidden(false)} onMouseLeave={() => setHidden(true)} @@ -73,27 +80,27 @@ function Sidebar({ floatingSidebar }) { <View onMouseOver={ - floatingSidebar + sidebarShouldFloat ? e => { e.stopPropagation(); setHidden(false); } : null } - onMouseLeave={floatingSidebar ? () => setHidden(true) : null} + onMouseLeave={sidebarShouldFloat ? () => setHidden(true) : null} style={{ position: 'absolute', top: 50, // If not floating, the -50 takes into account the transform below - bottom: floatingSidebar ? 50 : -50, + bottom: sidebarShouldFloat ? 50 : -50, zIndex: 1001, borderRadius: '0 6px 6px 0', overflow: 'hidden', boxShadow: - !floatingSidebar || hidden + !sidebarShouldFloat || hidden ? 'none' : '0 15px 30px 0 rgba(0,0,0,0.25), 0 3px 15px 0 rgba(0,0,0,.5)', - transform: `translateY(${!floatingSidebar ? -50 : 0}px) + transform: `translateY(${!sidebarShouldFloat ? -50 : 0}px) translateX(${hidden ? -SIDEBAR_WIDTH : 0}px)`, transition: 'transform .5s, box-shadow .5s', }} @@ -105,12 +112,12 @@ function Sidebar({ floatingSidebar }) { style={[ { backgroundColor: colors.n1, - opacity: floatingSidebar ? 0 : 1, - transform: `translateX(${floatingSidebar ? -50 : 0}px)`, + opacity: sidebarShouldFloat ? 0 : 1, + transform: `translateX(${sidebarShouldFloat ? -50 : 0}px)`, transition: 'transform .4s, opacity .2s', width: SIDEBAR_WIDTH, }, - floatingSidebar && { + sidebarShouldFloat && { position: 'absolute', top: 0, bottom: 0, diff --git a/packages/desktop-client/src/components/Titlebar.js b/packages/desktop-client/src/components/Titlebar.js index ba095bb7ba02e2a40cf1bbcdf4c9a47241684c86..b2a6a6de3473a1d923cf81cbe3aae1e2b12230c9 100644 --- a/packages/desktop-client/src/components/Titlebar.js +++ b/packages/desktop-client/src/components/Titlebar.js @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef, useContext } from 'react'; import { connect } from 'react-redux'; import { Switch, Route, withRouter } from 'react-router-dom'; +import { useViewportSize } from '@react-aria/utils'; import { css, media } from 'glamor'; import * as actions from 'loot-core/src/client/actions'; @@ -15,7 +16,7 @@ import AlertTriangle from '../icons/v2/AlertTriangle'; import ArrowButtonRight1 from '../icons/v2/ArrowButtonRight1'; import NavigationMenu from '../icons/v2/NavigationMenu'; import { colors } from '../style'; -import tokens from '../tokens'; +import tokens, { breakpoints } from '../tokens'; import AccountSyncCheck from './accounts/AccountSyncCheck'; import AnimatedRefresh from './AnimatedRefresh'; @@ -266,6 +267,9 @@ function Titlebar({ let sidebar = useSidebar(); const serverURL = useServerURL(); + let windowWidth = useViewportSize().width; + let sidebarAlwaysFloats = windowWidth < breakpoints.medium; + return ( <View style={[ @@ -285,20 +289,24 @@ function Titlebar({ style, ]} > - {floatingSidebar && ( + {(floatingSidebar || sidebarAlwaysFloats) && ( <Button bare style={{ marginRight: 8, '& .arrow-right': { opacity: 0, transition: 'opacity .3s' }, '& .menu': { opacity: 1, transition: 'opacity .3s' }, - '&:hover .arrow-right': { opacity: 1 }, - '&:hover .menu': { opacity: 0 }, + '&:hover .arrow-right': !sidebarAlwaysFloats && { opacity: 1 }, + '&:hover .menu': !sidebarAlwaysFloats && { opacity: 0 }, }} onMouseEnter={() => sidebar.show()} onMouseLeave={() => sidebar.hide()} onClick={() => { - saveGlobalPrefs({ floatingSidebar: !floatingSidebar }); + if (windowWidth >= breakpoints.medium) { + saveGlobalPrefs({ floatingSidebar: !floatingSidebar }); + } else { + sidebar.toggle(); + } }} > <View style={{ width: 15, height: 15 }}> diff --git a/packages/desktop-client/src/components/sidebar.js b/packages/desktop-client/src/components/sidebar.js index da6c61d8dfa2dda7892f6d3e44637003646fe3c2..36177ed7870e6f490e298796c736c9b0733265da 100644 --- a/packages/desktop-client/src/components/sidebar.js +++ b/packages/desktop-client/src/components/sidebar.js @@ -1,6 +1,7 @@ import React, { useState, useMemo, useCallback, useEffect } from 'react'; import { useLocation } from 'react-router'; +import { useViewportSize } from '@react-aria/utils'; import { css } from 'glamor'; import * as Platform from 'loot-core/src/client/platform'; @@ -16,6 +17,7 @@ import Wallet from '../icons/v1/Wallet'; import ArrowButtonLeft1 from '../icons/v2/ArrowButtonLeft1'; import CalendarIcon from '../icons/v2/Calendar'; import { styles, colors } from '../style'; +import { breakpoints } from '../tokens'; import { View, @@ -537,6 +539,9 @@ export function Sidebar({ }) { let hasWindowButtons = !Platform.isBrowser && Platform.OS === 'mac'; + let windowWidth = useViewportSize().width; + let sidebarAlwaysFloats = windowWidth < breakpoints.medium; + return ( <View style={[ @@ -557,7 +562,7 @@ export function Sidebar({ style, ]} > - {hasWindowButtons && ( + {hasWindowButtons && !sidebarAlwaysFloats && ( <ToggleButton style={[ { @@ -609,7 +614,9 @@ export function Sidebar({ <View style={{ flex: 1, flexDirection: 'row' }} /> - {!hasWindowButtons && <ToggleButton onFloat={onFloat} />} + {!hasWindowButtons && !sidebarAlwaysFloats && ( + <ToggleButton onFloat={onFloat} /> + )} </View> <View style={{ overflow: 'auto' }}> diff --git a/packages/desktop-client/src/style.js b/packages/desktop-client/src/style.js index 330f3996318235feaf46030f9ea4276c5e8f167f..e532d85b367db3b3cd9f4b0a8b285edea0a7b8df 100644 --- a/packages/desktop-client/src/style.js +++ b/packages/desktop-client/src/style.js @@ -115,10 +115,10 @@ export const styles = { flex: 1, [`@media (min-width: ${tokens.breakpoint_xs})`]: { minWidth: 360, + paddingTop: 36, }, [`@media (min-width: ${tokens.breakpoint_medium})`]: { minWidth: 500, - paddingTop: 36, }, }, pageHeader: { diff --git a/packages/desktop-client/src/tokens.js b/packages/desktop-client/src/tokens.js index 96fca17498fe5b9d93aea922605e0bb50d6882b9..de4c6eec4e3d454f745461d35b69d1fa042bb687 100644 --- a/packages/desktop-client/src/tokens.js +++ b/packages/desktop-client/src/tokens.js @@ -5,3 +5,10 @@ const tokens = { breakpoint_wide: '1024px', }; export default tokens; + +export const breakpoints = { + xs: 350, + narrow: 512, + medium: 768, + wide: 1024, +}; diff --git a/upcoming-release-notes/835.md b/upcoming-release-notes/835.md new file mode 100644 index 0000000000000000000000000000000000000000..1ead3b0e48abf748e8ff77b2c379e67caa3ce964 --- /dev/null +++ b/upcoming-release-notes/835.md @@ -0,0 +1,6 @@ +--- +category: Enhancements +authors: [j-f1] +--- + +Force the sidebar to always float when the window is narrow