From b2d703bee4c9195f40400635f73b426ac9fedd75 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Sat, 17 Apr 2021 10:40:39 -0700 Subject: [PATCH] fix: Improved mobile styling fix: Severla context menus miss-positioned fix: Search filters not large enough on mobile fix: Deep black background on mobile to match native apps fix: Sticky document header allowing horizontal scrolling on mobile --- app/components/Button.js | 2 +- app/components/Header.js | 6 ++---- app/components/Theme.js | 20 +++++++++++++------ app/hooks/useMediaQuery.js | 20 +++++++++++++++++++ app/menus/NewDocumentMenu.js | 2 +- app/menus/NewTemplateMenu.js | 2 +- app/scenes/Search/Search.js | 5 ++++- app/scenes/Search/components/FilterOption.js | 13 +++++++++--- app/scenes/Search/components/FilterOptions.js | 2 +- shared/styles/theme.js | 8 ++++++++ 10 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 app/hooks/useMediaQuery.js diff --git a/app/components/Button.js b/app/components/Button.js index bfef711e..6ba2b8b5 100644 --- a/app/components/Button.js +++ b/app/components/Button.js @@ -134,7 +134,7 @@ export type Props = {| "data-event-action"?: string, |}; -const Button = React.forwardRef( +const Button = React.forwardRef( ( { type = "text", diff --git a/app/components/Header.js b/app/components/Header.js index a5913338..bcd1bb3f 100644 --- a/app/components/Header.js +++ b/app/components/Header.js @@ -97,6 +97,7 @@ const Wrapper = styled(Flex)` `; const Title = styled("div")` + display: none; font-size: 16px; font-weight: 600; text-overflow: ellipsis; @@ -105,12 +106,9 @@ const Title = styled("div")` cursor: pointer; min-width: 0; - /* on mobile, there's always a floating menu button in the top left - add some padding here to offset - */ - padding-left: 40px; ${breakpoint("tablet")` padding-left: 0; + display: block; `}; svg { diff --git a/app/components/Theme.js b/app/components/Theme.js index 560f2fe4..bdcf6288 100644 --- a/app/components/Theme.js +++ b/app/components/Theme.js @@ -3,22 +3,30 @@ import { observer } from "mobx-react"; import * as React from "react"; import { ThemeProvider } from "styled-components"; import GlobalStyles from "shared/styles/globals"; -import { dark, light } from "shared/styles/theme"; +import { dark, light, lightMobile, darkMobile } from "shared/styles/theme"; +import useMediaQuery from "hooks/useMediaQuery"; import useStores from "hooks/useStores"; +const empty = {}; + type Props = {| children: React.Node, |}; function Theme({ children }: Props) { const { ui } = useStores(); + const theme = ui.resolvedTheme === "dark" ? dark : light; + const mobileTheme = ui.resolvedTheme === "dark" ? darkMobile : lightMobile; + const isMobile = useMediaQuery(`(max-width: ${theme.breakpoints.tablet}px)`); return ( - - <> - - {children} - + + + <> + + {children} + + ); } diff --git a/app/hooks/useMediaQuery.js b/app/hooks/useMediaQuery.js new file mode 100644 index 00000000..4fcdc74a --- /dev/null +++ b/app/hooks/useMediaQuery.js @@ -0,0 +1,20 @@ +// @flow +import { useState, useEffect } from "react"; + +export default function useMediaQuery(query: string): boolean { + const [matches, setMatches] = useState(false); + + useEffect(() => { + const media = window.matchMedia(query); + if (media.matches !== matches) { + setMatches(media.matches); + } + const listener = () => { + setMatches(media.matches); + }; + media.addListener(listener); + return () => media.removeListener(listener); + }, [matches, query]); + + return matches; +} diff --git a/app/menus/NewDocumentMenu.js b/app/menus/NewDocumentMenu.js index a4c37cc8..ad1cb7bc 100644 --- a/app/menus/NewDocumentMenu.js +++ b/app/menus/NewDocumentMenu.js @@ -17,7 +17,7 @@ import useStores from "hooks/useStores"; import { newDocumentUrl } from "utils/routeHelpers"; function NewDocumentMenu() { - const menu = useMenuState(); + const menu = useMenuState({ modal: true }); const { t } = useTranslation(); const team = useCurrentTeam(); const { collections, policies } = useStores(); diff --git a/app/menus/NewTemplateMenu.js b/app/menus/NewTemplateMenu.js index ae298192..ba8c8fd3 100644 --- a/app/menus/NewTemplateMenu.js +++ b/app/menus/NewTemplateMenu.js @@ -16,7 +16,7 @@ import useStores from "hooks/useStores"; import { newDocumentUrl } from "utils/routeHelpers"; function NewTemplateMenu() { - const menu = useMenuState(); + const menu = useMenuState({ modal: true }); const { t } = useTranslation(); const team = useCurrentTeam(); const { collections, policies } = useStores(); diff --git a/app/scenes/Search/Search.js b/app/scenes/Search/Search.js index 233404e0..c5fef0c3 100644 --- a/app/scenes/Search/Search.js +++ b/app/scenes/Search/Search.js @@ -406,8 +406,11 @@ const ResultsWrapper = styled(Flex)` position: absolute; transition: all 300ms cubic-bezier(0.65, 0.05, 0.36, 1); top: ${(props) => (props.pinToTop ? "0%" : "50%")}; - margin-top: ${(props) => (props.pinToTop ? "40px" : "-75px")}; width: 100%; + + ${breakpoint("tablet")` + margin-top: ${(props) => (props.pinToTop ? "40px" : "-75px")}; + `}; `; const ResultList = styled(Flex)` diff --git a/app/scenes/Search/components/FilterOption.js b/app/scenes/Search/components/FilterOption.js index b46637e5..f51cc392 100644 --- a/app/scenes/Search/components/FilterOption.js +++ b/app/scenes/Search/components/FilterOption.js @@ -3,6 +3,7 @@ import { CheckmarkIcon } from "outline-icons"; import * as React from "react"; import { MenuItem } from "reakit/Menu"; import styled from "styled-components"; +import breakpoint from "styled-components-breakpoint"; import Flex from "components/Flex"; import HelpText from "components/HelpText"; @@ -48,8 +49,8 @@ const Checkmark = styled(CheckmarkIcon)` const Button = styled.button` display: flex; flex-direction: column; - font-size: 15px; - padding: 4px 8px; + font-size: 16px; + padding: 8px; margin: 0; border: 0; background: none; @@ -58,7 +59,7 @@ const Button = styled.button` font-weight: ${(props) => (props.active ? "600" : "normal")}; justify-content: center; width: 100%; - min-height: 32px; + min-height: 42px; ${HelpText} { font-weight: normal; @@ -68,6 +69,12 @@ const Button = styled.button` &:hover { background: ${(props) => props.theme.listItemHoverBackground}; } + + ${breakpoint("tablet")` + padding: 4px 8px; + font-size: 15px; + min-height: 32px; + `}; `; const ListItem = styled("li")` diff --git a/app/scenes/Search/components/FilterOptions.js b/app/scenes/Search/components/FilterOptions.js index d83a22f7..f788d504 100644 --- a/app/scenes/Search/components/FilterOptions.js +++ b/app/scenes/Search/components/FilterOptions.js @@ -30,7 +30,7 @@ const FilterOptions = ({ className, onSelect, }: Props) => { - const menu = useMenuState(); + const menu = useMenuState({ modal: true }); const selected = find(options, { key: activeKey }) || options[0]; const selectedLabel = selected ? `${selectedPrefix} ${selected.label}` : ""; diff --git a/shared/styles/theme.js b/shared/styles/theme.js index fd6cbd0c..918c7977 100644 --- a/shared/styles/theme.js +++ b/shared/styles/theme.js @@ -241,4 +241,12 @@ export const dark = { scrollbarThumb: colors.lightBlack, }; +export const lightMobile = { + background: colors.white, +}; + +export const darkMobile = { + background: colors.black, +}; + export default light;