From f3a9e8748dc6ccac056c9cb3c2afae1b6d328705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 29 Jun 2024 14:37:18 +0200 Subject: [PATCH 01/15] FeaturePanel: Drawer --- src/components/App/App.tsx | 15 +++- .../FeaturePanel/Climbing/ClimbingPanel.tsx | 66 +++++++-------- .../FeaturePanel/FeatureHeading.tsx | 1 + src/components/FeaturePanel/FeaturePanel.tsx | 82 ++++++++++--------- .../FeaturePanel/FeaturePanelInDrawer.tsx | 61 ++++++++++++++ .../FeaturePreview/FeaturePreview.tsx | 1 + .../LayerSwitcher/LayerSwitcher.tsx | 1 + .../Map/behaviour/useOnMapClicked.tsx | 5 -- src/components/SearchBox/SearchBox.tsx | 7 +- src/components/utils/PanelHelpers.tsx | 31 ++++--- src/helpers/GlobalStyle.tsx | 11 ++- 11 files changed, 182 insertions(+), 99 deletions(-) create mode 100644 src/components/FeaturePanel/FeaturePanelInDrawer.tsx diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index c32d8ed52..8293ef813 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -12,7 +12,6 @@ import { HomepagePanel } from '../HomepagePanel/HomepagePanel'; import { Loading } from './Loading'; import { FeatureProvider, useFeatureContext } from '../utils/FeatureContext'; import { OsmAuthProvider } from '../utils/OsmAuthContext'; -import { FeaturePreview } from '../FeaturePreview/FeaturePreview'; import { TitleAndMetaTags } from '../../helpers/TitleAndMetaTags'; import { InstallDialog } from '../HomepagePanel/InstallDialog'; import { setIntlForSSR } from '../../services/intl'; @@ -21,6 +20,9 @@ import { ClimbingDialog } from '../FeaturePanel/Climbing/ClimbingDialog'; import { ClimbingContextProvider } from '../FeaturePanel/Climbing/contexts/ClimbingContext'; import { StarsProvider } from '../utils/StarsContext'; import { SnackbarProvider } from '../utils/SnackbarContext'; +import { useMobileMode } from '../helpers'; +import { FeaturePanelInDrawer } from '../FeaturePanel/FeaturePanelInDrawer'; +import { PanelWrapper } from '../utils/PanelHelpers'; const usePersistMapView = () => { const { view } = useMapStateContext(); @@ -66,7 +68,8 @@ const useUpdateViewFromHash = () => { }; const IndexWithProviders = () => { - const { feature, featureShown, preview } = useFeatureContext(); + const isMobileMode = useMobileMode(); + const { feature, featureShown } = useFeatureContext(); const router = useRouter(); useUpdateViewFromFeature(); usePersistMapView(); @@ -80,7 +83,12 @@ const IndexWithProviders = () => { <> - {featureShown && } + {featureShown && !isMobileMode && ( + + + + )} + {featureShown && isMobileMode && } {isClimbingDialogShown && ( @@ -90,7 +98,6 @@ const IndexWithProviders = () => { {router.pathname === '/install' && } - {preview && } ); diff --git a/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx b/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx index 303bc8586..f26d022ac 100644 --- a/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx +++ b/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx @@ -56,45 +56,45 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => { return ( <> - - - + {/* + */} + - - {label} - - - - + + {label} + + + + - - + + - - + + -
- -
+
+ +
- + - {/* @TODO unite with parent panel */} -
{footer}
-
- - - -
+ {/* @TODO unite with parent panel */} +
{footer}
+ {/*
*/} + + + + {/*
*/} ); }; diff --git a/src/components/FeaturePanel/FeatureHeading.tsx b/src/components/FeaturePanel/FeatureHeading.tsx index 84ec59c6c..dab49ca4a 100644 --- a/src/components/FeaturePanel/FeatureHeading.tsx +++ b/src/components/FeaturePanel/FeatureHeading.tsx @@ -10,6 +10,7 @@ const Wrapper = styled.div<{ $deleted: boolean }>` padding-bottom: 30px; ${({ $deleted }) => $deleted && 'text-decoration: line-through;'} + padding: 25px 20px; &:hover .show-on-hover { display: block !important; } diff --git a/src/components/FeaturePanel/FeaturePanel.tsx b/src/components/FeaturePanel/FeaturePanel.tsx index b8d76dfde..0328be818 100644 --- a/src/components/FeaturePanel/FeaturePanel.tsx +++ b/src/components/FeaturePanel/FeaturePanel.tsx @@ -93,45 +93,47 @@ export const FeaturePanel = () => { } return ( - - - - - - - - - - - - - {!skeleton && ( - <> - - - - - - - {advanced && } - - - - {editEnabled && } - - {point && } - - - )} - - - {footer} - - - + <> + {/* + */} + + + + + + + + + + + {!skeleton && ( + <> + + + + + + + {advanced && } + + + + {editEnabled && } + + {point && } + + + )} + + + {footer} + + {/* + */} + ); }; diff --git a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx new file mode 100644 index 000000000..435edb567 --- /dev/null +++ b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx @@ -0,0 +1,61 @@ +import React, { useState } from 'react'; + +import { SwipeableDrawer, useTheme } from '@mui/material'; +import styled from 'styled-components'; +import { grey } from '@mui/material/colors'; +import { FeaturePanel } from './FeaturePanel'; + +const Puller = styled.div` + width: 30px; + height: 6px; + background-color: ${({ theme }) => + theme.palette.mode === 'light' ? grey[300] : grey[900]}; + border-radius: 3px; + position: absolute; + top: 8px; + left: calc(50% - 15px); +`; + +const ListContainer = styled('div')(() => ({ + maxHeight: '90vh', + overflow: 'auto', +})); + +export const FeaturePanelInDrawer = () => { + const [open, setOpen] = useState(false); + const theme = useTheme(); + + return ( + setOpen(false)} + onOpen={() => { + setOpen(true); + }} + swipeAreaWidth={72} + disableSwipeToOpen={false} + ModalProps={{ + keepMounted: true, + }} + > +
+ + + + +
+
+ ); +}; diff --git a/src/components/FeaturePreview/FeaturePreview.tsx b/src/components/FeaturePreview/FeaturePreview.tsx index da28ebd71..bc9e68df5 100644 --- a/src/components/FeaturePreview/FeaturePreview.tsx +++ b/src/components/FeaturePreview/FeaturePreview.tsx @@ -26,6 +26,7 @@ export const FeaturePreview = () => { if (!preview || preview.noPreviewButton) { return null; } + Router.push(`${getOsmappLink(preview)}${window.location.hash}`); const handleClick = () => { setPreview(null); diff --git a/src/components/LayerSwitcher/LayerSwitcher.tsx b/src/components/LayerSwitcher/LayerSwitcher.tsx index 6fb5c5863..27d441c6f 100644 --- a/src/components/LayerSwitcher/LayerSwitcher.tsx +++ b/src/components/LayerSwitcher/LayerSwitcher.tsx @@ -20,6 +20,7 @@ const LayerSwitcher = () => { variant={panelFixed ? 'persistent' : 'temporary'} disableBackdropTransition disableSwipeToOpen + swipeAreaWidth={100} >
diff --git a/src/components/Map/behaviour/useOnMapClicked.tsx b/src/components/Map/behaviour/useOnMapClicked.tsx index b04112fc5..6e5ab9e5b 100644 --- a/src/components/Map/behaviour/useOnMapClicked.tsx +++ b/src/components/Map/behaviour/useOnMapClicked.tsx @@ -58,11 +58,6 @@ export const useOnMapClicked = createMapEventHook( return; } - if (mobileMode) { - setPreview(skeleton); - return; - } - // router wouldnt overwrite the skeleton if same url is already loaded setFeature((feature) => isSameOsmId(feature, skeleton) ? feature : skeleton, diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx index 628ae13b4..d1447ec24 100644 --- a/src/components/SearchBox/SearchBox.tsx +++ b/src/components/SearchBox/SearchBox.tsx @@ -20,7 +20,7 @@ const TopPanel = styled.div` padding: 10px; box-sizing: border-box; - z-index: 1200; + z-index: 1201; width: 100%; @media ${isDesktop} { @@ -66,6 +66,7 @@ const useOnClosePanel = () => { }; const SearchBox = () => { + const isMobileMode = useMobileMode(); const { featureShown } = useFeatureContext(); const { inputValue, setInputValue } = useInputValueState(); const [options, setOptions] = useState([]); @@ -90,7 +91,9 @@ const SearchBox = () => { setOverpassLoading={setOverpassLoading} /> - {featureShown && } + {featureShown && !isMobileMode && ( + + )} {overpassLoading && } diff --git a/src/components/utils/PanelHelpers.tsx b/src/components/utils/PanelHelpers.tsx index 3d4cf7d32..833753543 100644 --- a/src/components/utils/PanelHelpers.tsx +++ b/src/components/utils/PanelHelpers.tsx @@ -2,31 +2,38 @@ import React from 'react'; import styled from 'styled-components'; import { Scrollbars } from 'react-custom-scrollbars'; import { useTheme } from '@mui/material'; -import { isDesktop } from '../helpers'; +// import { isDesktop } from '../helpers'; import { useScrollShadow } from '../FeaturePanel/Climbing/utils/useScrollShadow'; import { SEARCH_BOX_HEIGHT } from '../SearchBox/consts'; // custom scrollbar // better: https://github.com/rommguy/react-custom-scroll // maybe https://github.com/malte-wessel/react-custom-scrollbars (larger) -export const PanelWrapper = styled.div` - position: absolute; - left: 0; - top: 72px; // TopPanel - bottom: 0; +export const PanelWrapper = styled.div<{ fromLeft?: boolean }>` + /* position: absolute; */ + /* left: 0; */ + /* top: 72px; // TopPanel */ + /* bottom: 0; */ background: ${({ theme }) => theme.palette.background.paper}; color: ${({ theme }) => theme.palette.text.primary}; overflow: hidden; - z-index: 1100; + /* z-index: 1100; */ box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; - width: 100%; - @media ${isDesktop} { + ${({ fromLeft }) => + fromLeft + ? ` width: 410px; - } + height: 100%; + margin-top: 72px; // TopPanel + ` + : ` + width: 100vw; + height: 100%; + `} & > div > div { // disable pulling panel around on mobile @@ -68,9 +75,9 @@ export const PanelScrollbars = ({ children }) => { export const PanelContent = styled.div` display: flex; flex-direction: column; - height: calc( + /* height: calc( 100vh - ${SEARCH_BOX_HEIGHT}px - 238px - ); // 100% - TopPanel - FeatureImage + ); // 100% - TopPanel - FeatureImage */ padding: 20px 0 0 0; `; diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 02f32d4b0..d88e85a8d 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -100,7 +100,12 @@ export const GlobalStyle = createGlobalStyle` } /* Hide compass by default */ -.hidden-compass .maplibregl-ctrl-compass { - display: none; -} + .hidden-compass .maplibregl-ctrl-compass { + display: none; + } + + .MuiDrawer-root > .MuiPaper-root { + height: calc(90vh - 72px); + overflow: visible; + } `; From ba6955ded3cf9c7bc1bba7c81b9ac063e44e567a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 29 Jun 2024 21:23:35 +0200 Subject: [PATCH 02/15] FeaturePanel: new drawer --- src/components/App/App.tsx | 9 +- src/components/App/Loading.tsx | 2 +- .../FeaturePanel/Climbing/ClimbingPanel.tsx | 7 +- src/components/FeaturePanel/FeaturePanel.tsx | 153 ++---------------- .../FeaturePanel/FeaturePanelInDrawer.tsx | 41 ++--- .../FeaturePanel/FeaturePanelInner.tsx | 138 ++++++++++++++++ .../FeaturePanel/ImagePane/Slider.tsx | 2 +- .../HomepagePanel/HomepagePanel.tsx | 2 +- src/components/Map/BrowserMap.tsx | 2 +- .../Map/behaviour/useOnMapClicked.tsx | 2 +- src/components/SearchBox/SearchBox.tsx | 20 ++- src/components/utils/PanelHelpers.tsx | 33 ++-- src/helpers/GlobalStyle.tsx | 2 +- src/helpers/theme.tsx | 2 + types.d.ts | 1 + 15 files changed, 213 insertions(+), 203 deletions(-) create mode 100644 src/components/FeaturePanel/FeaturePanelInner.tsx diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 8293ef813..0d8dec4f7 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -22,7 +22,6 @@ import { StarsProvider } from '../utils/StarsContext'; import { SnackbarProvider } from '../utils/SnackbarContext'; import { useMobileMode } from '../helpers'; import { FeaturePanelInDrawer } from '../FeaturePanel/FeaturePanelInDrawer'; -import { PanelWrapper } from '../utils/PanelHelpers'; const usePersistMapView = () => { const { view } = useMapStateContext(); @@ -81,13 +80,9 @@ const IndexWithProviders = () => { const photo = router.query.all?.[3]; return ( <> - - {featureShown && !isMobileMode && ( - - - - )} + + {featureShown && !isMobileMode && } {featureShown && isMobileMode && } {isClimbingDialogShown && ( diff --git a/src/components/App/Loading.tsx b/src/components/App/Loading.tsx index eb6f16c9b..45cb7a88c 100644 --- a/src/components/App/Loading.tsx +++ b/src/components/App/Loading.tsx @@ -6,7 +6,7 @@ import { isDesktop, useBoolState } from '../helpers'; const Wrapper = styled.div` position: absolute; - top: 72px; + top: 0; z-index: 1200; width: 100%; diff --git a/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx b/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx index f26d022ac..1c0d8d8e3 100644 --- a/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx +++ b/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx @@ -4,7 +4,6 @@ import Router from 'next/router'; import ZoomInIcon from '@mui/icons-material/ZoomIn'; import { Button } from '@mui/material'; import { useClimbingContext } from './contexts/ClimbingContext'; -import { PanelScrollbars, PanelWrapper } from '../../utils/PanelHelpers'; import { RouteList } from './RouteList/RouteList'; import { useFeatureContext } from '../../utils/FeatureContext'; import { getLabel } from '../../../helpers/featureLabel'; @@ -19,6 +18,7 @@ import { RouteDistribution } from './RouteDistribution'; import { YellowedBadge } from './YellowedBadge'; import { getWikimediaCommonsKeys, removeFilePrefix } from './utils/photo'; import { SuggestEdit } from '../SuggestEdit'; +import { PanelContent } from '../../utils/PanelHelpers'; const HeadingContainer = styled.div` display: flex; @@ -55,7 +55,7 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => { preparePhotosAndSet(cragPhotos); return ( - <> + {/* */} @@ -78,7 +78,6 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => {
- {/* @TODO unite with parent panel */}
{footer}
{/* */} @@ -95,6 +94,6 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => { {/* */} - + ); }; diff --git a/src/components/FeaturePanel/FeaturePanel.tsx b/src/components/FeaturePanel/FeaturePanel.tsx index 0328be818..83173c4d8 100644 --- a/src/components/FeaturePanel/FeaturePanel.tsx +++ b/src/components/FeaturePanel/FeaturePanel.tsx @@ -1,139 +1,14 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; -import { FeatureHeading } from './FeatureHeading'; -import Coordinates from './Coordinates'; -import { useToggleState } from '../helpers'; -import { getFullOsmappLink, getKey } from '../../services/helpers'; -import { - PanelContent, - PanelFooter, - PanelScrollbars, - PanelSidePadding, - PanelWrapper, -} from '../utils/PanelHelpers'; -import { useFeatureContext } from '../utils/FeatureContext'; -import { t } from '../../services/intl'; -import { FeatureDescription } from './FeatureDescription'; -import { ObjectsAround } from './ObjectsAround'; -import { OsmError } from './OsmError'; -import { Members } from './Members'; -import { getLabel } from '../../helpers/featureLabel'; -import { ImageSection } from './ImageSection/ImageSection'; -import { PublicTransport } from './PublicTransport/PublicTransport'; -import { Properties } from './Properties/Properties'; -import { MemberFeatures } from './MemberFeatures'; -import { ClimbingPanel } from './Climbing/ClimbingPanel'; -import { ClimbingContextProvider } from './Climbing/contexts/ClimbingContext'; -import { isClimbingRelation } from '../../services/osmApi'; -import { ParentLink } from './ParentLink'; -import { ImageSlider } from './ImagePane/ImageSlider'; -import { SuggestEdit } from './SuggestEdit'; - -const Flex = styled.div` - flex: 1; -`; - -export const FeaturePanel = () => { - const { feature } = useFeatureContext(); - - const [advanced, setAdvanced] = useState(false); - const [showAround, toggleShowAround] = useToggleState(false); - const [showTags, toggleShowTags] = useToggleState(false); - - const { point, tags, skeleton, deleted } = feature; - const editEnabled = !skeleton; - const showTagsTable = deleted || showTags || (!skeleton && !feature.schema); - - const osmappLink = getFullOsmappLink(feature); - const label = getLabel(feature); - - const footer = ( - - - -
- {osmappLink} -
- {' '} - - {!point && showAround && } -
- ); - - if (!feature) { - return null; - } - - if ( - isClimbingRelation(feature) && // only for this condition is memberFeatures fetched - feature.tags.climbing === 'crag' && - !advanced - ) { - return ( - - - - ); - } - - return ( - <> - {/* - */} - - - - - - - - - - - {!skeleton && ( - <> - - - - - - - {advanced && } - - - - {editEnabled && } - - {point && } - - - )} - - - {footer} - - {/* - */} - - ); -}; +import React from 'react'; + +import { PanelScrollbars, PanelWrapper } from '../utils/PanelHelpers'; +import { FeaturePanelInner } from './FeaturePanelInner'; + +export const FeaturePanel = () => ( + <> + + + + + + +); diff --git a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx index 435edb567..c2b08afd9 100644 --- a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx +++ b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx @@ -1,9 +1,22 @@ import React, { useState } from 'react'; -import { SwipeableDrawer, useTheme } from '@mui/material'; +import { SwipeableDrawer } from '@mui/material'; import styled from 'styled-components'; import { grey } from '@mui/material/colors'; -import { FeaturePanel } from './FeaturePanel'; +import { FeaturePanelInner } from './FeaturePanelInner'; + +const Container = styled.div` + position: relative; + background: ${({ theme }) => theme.palette.background.paper}; + margin-top: -86px; + border-top-left-radius: 12px; + border-top-right-radius: 12px; + visibility: visible; + right: 0; + left: 0; + box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); + height: 100%; +`; const Puller = styled.div` width: 30px; @@ -12,18 +25,19 @@ const Puller = styled.div` theme.palette.mode === 'light' ? grey[300] : grey[900]}; border-radius: 3px; position: absolute; + pointer-events: none; top: 8px; left: calc(50% - 15px); `; const ListContainer = styled('div')(() => ({ - maxHeight: '90vh', + maxHeight: 'calc(100% - 8px)', + height: '100%', overflow: 'auto', })); export const FeaturePanelInDrawer = () => { const [open, setOpen] = useState(false); - const theme = useTheme(); return ( { onOpen={() => { setOpen(true); }} - swipeAreaWidth={72} + swipeAreaWidth={86} disableSwipeToOpen={false} ModalProps={{ keepMounted: true, }} > -
+ - + -
+
); }; diff --git a/src/components/FeaturePanel/FeaturePanelInner.tsx b/src/components/FeaturePanel/FeaturePanelInner.tsx new file mode 100644 index 000000000..9399b8c4a --- /dev/null +++ b/src/components/FeaturePanel/FeaturePanelInner.tsx @@ -0,0 +1,138 @@ +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { Box } from '@mui/material'; +import { FeatureHeading } from './FeatureHeading'; +import Coordinates from './Coordinates'; +import { useToggleState } from '../helpers'; +import { getFullOsmappLink, getKey } from '../../services/helpers'; +import { + PanelContent, + PanelFooter, + PanelSidePadding, +} from '../utils/PanelHelpers'; +import { useFeatureContext } from '../utils/FeatureContext'; +import { t } from '../../services/intl'; +import { FeatureDescription } from './FeatureDescription'; +import { ObjectsAround } from './ObjectsAround'; +import { OsmError } from './OsmError'; +import { Members } from './Members'; +import { getLabel } from '../../helpers/featureLabel'; +import { ImageSection } from './ImageSection/ImageSection'; +import { PublicTransport } from './PublicTransport/PublicTransport'; +import { Properties } from './Properties/Properties'; +import { MemberFeatures } from './MemberFeatures'; +import { ClimbingPanel } from './Climbing/ClimbingPanel'; +import { ClimbingContextProvider } from './Climbing/contexts/ClimbingContext'; +import { isClimbingRelation } from '../../services/osmApi'; +import { ParentLink } from './ParentLink'; +import { ImageSlider } from './ImagePane/ImageSlider'; +import { SuggestEdit } from './SuggestEdit'; + +const Flex = styled.div` + flex: 1; +`; + +export const FeaturePanelInner = () => { + const { feature } = useFeatureContext(); + + const [advanced, setAdvanced] = useState(false); + const [showAround, toggleShowAround] = useToggleState(false); + const [showTags, toggleShowTags] = useToggleState(false); + + const { point, tags, skeleton, deleted } = feature; + const editEnabled = !skeleton; + const showTagsTable = deleted || showTags || (!skeleton && !feature.schema); + + const osmappLink = getFullOsmappLink(feature); + const label = getLabel(feature); + + const footer = ( + + + +
+ {osmappLink} +
+ {' '} + + {!point && showAround && } +
+ ); + + if (!feature) { + return null; + } + + if ( + isClimbingRelation(feature) && // only for this condition is memberFeatures fetched + feature.tags.climbing === 'crag' && + !advanced + ) { + return ( + + + + ); + } + + return ( + <> + + + + + + + + {tags.climbing !== 'area' && ( + + + + )} + + + {!skeleton && ( + <> + + + + + + + {advanced && } + + + + {editEnabled && } + + {point && } + + + )} + + + {footer} + + + ); +}; diff --git a/src/components/FeaturePanel/ImagePane/Slider.tsx b/src/components/FeaturePanel/ImagePane/Slider.tsx index c4262f42d..c8128fb1a 100644 --- a/src/components/FeaturePanel/ImagePane/Slider.tsx +++ b/src/components/FeaturePanel/ImagePane/Slider.tsx @@ -7,7 +7,7 @@ import { useScrollShadow } from '../Climbing/utils/useScrollShadow'; const Wrapper = styled.div` width: 100%; text-align: center; - overflow: hidden; + /* overflow: hidden; */ margin-bottom: 1rem; position: relative; diff --git a/src/components/HomepagePanel/HomepagePanel.tsx b/src/components/HomepagePanel/HomepagePanel.tsx index 1906fbada..4817474f1 100644 --- a/src/components/HomepagePanel/HomepagePanel.tsx +++ b/src/components/HomepagePanel/HomepagePanel.tsx @@ -24,7 +24,7 @@ import { import { useMobileMode } from '../helpers'; export const Content = styled.div` - height: calc(100vh - 72px); // 100% - TopPanel - FeatureImage + height: calc(100% - 72px); // 100% - TopPanel - FeatureImage padding: 20px 2em 0 2em; a.maptiler { diff --git a/src/components/Map/BrowserMap.tsx b/src/components/Map/BrowserMap.tsx index 8274df98e..5e7b103c4 100644 --- a/src/components/Map/BrowserMap.tsx +++ b/src/components/Map/BrowserMap.tsx @@ -48,7 +48,7 @@ const BrowserMap = ({ onMapLoaded }) => { const { setFeature, setPreview } = useFeatureContext(); const [map, mapRef] = useInitMap(); useAddTopRightControls(map, mobileMode); - useOnMapClicked(map, setFeature, setPreview, mobileMode); + useOnMapClicked(map, setFeature, setPreview); useOnMapLongPressed(map, setPreview); useOnMapLoaded(map, onMapLoaded); useFeatureMarker(map); diff --git a/src/components/Map/behaviour/useOnMapClicked.tsx b/src/components/Map/behaviour/useOnMapClicked.tsx index 6e5ab9e5b..57d850c65 100644 --- a/src/components/Map/behaviour/useOnMapClicked.tsx +++ b/src/components/Map/behaviour/useOnMapClicked.tsx @@ -39,7 +39,7 @@ const getCoordsPreview = (coords, zoom) => { }; export const useOnMapClicked = createMapEventHook( - (map, setFeature, setPreview, mobileMode) => ({ + (map, setFeature, setPreview) => ({ eventType: 'click', eventHandler: async ({ point }) => { const coords = map.unproject(point).toArray(); diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx index d1447ec24..4b329b867 100644 --- a/src/components/SearchBox/SearchBox.tsx +++ b/src/components/SearchBox/SearchBox.tsx @@ -1,5 +1,5 @@ import React, { useRef, useState } from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import SearchIcon from '@mui/icons-material/Search'; import { CircularProgress, IconButton, Paper } from '@mui/material'; import Router from 'next/router'; @@ -12,15 +12,20 @@ import { SEARCH_BOX_HEIGHT } from './consts'; import { useInputValueState } from './options/geocoder'; import { useOptions } from './useOptions'; -const TopPanel = styled.div` +const TopPanel = styled.div<{ $isMobileMode: boolean }>` position: absolute; height: ${SEARCH_BOX_HEIGHT}px; - box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.12); - background-color: ${({ theme }) => theme.palette.background.searchBox}; + ${({ $isMobileMode }) => + !$isMobileMode && + css` + box-shadow: 0 10px 20px 0 rgba(0, 0, 0, 0.12); + background-color: ${({ theme }) => theme.palette.background.searchBox}; + `} + padding: 10px; box-sizing: border-box; - z-index: 1201; + z-index: 1; width: 100%; @media ${isDesktop} { @@ -32,6 +37,9 @@ const StyledPaper = styled(Paper)` padding: 2px 4px; display: flex; align-items: center; + background-color: ${({ theme }) => theme.palette.background.searchInput}; + -webkit-backdrop-filter: blur(35px); + backdrop-filter: blur(35px); .MuiAutocomplete-root { flex: 1; @@ -77,7 +85,7 @@ const SearchBox = () => { useOptions(inputValue, setOptions); return ( - + diff --git a/src/components/utils/PanelHelpers.tsx b/src/components/utils/PanelHelpers.tsx index 833753543..8d5f4897d 100644 --- a/src/components/utils/PanelHelpers.tsx +++ b/src/components/utils/PanelHelpers.tsx @@ -2,38 +2,30 @@ import React from 'react'; import styled from 'styled-components'; import { Scrollbars } from 'react-custom-scrollbars'; import { useTheme } from '@mui/material'; -// import { isDesktop } from '../helpers'; +import { isDesktop } from '../helpers'; import { useScrollShadow } from '../FeaturePanel/Climbing/utils/useScrollShadow'; -import { SEARCH_BOX_HEIGHT } from '../SearchBox/consts'; // custom scrollbar // better: https://github.com/rommguy/react-custom-scroll // maybe https://github.com/malte-wessel/react-custom-scrollbars (larger) -export const PanelWrapper = styled.div<{ fromLeft?: boolean }>` - /* position: absolute; */ - /* left: 0; */ - /* top: 72px; // TopPanel */ - /* bottom: 0; */ +export const PanelWrapper = styled.div` + position: absolute; + left: 0; + top: 72px; // TopPanel + bottom: 0; background: ${({ theme }) => theme.palette.background.paper}; color: ${({ theme }) => theme.palette.text.primary}; overflow: hidden; - /* z-index: 1100; */ + z-index: 1100; box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); display: flex; flex-direction: column; - ${({ fromLeft }) => - fromLeft - ? ` + width: 100%; + @media ${isDesktop} { width: 410px; - height: 100%; - margin-top: 72px; // TopPanel - ` - : ` - width: 100vw; - height: 100%; - `} + } & > div > div { // disable pulling panel around on mobile @@ -75,10 +67,7 @@ export const PanelScrollbars = ({ children }) => { export const PanelContent = styled.div` display: flex; flex-direction: column; - /* height: calc( - 100vh - ${SEARCH_BOX_HEIGHT}px - 238px - ); // 100% - TopPanel - FeatureImage */ - padding: 20px 0 0 0; + height: 100%; `; export const PanelFooter = styled.div` diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index d88e85a8d..345ca0414 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -105,7 +105,7 @@ export const GlobalStyle = createGlobalStyle` } .MuiDrawer-root > .MuiPaper-root { - height: calc(90vh - 72px); + height: calc(100% - 86px - 8px); overflow: visible; } `; diff --git a/src/helpers/theme.tsx b/src/helpers/theme.tsx index be66d4f46..392274ae9 100644 --- a/src/helpers/theme.tsx +++ b/src/helpers/theme.tsx @@ -27,6 +27,7 @@ const lightTheme = createTheme({ paper: '#fafafa', hover: '#f2f3f2', searchBox: '#eb5757', + searchInput: 'rgba(255,255,255,0.7)', }, invertFilter: 'invert(0)', climbing: { @@ -66,6 +67,7 @@ const darkTheme = createTheme({ paper: '#424242', hover: grey['700'], searchBox: '#963838', + searchInput: 'rgba(0,0,0,0.6)', }, invertFilter: 'invert(1)', climbing: { diff --git a/types.d.ts b/types.d.ts index 0c0ff0793..351812819 100644 --- a/types.d.ts +++ b/types.d.ts @@ -39,6 +39,7 @@ declare module '@mui/material/styles' { elevation?: string; hover?: string; searchBox?: string; + searchInput?: string; } interface Theme { From 8c903b68567635fbd336fe2a5b28ef32a1c729ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sun, 30 Jun 2024 09:50:52 +0200 Subject: [PATCH 03/15] move icons to SearchBox in mobileMode --- .../Map/TopMenu/HamburgerIconButton.tsx | 7 +++++++ src/components/Map/TopMenu/HamburgerMenu.tsx | 1 + .../Map/TopMenu/LoginIconButton.tsx | 8 ++++++++ src/components/Map/TopMenu/TopMenu.tsx | 20 ++++++++++++------- src/components/SearchBox/SearchBox.tsx | 8 ++++++++ src/components/helpers.tsx | 7 ++++--- 6 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/components/Map/TopMenu/HamburgerIconButton.tsx b/src/components/Map/TopMenu/HamburgerIconButton.tsx index 0d5fd69f3..4325c3c40 100644 --- a/src/components/Map/TopMenu/HamburgerIconButton.tsx +++ b/src/components/Map/TopMenu/HamburgerIconButton.tsx @@ -3,6 +3,7 @@ import MenuIcon from '@mui/icons-material/Menu'; import React from 'react'; import styled from 'styled-components'; import { t } from '../../../services/intl'; +import { isMobileMode } from '../../helpers'; const StyledIconButton = styled(IconButton)` padding: 12px; @@ -11,6 +12,12 @@ const StyledIconButton = styled(IconButton)` svg { filter: drop-shadow(0 0 2px #ffffff); } + @media ${isMobileMode} { + svg { + filter: none; + filter: invert(100%); + } + } `; export const HamburgerIconButton = ({ anchorRef, onClick }) => ( diff --git a/src/components/Map/TopMenu/HamburgerMenu.tsx b/src/components/Map/TopMenu/HamburgerMenu.tsx index 5cc91a9b7..1b25a9545 100644 --- a/src/components/Map/TopMenu/HamburgerMenu.tsx +++ b/src/components/Map/TopMenu/HamburgerMenu.tsx @@ -176,6 +176,7 @@ export const HamburgerMenu = () => { ( - - - - -); +export const TopMenu = () => { + const isMobileMode = useMobileMode(); + + if (isMobileMode) return null; + + return ( + + + + + ); +}; diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx index 4b329b867..80a636070 100644 --- a/src/components/SearchBox/SearchBox.tsx +++ b/src/components/SearchBox/SearchBox.tsx @@ -11,6 +11,8 @@ import { isDesktop, useMobileMode } from '../helpers'; import { SEARCH_BOX_HEIGHT } from './consts'; import { useInputValueState } from './options/geocoder'; import { useOptions } from './useOptions'; +import { HamburgerMenu } from '../Map/TopMenu/HamburgerMenu'; +import { LoginMenu } from '../Map/TopMenu/LoginMenu'; const TopPanel = styled.div<{ $isMobileMode: boolean }>` position: absolute; @@ -102,6 +104,12 @@ const SearchBox = () => { {featureShown && !isMobileMode && ( )} + {isMobileMode && ( + <> + + + + )} {overpassLoading && } diff --git a/src/components/helpers.tsx b/src/components/helpers.tsx index edf476be7..0da1ce605 100644 --- a/src/components/helpers.tsx +++ b/src/components/helpers.tsx @@ -87,10 +87,11 @@ export const dotToOptionalBr = (url = '') => export const trimText = (text, limit) => text?.length > limit ? `${text?.substring(0, limit)}…` : text; -// (<= tablet size) MobileMode shows preview instead of panel -export const useMobileMode = () => useMediaQuery('(max-width: 700px)'); +// (<= tablet size) MobileMode shows FeaturePanel in Drawer (instead of side) +export const isMobileMode = '(max-width: 700px)'; +export const useMobileMode = () => useMediaQuery(isMobileMode); -// (>= mobile size) This changes just the app layout +// (>= mobile size) SearchBox stops growing export const isDesktop = '(min-width: 500px)'; // is mobile device - specific behaviour like longpress or geouri From 6fb968aa3e59a6813679990210ab56c362c26a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sun, 30 Jun 2024 10:16:25 +0200 Subject: [PATCH 04/15] remove PreviewButton + setters --- .../FeaturePanel/MemberFeatures.tsx | 6 +- src/components/FeaturePanel/ObjectsAround.tsx | 3 +- .../FeaturePreview/FeaturePreview.tsx | 58 ----------------- .../HomepagePanel/HomepagePanel.tsx | 8 +-- src/components/Map/BrowserMap.tsx | 6 +- .../Map/behaviour/useOnMapClicked.tsx | 64 +++++++++---------- .../Map/behaviour/useOnMapLongPressed.tsx | 6 +- .../SearchBox/AutocompleteInput.tsx | 3 - src/components/SearchBox/SearchBox.tsx | 6 +- .../SearchBox/onHighlightFactory.ts | 8 ++- src/components/SearchBox/onSelectedFactory.ts | 14 ++-- src/services/types.ts | 3 - 12 files changed, 54 insertions(+), 131 deletions(-) delete mode 100644 src/components/FeaturePreview/FeaturePreview.tsx diff --git a/src/components/FeaturePanel/MemberFeatures.tsx b/src/components/FeaturePanel/MemberFeatures.tsx index abb1494ee..157b1165e 100644 --- a/src/components/FeaturePanel/MemberFeatures.tsx +++ b/src/components/FeaturePanel/MemberFeatures.tsx @@ -93,8 +93,7 @@ const Item = ({ feature }: { feature: Feature }) => { setPreview(null); Router.push(`/${getUrlOsmId(osmMeta)}${window.location.hash}`); }; - const handleHover = () => - feature.center && setPreview({ ...feature, noPreviewButton: true }); + const handleHover = () => feature.center && setPreview(feature); return (
  • @@ -128,8 +127,7 @@ const CragItem = ({ feature }: { feature: Feature }) => { setPreview(null); Router.push(`/${getUrlOsmId(osmMeta)}${window.location.hash}`); }; - const handleHover = () => - feature.center && setPreview({ ...feature, noPreviewButton: true }); + const handleHover = () => feature.center && setPreview(feature); const cragPhotoKeys = getWikimediaCommonsKeys(feature.tags); diff --git a/src/components/FeaturePanel/ObjectsAround.tsx b/src/components/FeaturePanel/ObjectsAround.tsx index 8b35a36fd..387b4c06e 100644 --- a/src/components/FeaturePanel/ObjectsAround.tsx +++ b/src/components/FeaturePanel/ObjectsAround.tsx @@ -41,8 +41,7 @@ const AroundItem = ({ feature }: { feature: Feature }) => { setPreview(null); Router.push(`/${getUrlOsmId(osmMeta)}${window.location.hash}`); }; - const handleHover = () => - feature.center && setPreview({ ...feature, noPreviewButton: true }); + const handleHover = () => feature.center && setPreview(feature); return (
  • diff --git a/src/components/FeaturePreview/FeaturePreview.tsx b/src/components/FeaturePreview/FeaturePreview.tsx deleted file mode 100644 index bc9e68df5..000000000 --- a/src/components/FeaturePreview/FeaturePreview.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import React from 'react'; -import styled from 'styled-components'; -import { Button } from '@mui/material'; -import Router from 'next/router'; -import { useFeatureContext } from '../utils/FeatureContext'; -import { ClosePanelButton } from '../utils/ClosePanelButton'; -import { getOsmappLink } from '../../services/helpers'; -import Maki from '../utils/Maki'; -import { getLabel } from '../../helpers/featureLabel'; - -const Wrapper = styled.div` - position: absolute; - z-index: 1200; // 1300 is mui-dialog - bottom: 40px; - left: 45%; - max-width: 45vw; - - .MuiButtonBase-root { - text-transform: none; - } -`; - -export const FeaturePreview = () => { - const { preview, setPreview, setFeature } = useFeatureContext(); - - if (!preview || preview.noPreviewButton) { - return null; - } - Router.push(`${getOsmappLink(preview)}${window.location.hash}`); - - const handleClick = () => { - setPreview(null); - setFeature({ ...preview, skeleton: true }); // skeleton needed so map doesnt move (Router will create new coordsFeature) - Router.push(`${getOsmappLink(preview)}${window.location.hash}`); // this will create brand new coordsFeature() - }; - - const onClose = () => { - setPreview(null); - }; - - return ( - - - - - ); -}; diff --git a/src/components/HomepagePanel/HomepagePanel.tsx b/src/components/HomepagePanel/HomepagePanel.tsx index 4817474f1..190217b99 100644 --- a/src/components/HomepagePanel/HomepagePanel.tsx +++ b/src/components/HomepagePanel/HomepagePanel.tsx @@ -83,14 +83,14 @@ const ExamplesClimbing = () => ( ); export const HomepagePanel = () => { - const { feature, preview, homepageShown, hideHomepage, persistHideHomepage } = + const { feature, homepageShown, hideHomepage, persistHideHomepage } = useFeatureContext(); const isMobileMode = useMobileMode(); - // hide after first shown feature or preview + // hide after first shown feature useEffect(() => { - if (feature || preview) hideHomepage(); - }, [feature, preview]); + if (feature) hideHomepage(); + }, [feature]); if (!homepageShown) { return null; diff --git a/src/components/Map/BrowserMap.tsx b/src/components/Map/BrowserMap.tsx index 5e7b103c4..9ce5a5273 100644 --- a/src/components/Map/BrowserMap.tsx +++ b/src/components/Map/BrowserMap.tsx @@ -45,11 +45,11 @@ const BrowserMap = ({ onMapLoaded }) => { } const mobileMode = useMobileMode(); - const { setFeature, setPreview } = useFeatureContext(); + const { setFeature } = useFeatureContext(); const [map, mapRef] = useInitMap(); useAddTopRightControls(map, mobileMode); - useOnMapClicked(map, setFeature, setPreview); - useOnMapLongPressed(map, setPreview); + useOnMapClicked(map, setFeature); + useOnMapLongPressed(map, setFeature); useOnMapLoaded(map, onMapLoaded); useFeatureMarker(map); diff --git a/src/components/Map/behaviour/useOnMapClicked.tsx b/src/components/Map/behaviour/useOnMapClicked.tsx index 57d850c65..7954968de 100644 --- a/src/components/Map/behaviour/useOnMapClicked.tsx +++ b/src/components/Map/behaviour/useOnMapClicked.tsx @@ -29,46 +29,44 @@ export const getSkeleton = (feature, clickCoords) => { }; }; -const getCoordsPreview = (coords, zoom) => { +const coordsFeatureSetter = (coords, zoom) => { if (isMobileDevice()) { return null; // handled by useOnMapLongPressed } - return (preview) => - preview ? null : getCoordsFeature(getRoundedPosition(coords, zoom)); + return (previousFeature) => + previousFeature ? null : getCoordsFeature(getRoundedPosition(coords, zoom)); }; -export const useOnMapClicked = createMapEventHook( - (map, setFeature, setPreview) => ({ - eventType: 'click', - eventHandler: async ({ point }) => { - const coords = map.unproject(point).toArray(); - const features = map.queryRenderedFeatures(point); - if (!features.length) { - setPreview(getCoordsPreview(coords, map.getZoom())); - return; - } +export const useOnMapClicked = createMapEventHook((map, setFeature) => ({ + eventType: 'click', + eventHandler: async ({ point }) => { + const coords = map.unproject(point).toArray(); + const features = map.queryRenderedFeatures(point); + if (!features.length) { + setFeature(coordsFeatureSetter(coords, map.getZoom())); + return; + } - const skeleton = getSkeleton(features[0], coords); - console.log(`clicked map feature (id=${features[0].id}): `, features[0]); // eslint-disable-line no-console - publishDbgObject('last skeleton', skeleton); + const skeleton = getSkeleton(features[0], coords); + console.log(`clicked map feature (id=${features[0].id}): `, features[0]); // eslint-disable-line no-console + publishDbgObject('last skeleton', skeleton); - if (skeleton.nonOsmObject) { - setPreview(getCoordsPreview(coords, map.getZoom())); - return; - } + if (skeleton.nonOsmObject) { + setFeature(coordsFeatureSetter(coords, map.getZoom())); + return; + } - // router wouldnt overwrite the skeleton if same url is already loaded - setFeature((feature) => - isSameOsmId(feature, skeleton) ? feature : skeleton, - ); - setPreview(null); + // router wouldnt overwrite the skeleton if same url is already loaded + setFeature((feature) => + isSameOsmId(feature, skeleton) ? feature : skeleton, + ); + setFeature(null); - const result = await maptilerFix(features[0], skeleton, features[0].id); - addFeatureCenterToCache(getShortId(skeleton.osmMeta), skeleton.center); // for ways/relations we dont receive center from OSM API - addFeatureCenterToCache(getShortId(result.osmMeta), skeleton.center); - const url = `/${getUrlOsmId(result.osmMeta)}${window.location.hash}`; - Router.push(url, undefined, { locale: 'default' }); - }, - }), -); + const result = await maptilerFix(features[0], skeleton, features[0].id); + addFeatureCenterToCache(getShortId(skeleton.osmMeta), skeleton.center); // for ways/relations we dont receive center from OSM API + addFeatureCenterToCache(getShortId(result.osmMeta), skeleton.center); + const url = `/${getUrlOsmId(result.osmMeta)}${window.location.hash}`; + Router.push(url, undefined, { locale: 'default' }); + }, +})); diff --git a/src/components/Map/behaviour/useOnMapLongPressed.tsx b/src/components/Map/behaviour/useOnMapLongPressed.tsx index 99c98650c..14036cd21 100644 --- a/src/components/Map/behaviour/useOnMapLongPressed.tsx +++ b/src/components/Map/behaviour/useOnMapLongPressed.tsx @@ -64,7 +64,7 @@ const emulatedLongPressListeners = (map, eventHandler) => { // return () => map.off('contextmenu', eventHandler); // }; -export const useOnMapLongPressed = (map, setPreview) => { +export const useOnMapLongPressed = (map, setFeature) => { useEffect(() => { if (!map) { return undefined; @@ -77,9 +77,9 @@ export const useOnMapLongPressed = (map, setPreview) => { const showCoords = ({ point }) => { const coords = map.unproject(point).toArray(); const roundedPosition = getRoundedPosition(coords, map.getZoom()); - setPreview(getCoordsFeature(roundedPosition)); + setFeature(getCoordsFeature(roundedPosition)); }; return emulatedLongPressListeners(map, showCoords); - }, [map, setPreview]); + }, [map, setFeature]); }; diff --git a/src/components/SearchBox/AutocompleteInput.tsx b/src/components/SearchBox/AutocompleteInput.tsx index a855642b9..661c2011e 100644 --- a/src/components/SearchBox/AutocompleteInput.tsx +++ b/src/components/SearchBox/AutocompleteInput.tsx @@ -4,7 +4,6 @@ import { useFeatureContext } from '../utils/FeatureContext'; import { renderOptionFactory } from './renderOptionFactory'; import { t } from '../../services/intl'; import { onSelectedFactory } from './onSelectedFactory'; -import { useMobileMode } from '../helpers'; import { useUserThemeContext } from '../../helpers/theme'; import { useMapStateContext } from '../utils/MapStateContext'; import { onHighlightFactory } from './onHighlightFactory'; @@ -67,7 +66,6 @@ export const AutocompleteInput = ({ const { setFeature, setPreview } = useFeatureContext(); const { bbox, showToast } = useMapStateContext(); const mapCenter = useMapCenter(); - const mobileMode = useMobileMode(); const { currentTheme } = useUserThemeContext(); return ( { - const { feature, setFeature, setPreview } = useFeatureContext(); - const mobileMode = useMobileMode(); + const { setFeature } = useFeatureContext(); return () => { - if (mobileMode) { - setPreview(feature); - } setFeature(null); Router.push(`/${window.location.hash}`); }; diff --git a/src/components/SearchBox/onHighlightFactory.ts b/src/components/SearchBox/onHighlightFactory.ts index c98984a55..dbbf4a60d 100644 --- a/src/components/SearchBox/onHighlightFactory.ts +++ b/src/components/SearchBox/onHighlightFactory.ts @@ -31,10 +31,12 @@ export const getSkeleton = (option) => { export const onHighlightFactory = (setPreview) => (e, option) => { if (option?.star?.center) { const { center } = option.star; - setPreview({ center, noPreviewButton: true }); + setPreview({ center }); return; } - if (!option?.geometry?.coordinates) return; - setPreview({ ...getSkeleton(option), noPreviewButton: true }); + if (option?.geometry?.coordinates) { + setPreview(getSkeleton(option)); + + } }; diff --git a/src/components/SearchBox/onSelectedFactory.ts b/src/components/SearchBox/onSelectedFactory.ts index f241ad119..e9ff746d6 100644 --- a/src/components/SearchBox/onSelectedFactory.ts +++ b/src/components/SearchBox/onSelectedFactory.ts @@ -45,7 +45,7 @@ const starOptionSelected = (option) => { Router.push(`/${getUrlOsmId(apiId)}`); }; -const geocoderOptionSelected = (option, mobileMode, setPreview, setFeature) => { +const geocoderOptionSelected = (option, setFeature) => { if (!option?.geometry.coordinates) return; const skeleton = getSkeleton(option); @@ -53,21 +53,15 @@ const geocoderOptionSelected = (option, mobileMode, setPreview, setFeature) => { addFeatureCenterToCache(getShortId(skeleton.osmMeta), skeleton.center); - if (mobileMode) { - setPreview(skeleton); - fitBounds(option); - return; - } - setFeature(skeleton); fitBounds(option, true); Router.push(`/${getUrlOsmId(skeleton.osmMeta)}`); }; export const onSelectedFactory = - (setFeature, setPreview, mobileMode, bbox, showToast, setOverpassLoading) => + (setFeature, setPreview, bbox, showToast, setOverpassLoading) => (_, option) => { - setPreview(null); + setPreview(null); // it could be stuck from onHighlight if (option.star) { starOptionSelected(option); @@ -79,5 +73,5 @@ export const onSelectedFactory = return; } - geocoderOptionSelected(option, mobileMode, setPreview, setFeature); + geocoderOptionSelected(option, setFeature); }; diff --git a/src/services/types.ts b/src/services/types.ts index ffadff7c5..67dc44e18 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -125,9 +125,6 @@ export interface Feature { state?: { hover: boolean }; skeleton?: boolean; nonOsmObject?: boolean; - - // preview - noPreviewButton?: boolean; } export type MessagesType = typeof Vocabulary; From 53e31238b6b3645b733a617315493ba225618159 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sun, 30 Jun 2024 10:41:40 +0200 Subject: [PATCH 05/15] fix Paper height --- src/components/FeaturePanel/FeaturePanelInDrawer.tsx | 12 ++++++++++-- src/components/Map/behaviour/useOnMapClicked.tsx | 1 - src/components/SearchBox/onHighlightFactory.ts | 1 - src/helpers/GlobalStyle.tsx | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx index c2b08afd9..b09198655 100644 --- a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx +++ b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx @@ -5,6 +5,13 @@ import styled from 'styled-components'; import { grey } from '@mui/material/colors'; import { FeaturePanelInner } from './FeaturePanelInner'; +const StyledSwipeableDrawer = styled(SwipeableDrawer)` + .MuiDrawer-root > .MuiPaper-root { + height: calc(100% - 86px - 8px); + overflow: visible; + } +`; + const Container = styled.div` position: relative; background: ${({ theme }) => theme.palette.background.paper}; @@ -40,7 +47,7 @@ export const FeaturePanelInDrawer = () => { const [open, setOpen] = useState(false); return ( - setOpen(false)} @@ -52,6 +59,7 @@ export const FeaturePanelInDrawer = () => { ModalProps={{ keepMounted: true, }} + className="featurePanelInDrawer" > @@ -59,6 +67,6 @@ export const FeaturePanelInDrawer = () => { - + ); }; diff --git a/src/components/Map/behaviour/useOnMapClicked.tsx b/src/components/Map/behaviour/useOnMapClicked.tsx index 7954968de..61c7e6a9f 100644 --- a/src/components/Map/behaviour/useOnMapClicked.tsx +++ b/src/components/Map/behaviour/useOnMapClicked.tsx @@ -61,7 +61,6 @@ export const useOnMapClicked = createMapEventHook((map, setFeature) => ({ setFeature((feature) => isSameOsmId(feature, skeleton) ? feature : skeleton, ); - setFeature(null); const result = await maptilerFix(features[0], skeleton, features[0].id); addFeatureCenterToCache(getShortId(skeleton.osmMeta), skeleton.center); // for ways/relations we dont receive center from OSM API diff --git a/src/components/SearchBox/onHighlightFactory.ts b/src/components/SearchBox/onHighlightFactory.ts index dbbf4a60d..5834a5656 100644 --- a/src/components/SearchBox/onHighlightFactory.ts +++ b/src/components/SearchBox/onHighlightFactory.ts @@ -37,6 +37,5 @@ export const onHighlightFactory = (setPreview) => (e, option) => { if (option?.geometry?.coordinates) { setPreview(getSkeleton(option)); - } }; diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 345ca0414..6b065eead 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -104,7 +104,7 @@ export const GlobalStyle = createGlobalStyle` display: none; } - .MuiDrawer-root > .MuiPaper-root { + .featurePanelInDrawer.MuiDrawer-root > .MuiPaper-root { height: calc(100% - 86px - 8px); overflow: visible; } From 8c31a662671fbed7405b3188c6454e93090b230f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Mon, 1 Jul 2024 23:54:12 +0200 Subject: [PATCH 06/15] Fix UX on desktop when mobile view is active --- src/components/App/App.tsx | 1 + .../FeaturePanel/Climbing/ClimbingPanel.tsx | 68 ++------------ .../FeaturePanel/FeatureHeading.tsx | 77 +++++++++++++--- .../FeaturePanel/FeaturePanelInDrawer.tsx | 90 ++++++++++++++++--- .../FeaturePanel/FeaturePanelInner.tsx | 6 +- .../FeaturePanel/ImagePane/Slider.tsx | 5 +- .../ImageSection/FeatureImage.tsx | 34 +------ .../ImageSection/ImageSection.tsx | 37 +------- .../ImageSection/PoiDescription.tsx | 27 ++---- src/components/FeaturePanel/ParentLink.tsx | 39 ++++---- src/components/Map/TopMenu/HamburgerMenu.tsx | 1 - src/components/helpers.tsx | 3 + src/helpers/GlobalStyle.tsx | 11 ++- 13 files changed, 189 insertions(+), 210 deletions(-) diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 0d8dec4f7..d1b8994fa 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -100,6 +100,7 @@ const IndexWithProviders = () => { const App = ({ featureFromRouter, initialMapView, cookies }) => { const mapView = getMapViewFromHash() || initialMapView; + return ( diff --git a/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx b/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx index 1c0d8d8e3..263bee6a6 100644 --- a/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx +++ b/src/components/FeaturePanel/Climbing/ClimbingPanel.tsx @@ -1,54 +1,22 @@ import React from 'react'; -import styled from 'styled-components'; -import Router from 'next/router'; -import ZoomInIcon from '@mui/icons-material/ZoomIn'; -import { Button } from '@mui/material'; import { useClimbingContext } from './contexts/ClimbingContext'; import { RouteList } from './RouteList/RouteList'; import { useFeatureContext } from '../../utils/FeatureContext'; -import { getLabel } from '../../../helpers/featureLabel'; -import { getOsmappLink } from '../../../services/helpers'; -import { StarButton } from '../ImageSection/StarButton'; import { OsmError } from '../OsmError'; import { Properties } from '../Properties/Properties'; -import { PoiDescription } from '../ImageSection/PoiDescription'; import { ImageSlider } from '../ImagePane/ImageSlider'; -import { ClimbingParentLink } from '../ParentLink'; import { RouteDistribution } from './RouteDistribution'; -import { YellowedBadge } from './YellowedBadge'; import { getWikimediaCommonsKeys, removeFilePrefix } from './utils/photo'; import { SuggestEdit } from '../SuggestEdit'; -import { PanelContent } from '../../utils/PanelHelpers'; - -const HeadingContainer = styled.div` - display: flex; - justify-content: space-between; - align-items: center; -`; - -const DetailButtonContainer = styled.div` - margin: 8px; - @supports (-webkit-touch-callout: none) { - /* CSS specific to iOS devices */ - margin-bottom: 28px; - } -`; - -const Heading = styled.div` - margin: 12px 8px 4px; - font-size: 36px; - line-height: 0.98; -`; +import { PanelContent, PanelSidePadding } from '../../utils/PanelHelpers'; +import { FeatureHeading } from '../FeatureHeading'; +import { ParentLink } from '../ParentLink'; export const ClimbingPanel = ({ footer, showTagsTable }) => { const { feature } = useFeatureContext(); - const label = getLabel(feature); const { preparePhotosAndSet } = useClimbingContext(); - const onFullScreenClick = () => { - Router.push(`${getOsmappLink(feature)}/climbing${window.location.hash}`); - }; const cragPhotos = getWikimediaCommonsKeys(feature.tags) .map((key) => feature.tags[key]) .map(removeFilePrefix); @@ -56,20 +24,12 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => { return ( - {/* - */} - - - - {label} - - - - - + + + + - @@ -80,20 +40,6 @@ export const ClimbingPanel = ({ footer, showTagsTable }) => { {/* @TODO unite with parent panel */}
    {footer}
    - {/*
    */} - - - - {/*
    */}
    ); }; diff --git a/src/components/FeaturePanel/FeatureHeading.tsx b/src/components/FeaturePanel/FeatureHeading.tsx index dab49ca4a..d0c764d60 100644 --- a/src/components/FeaturePanel/FeatureHeading.tsx +++ b/src/components/FeaturePanel/FeatureHeading.tsx @@ -1,28 +1,77 @@ import React from 'react'; import styled from 'styled-components'; -import { EditIconButton } from './helpers/EditIconButton'; +import EditIcon from '@mui/icons-material/Edit'; +import { IconButton } from '@mui/material'; import { useEditDialogContext } from './helpers/EditDialogContext'; +import { PoiDescription } from './ImageSection/PoiDescription'; +import { StarButton } from './ImageSection/StarButton'; +import { getLabel } from '../../helpers/featureLabel'; +import { useFeatureContext } from '../utils/FeatureContext'; +import { t } from '../../services/intl'; -const Wrapper = styled.div<{ $deleted: boolean }>` - font-size: 36px; - line-height: 0.98; +const StyledEditButton = styled(IconButton)` + visibility: hidden; position: relative; - padding-bottom: 30px; - ${({ $deleted }) => $deleted && 'text-decoration: line-through;'} + top: 3px; +`; +const NameWithEdit = styled.div` + display: flex; + gap: 8px; +`; +const Container = styled.div` + margin: 12px 0 20px 0; +`; + +const HeadingContainer = styled.div` + margin: 6px 0 4px 0; - padding: 25px 20px; - &:hover .show-on-hover { - display: block !important; + display: flex; + justify-content: space-between; + align-items: flex-start; + position: relative; + + &:hover ${StyledEditButton} { + visibility: visible; } `; -export const FeatureHeading = ({ title, deleted, editEnabled }) => { +const Heading = styled.h1<{ $deleted: boolean }>` + font-size: 36px; + line-height: 0.98; + margin: 0; + ${({ $deleted }) => $deleted && 'text-decoration: line-through;'} +`; + +export const FeatureHeading = () => { const { openWithTag } = useEditDialogContext(); + const { feature } = useFeatureContext(); + const label = getLabel(feature); + const { skeleton, deleted } = feature; + const editEnabled = !skeleton; return ( - - {editEnabled && openWithTag('name')} />} - {title} - + + + + + {label} + {/* */} + {editEnabled && ( +
    + openWithTag('name')} + size="small" + > + + +
    + )} +
    + +
    +
    ); }; diff --git a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx index b09198655..850f31289 100644 --- a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx +++ b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx @@ -1,13 +1,20 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { SwipeableDrawer } from '@mui/material'; import styled from 'styled-components'; import { grey } from '@mui/material/colors'; import { FeaturePanelInner } from './FeaturePanelInner'; +import { + DRAWER_PREVIEW_HEIGHT, + DRAWER_TOP_OFFSET, + isMobileDevice, + useMobileMode, +} from '../helpers'; const StyledSwipeableDrawer = styled(SwipeableDrawer)` .MuiDrawer-root > .MuiPaper-root { - height: calc(100% - 86px - 8px); + pointer-events: all !important; + height: calc(100% - ${DRAWER_PREVIEW_HEIGHT}px - ${DRAWER_TOP_OFFSET}px); overflow: visible; } `; @@ -22,47 +29,104 @@ const Container = styled.div` right: 0; left: 0; box-shadow: 0 0 20px rgba(0, 0, 0, 0.2); - height: 100%; + height: calc(100% + ${DRAWER_PREVIEW_HEIGHT}px + ${DRAWER_TOP_OFFSET}px); `; -const Puller = styled.div` - width: 30px; +const PULLER_WIDTH = 30; +const PULLER_HIP_SLOP = 10; + +const Puller = styled.div<{ isHovered: boolean }>` + width: ${PULLER_WIDTH}px; height: 6px; background-color: ${({ theme }) => theme.palette.mode === 'light' ? grey[300] : grey[900]}; border-radius: 3px; + + ${({ isHovered, theme }) => + isHovered && `background-color: ${theme.palette.primary.main};`}; +`; + +const PullerContainer = styled.div` position: absolute; - pointer-events: none; - top: 8px; - left: calc(50% - 15px); + z-index: 1; + top: 0px; + left: calc(50% - ${PULLER_WIDTH / 2}px - ${PULLER_HIP_SLOP}px); + padding: ${PULLER_HIP_SLOP}px; + cursor: pointer; + + &:hover ${Puller} { + background-color: ${({ theme }) => theme.palette.primary.main}; + } `; const ListContainer = styled('div')(() => ({ - maxHeight: 'calc(100% - 8px)', + maxHeight: `calc(100% - ${DRAWER_TOP_OFFSET}px)`, height: '100%', overflow: 'auto', })); export const FeaturePanelInDrawer = () => { const [open, setOpen] = useState(false); + const [isHovered, setIsHovered] = useState(false); + const hasMobileResolution = useMobileMode(); + const isDesktop = !isMobileDevice(); + + const handleOnOpen = () => setOpen(true); + const handleOnClose = () => setOpen(false); + + useEffect(() => { + if (isDesktop && hasMobileResolution) { + const swipeAreaElement = document.querySelector('.PrivateSwipeArea-root'); + + const handleSwipeAreaClick = () => { + setOpen(true); + }; + const handleOnMouseOver = () => { + setIsHovered(true); + }; + const handleOnMouseOut = () => { + setIsHovered(false); + }; + + if (swipeAreaElement) { + swipeAreaElement.addEventListener('click', handleSwipeAreaClick); + swipeAreaElement.addEventListener('mouseover', handleOnMouseOver); + swipeAreaElement.addEventListener('mouseout', handleOnMouseOut); + } + return () => { + if (swipeAreaElement) { + swipeAreaElement.removeEventListener('click', handleSwipeAreaClick); + swipeAreaElement.removeEventListener('mouseover', handleOnMouseOver); + swipeAreaElement.removeEventListener('mouseout', handleOnMouseOut); + } + }; + } + return () => null; + }, [hasMobileResolution, isDesktop, setIsHovered]); return ( setOpen(false)} - onOpen={() => { - setOpen(true); + onClose={handleOnClose} + onOpen={handleOnOpen} + style={{ + pointerEvents: 'all', }} swipeAreaWidth={86} disableSwipeToOpen={false} ModalProps={{ keepMounted: true, }} + SwipeAreaProps={{ + cursor: 'pointer', + }} className="featurePanelInDrawer" > - + + + diff --git a/src/components/FeaturePanel/FeaturePanelInner.tsx b/src/components/FeaturePanel/FeaturePanelInner.tsx index 9399b8c4a..429de5567 100644 --- a/src/components/FeaturePanel/FeaturePanelInner.tsx +++ b/src/components/FeaturePanel/FeaturePanelInner.tsx @@ -95,12 +95,8 @@ export const FeaturePanelInner = () => { <> + - diff --git a/src/components/FeaturePanel/ImagePane/Slider.tsx b/src/components/FeaturePanel/ImagePane/Slider.tsx index c8128fb1a..8334ea78a 100644 --- a/src/components/FeaturePanel/ImagePane/Slider.tsx +++ b/src/components/FeaturePanel/ImagePane/Slider.tsx @@ -21,6 +21,9 @@ const Wrapper = styled.div` padding-left: 16px; padding-right: 16px; + + padding-top: 16px; + padding-bottom: 16px; } .slides > div { @@ -29,8 +32,6 @@ const Wrapper = styled.div` align-items: center; position: relative; - margin-top: 16px; - margin-bottom: 16px; } `; diff --git a/src/components/FeaturePanel/ImageSection/FeatureImage.tsx b/src/components/FeaturePanel/ImageSection/FeatureImage.tsx index 0255fbfda..c83759ecb 100644 --- a/src/components/FeaturePanel/ImageSection/FeatureImage.tsx +++ b/src/components/FeaturePanel/ImageSection/FeatureImage.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react'; +import React from 'react'; import styled from 'styled-components'; @@ -21,33 +21,6 @@ const Wrapper = styled.div<{ $uncertainImage: boolean }>` : ''} `; -const GradientCover = styled.div` - pointer-events: none; - position: absolute; - width: 100%; - height: 100%; - top: 0; - bottom: 0; - left: 0; - right: 0; - opacity: 0.6; - background: linear-gradient( - to bottom, - rgba(0, 0, 0, 0) 70%, - rgba(0, 0, 0, 0.15) 76%, - #000000 - ); -`; - -const Bottom = styled.div` - position: absolute; - bottom: 0; - display: flex; - align-items: center; - width: 100%; - height: 44px; -`; - const IconWrapper = styled.div` padding-top: 40px; text-align: center; @@ -83,10 +56,9 @@ const AttributionLink = styled.a<{ $portrait: boolean }>` interface Props { feature: Feature; ico: string; - children: ReactNode; } -export const FeatureImage = ({ feature, ico, children }: Props) => { +export const FeatureImage = ({ feature, ico }: Props) => { const [image, setImage] = React.useState(feature.ssrFeatureImage ?? LOADING); React.useEffect(() => { @@ -116,7 +88,6 @@ export const FeatureImage = ({ feature, ico, children }: Props) => { {image && image !== LOADING && ( )} - {(image === undefined || image === LOADING) && ( {ico} @@ -135,7 +106,6 @@ export const FeatureImage = ({ feature, ico, children }: Props) => { )} {!feature.skeleton && image === LOADING && } - {children} ); }; diff --git a/src/components/FeaturePanel/ImageSection/ImageSection.tsx b/src/components/FeaturePanel/ImageSection/ImageSection.tsx index 7ec73ee4d..a99348ee7 100644 --- a/src/components/FeaturePanel/ImageSection/ImageSection.tsx +++ b/src/components/FeaturePanel/ImageSection/ImageSection.tsx @@ -1,45 +1,10 @@ -import Share from '@mui/icons-material/Share'; -import Directions from '@mui/icons-material/Directions'; import React from 'react'; import { useFeatureContext } from '../../utils/FeatureContext'; import { FeatureImage } from './FeatureImage'; -import { t } from '../../../services/intl'; -import { SHOW_PROTOTYPE_UI } from '../../../config'; -import { PoiDescriptionDark } from './PoiDescription'; -import { StarButtonDark } from './StarButton'; -import { StyledActionButton } from './utils'; export const ImageSection = () => { const { feature } = useFeatureContext(); const { properties } = feature; - return ( - - - - {SHOW_PROTOTYPE_UI && ( - <> - - - - - )} - - - - {SHOW_PROTOTYPE_UI && ( - <> - - - - - )} - - ); + return ; }; diff --git a/src/components/FeaturePanel/ImageSection/PoiDescription.tsx b/src/components/FeaturePanel/ImageSection/PoiDescription.tsx index 331f69af0..8a64bd80b 100644 --- a/src/components/FeaturePanel/ImageSection/PoiDescription.tsx +++ b/src/components/FeaturePanel/ImageSection/PoiDescription.tsx @@ -5,16 +5,16 @@ import { useFeatureContext } from '../../utils/FeatureContext'; import Maki from '../../utils/Maki'; import { useUserThemeContext } from '../../../helpers/theme'; -const PoiType = styled.div<{ $isSkeleton: Boolean; $forceWhite?: Boolean }>` - color: ${({ $forceWhite, theme }) => - $forceWhite ? '#fff' : theme.palette.secondary.main}; - margin: 0 auto 0 15px; +const PoiType = styled.div<{ $isSkeleton: Boolean }>` + color: ${({ theme }) => theme.palette.secondary.main}; + font-size: 13px; position: relative; - ${({ $forceWhite }) => $forceWhite && 'flex: 1;'} - svg { - vertical-align: bottom; + img { + position: relative; + top: -1px; + left: 1px; } span { @@ -22,19 +22,6 @@ const PoiType = styled.div<{ $isSkeleton: Boolean; $forceWhite?: Boolean }>` } `; -export const PoiDescriptionDark = () => { - const { feature } = useFeatureContext(); - const { properties } = feature; - const poiType = getHumanPoiType(feature); - - return ( - - - {poiType} - - ); -}; - export const PoiDescription = () => { const { currentTheme } = useUserThemeContext(); const { feature } = useFeatureContext(); diff --git a/src/components/FeaturePanel/ParentLink.tsx b/src/components/FeaturePanel/ParentLink.tsx index cb5303233..d955c0c12 100644 --- a/src/components/FeaturePanel/ParentLink.tsx +++ b/src/components/FeaturePanel/ParentLink.tsx @@ -19,18 +19,18 @@ const Row = styled.div` const IconWrapper = styled.div` position: relative; - top: 1px; + top: 2px; `; -const ClimbingParentItem = styled.div` - margin: 12px 8px -4px 8px; +const ParentItem = styled.div` + margin: 12px 0 4px 0; a { color: ${({ theme }) => theme.palette.secondary.main}; font-size: 13px; display: block; + text-decoration: none; &:hover { - text-decoration: none; color: ${({ theme }) => theme.palette.text.secondary}; } &:hover svg { @@ -40,16 +40,6 @@ const ClimbingParentItem = styled.div` } `; -const ParentItem = styled.div` - margin: 12px 0 4px 0; - - a { - color: ${({ theme }) => theme.palette.secondary.main}; - font-size: 13px; - display: block; - } -`; - export const Arrow = ({ children }) => ( @@ -86,14 +76,15 @@ export const ParentLinkContent = () => { ); }; -export const ParentLink = () => ( - - - -); +export const ParentLink = () => { + const { feature } = useFeatureContext(); + const hasParentLink = feature.parentFeatures?.length; -export const ClimbingParentLink = () => ( - - - -); + if (!hasParentLink) return null; + + return ( + + + + ); +}; diff --git a/src/components/Map/TopMenu/HamburgerMenu.tsx b/src/components/Map/TopMenu/HamburgerMenu.tsx index 1b25a9545..5cc91a9b7 100644 --- a/src/components/Map/TopMenu/HamburgerMenu.tsx +++ b/src/components/Map/TopMenu/HamburgerMenu.tsx @@ -176,7 +176,6 @@ export const HamburgerMenu = () => { void] => { diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 6b065eead..c49e461d5 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -1,5 +1,9 @@ import { createGlobalStyle } from 'styled-components'; -import { isDesktop } from '../components/helpers'; +import { + DRAWER_PREVIEW_HEIGHT, + DRAWER_TOP_OFFSET, + isDesktop, +} from '../components/helpers'; export const GlobalStyle = createGlobalStyle` html, body, #__next { @@ -105,7 +109,10 @@ export const GlobalStyle = createGlobalStyle` } .featurePanelInDrawer.MuiDrawer-root > .MuiPaper-root { - height: calc(100% - 86px - 8px); + height: calc(100% - ${DRAWER_PREVIEW_HEIGHT}px - ${DRAWER_TOP_OFFSET}px); overflow: visible; } + .PrivateSwipeArea-root { + cursor: pointer; + } `; From e3d09f81e2c2ff2988b9a02fae2bc901e7bd4726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Wed, 3 Jul 2024 22:37:29 +0200 Subject: [PATCH 07/15] Map buttons: Update styles --- .../LayerSwitcher/LayerSwitcherButton.tsx | 41 +++++++++++++------ src/components/LayerSwitcher/LayersIcon.tsx | 2 +- src/components/Map/Map.tsx | 2 +- src/components/Map/MapFooter/MapFooter.tsx | 4 +- src/components/helpers.tsx | 4 ++ src/helpers/GlobalStyle.tsx | 28 ++++++++++--- 6 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/components/LayerSwitcher/LayerSwitcherButton.tsx b/src/components/LayerSwitcher/LayerSwitcherButton.tsx index 6839349c7..71cb46ba7 100644 --- a/src/components/LayerSwitcher/LayerSwitcherButton.tsx +++ b/src/components/LayerSwitcher/LayerSwitcherButton.tsx @@ -1,17 +1,31 @@ import React from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import LayersIcon from './LayersIcon'; import { t } from '../../services/intl'; +import { useMobileMode } from '../helpers'; +import { convertHexToRgba } from '../utils/colorUtils'; -const StyledLayerSwitcher = styled.button` +const StyledLayerSwitcher = styled.button<{ isMobileMode: boolean }>` margin: 0; padding: 0; - width: 52px; - height: 69px; - border-radius: 5px; + ${({ isMobileMode }) => + isMobileMode + ? css` + width: 44px; + height: 44px; + border-radius: 50%; + ` + : css` + width: 52px; + height: 69px; + border-radius: 5px; + `} + border: 0; box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); - background-color: ${({ theme }) => theme.palette.background.paper}; + background-color: ${({ theme }) => + convertHexToRgba(theme.palette.background.paper, 0.5)}; + backdrop-filter: blur(15px); font-size: 12px; color: ${({ theme }) => theme.palette.text.primary}; outline: 0; @@ -27,9 +41,12 @@ const StyledLayerSwitcher = styled.button` } `; -export const LayerSwitcherButton = ({ onClick }: { onClick?: any }) => ( - - - {t('layerswitcher.button')} - -); +export const LayerSwitcherButton = ({ onClick }: { onClick?: any }) => { + const isMobileMode = useMobileMode(); + return ( + + + {!isMobileMode && t('layerswitcher.button')} + + ); +}; diff --git a/src/components/LayerSwitcher/LayersIcon.tsx b/src/components/LayerSwitcher/LayersIcon.tsx index bed2b2576..92a2d9214 100644 --- a/src/components/LayerSwitcher/LayersIcon.tsx +++ b/src/components/LayerSwitcher/LayersIcon.tsx @@ -2,7 +2,7 @@ import React from 'react'; const SvgComponent = (props) => ( // eslint-disable-next-line react/jsx-props-no-spreading - + diff --git a/src/components/Map/Map.tsx b/src/components/Map/Map.tsx index b4cbef710..a5345146d 100644 --- a/src/components/Map/Map.tsx +++ b/src/components/Map/Map.tsx @@ -36,7 +36,7 @@ const TopRight = styled.div` z-index: 1000; padding: 10px; right: 0; - top: 72px; + top: 62px; @media ${isDesktop} { top: 0; diff --git a/src/components/Map/MapFooter/MapFooter.tsx b/src/components/Map/MapFooter/MapFooter.tsx index d595511a1..c94e7ffcc 100644 --- a/src/components/Map/MapFooter/MapFooter.tsx +++ b/src/components/Map/MapFooter/MapFooter.tsx @@ -27,8 +27,8 @@ const FooterContainer = styled.div<{ $hasShadow: boolean }>` color: ${({ theme }) => theme.palette.text.primary}; background-color: ${({ theme }) => convertHexToRgba(theme.palette.background.paper, 0.5)}; - -webkit-backdrop-filter: blur(10px); - backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(15px); + backdrop-filter: blur(15px); ${({ $hasShadow }) => $hasShadow ? 'box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);' : ''} `; diff --git a/src/components/helpers.tsx b/src/components/helpers.tsx index b84d1e70b..4ea04f11c 100644 --- a/src/components/helpers.tsx +++ b/src/components/helpers.tsx @@ -97,6 +97,10 @@ export const useMobileMode = () => useMediaQuery(isMobileMode); // (>= mobile size) SearchBox stops growing export const isDesktop = '(min-width: 500px)'; +export const isMobileResolution = '(max-width: 500px)'; +export const isTabletResolution = '(min-width: 501px) and (max-width: 700px)'; +export const isDesktopResolution = '(min-width: 701px)'; + // is mobile device - specific behaviour like longpress or geouri export const isMobileDevice = () => isBrowser() && /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); // TODO this can be isomorphic ? otherwise we have hydration error diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index c49e461d5..9e6cd1c39 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -2,8 +2,11 @@ import { createGlobalStyle } from 'styled-components'; import { DRAWER_PREVIEW_HEIGHT, DRAWER_TOP_OFFSET, - isDesktop, + isDesktopResolution, + isMobileMode, + isTabletResolution, } from '../components/helpers'; +import { convertHexToRgba } from '../components/utils/colorUtils'; export const GlobalStyle = createGlobalStyle` html, body, #__next { @@ -58,23 +61,38 @@ export const GlobalStyle = createGlobalStyle` } .maplibregl-ctrl-group { - background: ${({ theme }) => theme.palette.background.paper} !important; + background-color: ${({ theme }) => + convertHexToRgba(theme.palette.background.paper, 0.5)} !important; + backdrop-filter: blur(10px); .maplibregl-ctrl-icon { filter: ${({ theme }) => theme.palette.invertFilter}; } + @media ${isMobileMode} { + border-radius: 50%; + + button { + width: 44px; + height: 44px; + } + } button + button { border-top: 1px solid ${({ theme }) => theme.palette.divider}; } } .maplibregl-ctrl-top-right { - top: ${83 + 72}px !important; + top: 114px !important; - @media ${isDesktop} { + @media ${isTabletResolution} { + top: 54px !important; + } + + @media ${isDesktopResolution} { top: 83px !important; } + } .maplibregl-canvas:not(:focus) { @@ -104,7 +122,7 @@ export const GlobalStyle = createGlobalStyle` } /* Hide compass by default */ - .hidden-compass .maplibregl-ctrl-compass { + .hidden-compass .maplibregl-ctrl:has(> .maplibregl-ctrl-compass) { display: none; } From 7d6568ae5c42742717755fa6576b6ae1c29dbb64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Wed, 3 Jul 2024 23:01:59 +0200 Subject: [PATCH 08/15] Slider: Update style for one image only --- .../FeaturePanel/ImagePane/ImageSlider.tsx | 31 +++++++----- .../FeaturePanel/ImagePane/Slider.tsx | 48 +++---------------- .../FeaturePanel/MemberFeatures.tsx | 2 +- .../LayerSwitcher/LayerSwitcherButton.tsx | 5 +- src/helpers/GlobalStyle.tsx | 2 +- src/services/images/getImageTags.ts | 4 +- 6 files changed, 32 insertions(+), 60 deletions(-) diff --git a/src/components/FeaturePanel/ImagePane/ImageSlider.tsx b/src/components/FeaturePanel/ImagePane/ImageSlider.tsx index 1c52013df..aee7bc7b4 100644 --- a/src/components/FeaturePanel/ImagePane/ImageSlider.tsx +++ b/src/components/FeaturePanel/ImagePane/ImageSlider.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import Router from 'next/router'; import { useFeatureContext } from '../../utils/FeatureContext'; import { Path, PathSvg } from './Path'; @@ -13,7 +13,6 @@ const HEIGHT = 245; const initialSize: Size = { width: 100, height: HEIGHT }; // until image size is known, the paths are rendered using this (eg. ssr) const Img = styled.img` - border-radius: 12px; &.hasPaths { opacity: 0.9; // let the paths be more prominent } @@ -22,26 +21,27 @@ const ImageWrapper = styled.div` position: relative; display: flex; height: 100%; - border-radius: 12px; - /* overflow: hidden; */ - ${({ onClick, theme }) => + ${({ onClick }) => onClick && - ` + css` cursor: pointer; - &:hover { - box-shadow: 0 0 10px ${theme.palette.secondary.main}; - }`} + `} svg { position: absolute; height: 100%; width: 100%; - border-radius: 8px; } `; -const Image = ({ imageTag }: { imageTag: ImageTag }) => { +const Image = ({ + imageTag, + onlyOneImage, +}: { + imageTag: ImageTag; + onlyOneImage: boolean; +}) => { const [size, setSize] = React.useState(initialSize); const { feature } = useFeatureContext(); const isCrag = feature.tags.climbing === 'crag'; @@ -67,7 +67,8 @@ const Image = ({ imageTag }: { imageTag: ImageTag }) => { {imageTag.v} { return ( {feature.imageTags.map((imageTag) => ( - + ))} {/* Fody */} {/* Mapillary */} diff --git a/src/components/FeaturePanel/ImagePane/Slider.tsx b/src/components/FeaturePanel/ImagePane/Slider.tsx index 8334ea78a..52c91cd9e 100644 --- a/src/components/FeaturePanel/ImagePane/Slider.tsx +++ b/src/components/FeaturePanel/ImagePane/Slider.tsx @@ -1,10 +1,8 @@ import React from 'react'; import styled from 'styled-components'; -import { useTheme } from '@mui/material'; -import { useScrollShadow } from '../Climbing/utils/useScrollShadow'; // from https://css-tricks.com/css-only-carousel/ -const Wrapper = styled.div` +const Wrapper = styled.div<{ onlyOneImage: boolean }>` width: 100%; text-align: center; /* overflow: hidden; */ @@ -19,51 +17,19 @@ const Wrapper = styled.div` scroll-behavior: smooth; -webkit-overflow-scrolling: touch; - padding-left: 16px; - padding-right: 16px; - - padding-top: 16px; - padding-bottom: 16px; + padding: ${({ onlyOneImage }) => (onlyOneImage ? '12px 0' : '12px 16px')}; } .slides > div { display: flex; justify-content: center; align-items: center; - position: relative; } `; -export const Slider = ({ children }) => { - const theme = useTheme(); - - const { - scrollElementRef, - onScroll, - ShadowContainer, - ShadowLeft, - ShadowRight, - } = useScrollShadow(); - - return ( - - - - -
    - {children} -
    - -
    -
    - ); -}; +export const Slider = ({ children }) => ( + +
    {children}
    +
    +); diff --git a/src/components/FeaturePanel/MemberFeatures.tsx b/src/components/FeaturePanel/MemberFeatures.tsx index 157b1165e..32c186eeb 100644 --- a/src/components/FeaturePanel/MemberFeatures.tsx +++ b/src/components/FeaturePanel/MemberFeatures.tsx @@ -172,7 +172,7 @@ const CragItem = ({ feature }: { feature: Feature }) => { {cragPhotoKeys.map((cragPhotoTag) => { const photoPath = feature.tags[cragPhotoTag]; - const url = getCommonsImageUrl(photoPath, 400); + const url = getCommonsImageUrl(photoPath, 410); return ; })} diff --git a/src/components/LayerSwitcher/LayerSwitcherButton.tsx b/src/components/LayerSwitcher/LayerSwitcherButton.tsx index 71cb46ba7..6e8f7d96f 100644 --- a/src/components/LayerSwitcher/LayerSwitcherButton.tsx +++ b/src/components/LayerSwitcher/LayerSwitcherButton.tsx @@ -24,7 +24,7 @@ const StyledLayerSwitcher = styled.button<{ isMobileMode: boolean }>` border: 0; box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); background-color: ${({ theme }) => - convertHexToRgba(theme.palette.background.paper, 0.5)}; + convertHexToRgba(theme.palette.background.paper, 0.7)}; backdrop-filter: blur(15px); font-size: 12px; color: ${({ theme }) => theme.palette.text.primary}; @@ -33,7 +33,8 @@ const StyledLayerSwitcher = styled.button<{ isMobileMode: boolean }>` &:hover, &:focus { - background-color: ${({ theme }) => theme.palette.background.hover}; + background-color: ${({ theme }) => + convertHexToRgba(theme.palette.background.paper, 0.75)}; } svg { diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 9e6cd1c39..44d63bd25 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -62,7 +62,7 @@ export const GlobalStyle = createGlobalStyle` .maplibregl-ctrl-group { background-color: ${({ theme }) => - convertHexToRgba(theme.palette.background.paper, 0.5)} !important; + convertHexToRgba(theme.palette.background.paper, 0.7)} !important; backdrop-filter: blur(10px); .maplibregl-ctrl-icon { diff --git a/src/services/images/getImageTags.ts b/src/services/images/getImageTags.ts index 5ab05b577..500b737c1 100644 --- a/src/services/images/getImageTags.ts +++ b/src/services/images/getImageTags.ts @@ -28,11 +28,11 @@ const parsePathTag = (pathString?: string): PathType | undefined => { const getImageUrl = (type: ImageTag['type'], v: string): string | null => { if (type === 'image') { - return v.match(/^File:/) ? getCommonsImageUrl(v, 400) : v; + return v.match(/^File:/) ? getCommonsImageUrl(v, 410) : v; } if (type === 'wikimedia_commons') { - return getCommonsImageUrl(v, 400); + return getCommonsImageUrl(v, 410); } return null; // API call needed From 8c37c33e11c61c885774959b75d7b69a03f89b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Fri, 5 Jul 2024 21:57:43 +0200 Subject: [PATCH 09/15] FeaturePanel: Show one image without margin --- .../FeaturePanel/ImagePane/ImageSlider.tsx | 21 +++++++++---------- .../FeaturePanel/ImagePane/Slider.tsx | 11 +++++----- .../HomepagePanel/HomepagePanel.tsx | 3 ++- src/components/SearchBox/SearchBox.tsx | 2 +- src/components/SearchBox/consts.ts | 2 +- src/components/utils/PanelHelpers.tsx | 5 +++-- 6 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/components/FeaturePanel/ImagePane/ImageSlider.tsx b/src/components/FeaturePanel/ImagePane/ImageSlider.tsx index aee7bc7b4..a3ea6da66 100644 --- a/src/components/FeaturePanel/ImagePane/ImageSlider.tsx +++ b/src/components/FeaturePanel/ImagePane/ImageSlider.tsx @@ -12,7 +12,9 @@ import { Slider } from './Slider'; const HEIGHT = 245; const initialSize: Size = { width: 100, height: HEIGHT }; // until image size is known, the paths are rendered using this (eg. ssr) -const Img = styled.img` +const Img = styled.img<{ $onlyOneImage: boolean }>` + max-height: 300px; + &.hasPaths { opacity: 0.9; // let the paths be more prominent } @@ -21,6 +23,7 @@ const ImageWrapper = styled.div` position: relative; display: flex; height: 100%; + box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px; ${({ onClick }) => onClick && @@ -69,6 +72,7 @@ const Image = ({ src={imageTag.imageUrl} width={onlyOneImage ? '100%' : undefined} height={onlyOneImage ? undefined : HEIGHT} + $onlyOneImage={onlyOneImage} alt={imageTag.v} onLoad={onPhotoLoad} className={hasPaths ? 'hasPaths' : ''} @@ -88,22 +92,17 @@ const Image = ({ export const ImageSlider = () => { const { feature } = useFeatureContext(); - // temporary - until ImageSlider is finished - if ( - !feature.imageTags?.some( - ({ path, memberPaths }) => path?.length || memberPaths?.length, - ) - ) { - return null; - } + const onlyOneImage = + (feature.imageTags?.filter((imageTag) => imageTag.imageUrl) ?? []) + .length === 1; return ( - + {feature.imageTags.map((imageTag) => ( ))} {/* Fody */} diff --git a/src/components/FeaturePanel/ImagePane/Slider.tsx b/src/components/FeaturePanel/ImagePane/Slider.tsx index 52c91cd9e..7031d8f2c 100644 --- a/src/components/FeaturePanel/ImagePane/Slider.tsx +++ b/src/components/FeaturePanel/ImagePane/Slider.tsx @@ -2,7 +2,7 @@ import React from 'react'; import styled from 'styled-components'; // from https://css-tricks.com/css-only-carousel/ -const Wrapper = styled.div<{ onlyOneImage: boolean }>` +const Wrapper = styled.div<{ $onlyOneImage: boolean }>` width: 100%; text-align: center; /* overflow: hidden; */ @@ -11,13 +11,14 @@ const Wrapper = styled.div<{ onlyOneImage: boolean }>` .slides { display: flex; - gap: 12px; + gap: 8px; + ${({ $onlyOneImage }) => $onlyOneImage && `justify-content: center;`} align-items: center; overflow-x: auto; scroll-behavior: smooth; -webkit-overflow-scrolling: touch; - padding: ${({ onlyOneImage }) => (onlyOneImage ? '12px 0' : '12px 16px')}; + padding: ${({ $onlyOneImage }) => ($onlyOneImage ? '12px 0' : '12px 16px')}; } .slides > div { @@ -28,8 +29,8 @@ const Wrapper = styled.div<{ onlyOneImage: boolean }>` } `; -export const Slider = ({ children }) => ( - +export const Slider = ({ children, onlyOneImage }) => ( +
    {children}
    ); diff --git a/src/components/HomepagePanel/HomepagePanel.tsx b/src/components/HomepagePanel/HomepagePanel.tsx index 190217b99..3415109ca 100644 --- a/src/components/HomepagePanel/HomepagePanel.tsx +++ b/src/components/HomepagePanel/HomepagePanel.tsx @@ -22,9 +22,10 @@ import { PROJECT_NAME, } from '../../services/project'; import { useMobileMode } from '../helpers'; +import { SEARCH_BOX_HEIGHT } from '../SearchBox/consts'; export const Content = styled.div` - height: calc(100% - 72px); // 100% - TopPanel - FeatureImage + height: calc(100% - ${SEARCH_BOX_HEIGHT}px); padding: 20px 2em 0 2em; a.maptiler { diff --git a/src/components/SearchBox/SearchBox.tsx b/src/components/SearchBox/SearchBox.tsx index 798d9afd3..47fd748c9 100644 --- a/src/components/SearchBox/SearchBox.tsx +++ b/src/components/SearchBox/SearchBox.tsx @@ -24,7 +24,7 @@ const TopPanel = styled.div<{ $isMobileMode: boolean }>` background-color: ${({ theme }) => theme.palette.background.searchBox}; `} - padding: 10px; + padding: 8px; box-sizing: border-box; z-index: 1; diff --git a/src/components/SearchBox/consts.ts b/src/components/SearchBox/consts.ts index 9c8bb3d3b..e3c2b32c4 100644 --- a/src/components/SearchBox/consts.ts +++ b/src/components/SearchBox/consts.ts @@ -1 +1 @@ -export const SEARCH_BOX_HEIGHT = 72; +export const SEARCH_BOX_HEIGHT = 68; diff --git a/src/components/utils/PanelHelpers.tsx b/src/components/utils/PanelHelpers.tsx index 8d5f4897d..98b892687 100644 --- a/src/components/utils/PanelHelpers.tsx +++ b/src/components/utils/PanelHelpers.tsx @@ -4,6 +4,7 @@ import { Scrollbars } from 'react-custom-scrollbars'; import { useTheme } from '@mui/material'; import { isDesktop } from '../helpers'; import { useScrollShadow } from '../FeaturePanel/Climbing/utils/useScrollShadow'; +import { SEARCH_BOX_HEIGHT } from '../SearchBox/consts'; // custom scrollbar // better: https://github.com/rommguy/react-custom-scroll @@ -11,7 +12,7 @@ import { useScrollShadow } from '../FeaturePanel/Climbing/utils/useScrollShadow' export const PanelWrapper = styled.div` position: absolute; left: 0; - top: 72px; // TopPanel + top: ${SEARCH_BOX_HEIGHT}px; bottom: 0; background: ${({ theme }) => theme.palette.background.paper}; color: ${({ theme }) => theme.palette.text.primary}; @@ -79,5 +80,5 @@ export const PanelFooter = styled.div` `; export const PanelSidePadding = styled.div` - padding: 0 15px; + padding: 0 12px; `; From 796aa68116bb42a5d38a9c430acbecc5c493f61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 6 Jul 2024 14:16:38 +0200 Subject: [PATCH 10/15] opacity --- .../FeaturePanel/FeaturePanelInDrawer.tsx | 21 +++++++++++-------- src/components/helpers.tsx | 4 ++-- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx index 850f31289..e6ad68601 100644 --- a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx +++ b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from 'react'; import { SwipeableDrawer } from '@mui/material'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; import { grey } from '@mui/material/colors'; import { FeaturePanelInner } from './FeaturePanelInner'; import { @@ -35,18 +35,15 @@ const Container = styled.div` const PULLER_WIDTH = 30; const PULLER_HIP_SLOP = 10; -const Puller = styled.div<{ isHovered: boolean }>` +const Puller = styled.div` width: ${PULLER_WIDTH}px; height: 6px; background-color: ${({ theme }) => theme.palette.mode === 'light' ? grey[300] : grey[900]}; border-radius: 3px; - - ${({ isHovered, theme }) => - isHovered && `background-color: ${theme.palette.primary.main};`}; `; -const PullerContainer = styled.div` +const PullerContainer = styled.div<{ $isHovered: boolean }>` position: absolute; z-index: 1; top: 0px; @@ -54,8 +51,14 @@ const PullerContainer = styled.div` padding: ${PULLER_HIP_SLOP}px; cursor: pointer; + ${({ $isHovered }) => + $isHovered && + css` + opacity: 0.5; + `} + &:hover ${Puller} { - background-color: ${({ theme }) => theme.palette.primary.main}; + opacity: 0.5; } `; @@ -124,8 +127,8 @@ export const FeaturePanelInDrawer = () => { className="featurePanelInDrawer" > - - + + diff --git a/src/components/helpers.tsx b/src/components/helpers.tsx index 4ea04f11c..836859860 100644 --- a/src/components/helpers.tsx +++ b/src/components/helpers.tsx @@ -97,8 +97,8 @@ export const useMobileMode = () => useMediaQuery(isMobileMode); // (>= mobile size) SearchBox stops growing export const isDesktop = '(min-width: 500px)'; -export const isMobileResolution = '(max-width: 500px)'; -export const isTabletResolution = '(min-width: 501px) and (max-width: 700px)'; +// TODO refactor breakpoints later +export const isTabletResolution = '(min-width: 501px)'; export const isDesktopResolution = '(min-width: 701px)'; // is mobile device - specific behaviour like longpress or geouri From 294932e67be4deeec38e2362f4eb91a6bb94d9a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 6 Jul 2024 16:40:33 +0200 Subject: [PATCH 11/15] refactor drawer --- .../FeaturePanel/FeaturePanelInDrawer.tsx | 141 +++++------------- .../FeaturePanel/ImagePane/ImageSlider.tsx | 2 +- .../FeaturePanel/helpers/Puller.tsx | 68 +++++++++ src/components/Map/MapFooter/MapFooter.tsx | 12 +- src/components/helpers.tsx | 4 +- src/helpers/GlobalStyle.tsx | 9 -- 6 files changed, 113 insertions(+), 123 deletions(-) create mode 100644 src/components/FeaturePanel/helpers/Puller.tsx diff --git a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx index e6ad68601..25ba29b1f 100644 --- a/src/components/FeaturePanel/FeaturePanelInDrawer.tsx +++ b/src/components/FeaturePanel/FeaturePanelInDrawer.tsx @@ -1,19 +1,16 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { SwipeableDrawer } from '@mui/material'; -import styled, { css } from 'styled-components'; -import { grey } from '@mui/material/colors'; +import styled, { createGlobalStyle } from 'styled-components'; import { FeaturePanelInner } from './FeaturePanelInner'; -import { - DRAWER_PREVIEW_HEIGHT, - DRAWER_TOP_OFFSET, - isMobileDevice, - useMobileMode, -} from '../helpers'; +import { Puller } from './helpers/Puller'; -const StyledSwipeableDrawer = styled(SwipeableDrawer)` - .MuiDrawer-root > .MuiPaper-root { - pointer-events: all !important; +const DRAWER_PREVIEW_HEIGHT = 86; +const DRAWER_TOP_OFFSET = 8; +const DRAWER_CLASSNAME = 'featurePanelInDrawer'; + +const GlobalStyleForDrawer = createGlobalStyle` + .${DRAWER_CLASSNAME}.MuiDrawer-root > .MuiPaper-root { height: calc(100% - ${DRAWER_PREVIEW_HEIGHT}px - ${DRAWER_TOP_OFFSET}px); overflow: visible; } @@ -32,108 +29,40 @@ const Container = styled.div` height: calc(100% + ${DRAWER_PREVIEW_HEIGHT}px + ${DRAWER_TOP_OFFSET}px); `; -const PULLER_WIDTH = 30; -const PULLER_HIP_SLOP = 10; - -const Puller = styled.div` - width: ${PULLER_WIDTH}px; - height: 6px; - background-color: ${({ theme }) => - theme.palette.mode === 'light' ? grey[300] : grey[900]}; - border-radius: 3px; +const ListContainer = styled.div` + max-height: calc(100% - ${DRAWER_TOP_OFFSET}px); + height: 100%; + overflow: auto; `; -const PullerContainer = styled.div<{ $isHovered: boolean }>` - position: absolute; - z-index: 1; - top: 0px; - left: calc(50% - ${PULLER_WIDTH / 2}px - ${PULLER_HIP_SLOP}px); - padding: ${PULLER_HIP_SLOP}px; - cursor: pointer; - - ${({ $isHovered }) => - $isHovered && - css` - opacity: 0.5; - `} - - &:hover ${Puller} { - opacity: 0.5; - } -`; - -const ListContainer = styled('div')(() => ({ - maxHeight: `calc(100% - ${DRAWER_TOP_OFFSET}px)`, - height: '100%', - overflow: 'auto', -})); - export const FeaturePanelInDrawer = () => { const [open, setOpen] = useState(false); - const [isHovered, setIsHovered] = useState(false); - const hasMobileResolution = useMobileMode(); - const isDesktop = !isMobileDevice(); const handleOnOpen = () => setOpen(true); const handleOnClose = () => setOpen(false); - useEffect(() => { - if (isDesktop && hasMobileResolution) { - const swipeAreaElement = document.querySelector('.PrivateSwipeArea-root'); - - const handleSwipeAreaClick = () => { - setOpen(true); - }; - const handleOnMouseOver = () => { - setIsHovered(true); - }; - const handleOnMouseOut = () => { - setIsHovered(false); - }; - - if (swipeAreaElement) { - swipeAreaElement.addEventListener('click', handleSwipeAreaClick); - swipeAreaElement.addEventListener('mouseover', handleOnMouseOver); - swipeAreaElement.addEventListener('mouseout', handleOnMouseOut); - } - return () => { - if (swipeAreaElement) { - swipeAreaElement.removeEventListener('click', handleSwipeAreaClick); - swipeAreaElement.removeEventListener('mouseover', handleOnMouseOver); - swipeAreaElement.removeEventListener('mouseout', handleOnMouseOut); - } - }; - } - return () => null; - }, [hasMobileResolution, isDesktop, setIsHovered]); - return ( - - - - - - - - - - + <> + + + + + + + + + + ); }; diff --git a/src/components/FeaturePanel/ImagePane/ImageSlider.tsx b/src/components/FeaturePanel/ImagePane/ImageSlider.tsx index a3ea6da66..dac47de6e 100644 --- a/src/components/FeaturePanel/ImagePane/ImageSlider.tsx +++ b/src/components/FeaturePanel/ImagePane/ImageSlider.tsx @@ -98,7 +98,7 @@ export const ImageSlider = () => { return ( - {feature.imageTags.map((imageTag) => ( + {feature.imageTags?.map((imageTag) => ( + theme.palette.mode === 'light' ? grey[300] : grey[900]}; + border-radius: 3px; + -webkit-tap-highlight-color: transparent; +`; + +const PullerContainer = styled.div<{ + $isDesktop: boolean; + $isClosed: boolean; +}>` + position: absolute; + top: 0; + left: calc(50% - ${HANDLE_WIDTH / 2}px - ${HANDLE_HIP_SLOP}px); + z-index: 1; + padding: ${HANDLE_HIP_SLOP}px; + + ${({ $isDesktop, $isClosed }) => + $isDesktop && + css` + cursor: pointer; + + &:hover ${Handle} { + opacity: 0.5; + } + + ${$isClosed && + css` + left: 0; + width: 100%; + height: 100%; + pointer-events: all; + `} + `} +`; + +type Props = { + setOpen: React.Dispatch>; + open: boolean; +}; + +export const Puller = ({ setOpen, open }: Props) => { + const isDesktop = !isMobileDevice(); + const toggleDrawer = () => { + setOpen((value) => !value); + }; + + return ( + + + + ); +}; diff --git a/src/components/Map/MapFooter/MapFooter.tsx b/src/components/Map/MapFooter/MapFooter.tsx index c94e7ffcc..e8db5c5f6 100644 --- a/src/components/Map/MapFooter/MapFooter.tsx +++ b/src/components/Map/MapFooter/MapFooter.tsx @@ -7,7 +7,8 @@ import { ClimbingLegend } from './ClimbingLegend'; import { convertHexToRgba } from '../../utils/colorUtils'; import { AttributionLinks } from './AttributionLinks'; import { useMapStateContext } from '../../utils/MapStateContext'; -import { useIsClient } from '../../helpers'; +import { useIsClient, useMobileMode } from '../../helpers'; +import { useFeatureContext } from '../../utils/FeatureContext'; const IconContainer = styled.div` width: 20px; @@ -70,7 +71,10 @@ const LegendExpandButton = ({ isVisible, setLegendShown }) => ( export const MapFooter = () => { const { activeLayers } = useMapStateContext(); + const isMobileMode = useMobileMode(); + const { featureShown } = useFeatureContext(); const hasClimbingLayer = activeLayers.includes('climbing'); + const hasLegend = isMobileMode && featureShown ? false : hasClimbingLayer; const [legendShown, setLegendShown] = usePersistedState( 'isLegendVisible', true, @@ -83,8 +87,8 @@ export const MapFooter = () => { } return ( - - {hasClimbingLayer && ( + + {hasLegend && ( { )} - {hasClimbingLayer && ( + {hasLegend && ( void] => { @@ -121,6 +118,7 @@ export const DotLoader = () => ( ); +// TODO import { NoSsr } from '@mui/base'; export const ClientOnly = ({ children }) => { const [mounted, setMounted] = useState(false); useEffect(() => setMounted(true), []); diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 44d63bd25..6c08dbbdd 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -1,7 +1,5 @@ import { createGlobalStyle } from 'styled-components'; import { - DRAWER_PREVIEW_HEIGHT, - DRAWER_TOP_OFFSET, isDesktopResolution, isMobileMode, isTabletResolution, @@ -126,11 +124,4 @@ export const GlobalStyle = createGlobalStyle` display: none; } - .featurePanelInDrawer.MuiDrawer-root > .MuiPaper-root { - height: calc(100% - ${DRAWER_PREVIEW_HEIGHT}px - ${DRAWER_TOP_OFFSET}px); - overflow: visible; - } - .PrivateSwipeArea-root { - cursor: pointer; - } `; From 163f467db1010aa00907fea32ecc7c25ecbf49c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 6 Jul 2024 16:40:33 +0200 Subject: [PATCH 12/15] refactor drawer --- src/components/LayerSwitcher/LayerSwitcher.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/LayerSwitcher/LayerSwitcher.tsx b/src/components/LayerSwitcher/LayerSwitcher.tsx index 27d441c6f..6fb5c5863 100644 --- a/src/components/LayerSwitcher/LayerSwitcher.tsx +++ b/src/components/LayerSwitcher/LayerSwitcher.tsx @@ -20,7 +20,6 @@ const LayerSwitcher = () => { variant={panelFixed ? 'persistent' : 'temporary'} disableBackdropTransition disableSwipeToOpen - swipeAreaWidth={100} >
    From a765c001e2bca8785da62dab9c00b2005c878c33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 6 Jul 2024 16:53:14 +0200 Subject: [PATCH 13/15] blur --- src/components/FeaturePanel/Climbing/ClimbingView.tsx | 2 +- src/components/LayerSwitcher/LayerSwitcherButton.tsx | 1 + src/components/Map/MapFooter/MapFooter.tsx | 2 +- src/helpers/GlobalStyle.tsx | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/FeaturePanel/Climbing/ClimbingView.tsx b/src/components/FeaturePanel/Climbing/ClimbingView.tsx index 7138a0ca5..43d1bc474 100644 --- a/src/components/FeaturePanel/Climbing/ClimbingView.tsx +++ b/src/components/FeaturePanel/Climbing/ClimbingView.tsx @@ -116,8 +116,8 @@ const ArrowExpanderButton = styled.div<{ $arrowOnTop?: boolean }>` `; const BlurContainer = styled.div<{ $isVisible: boolean }>` - -webkit-backdrop-filter: blur(15px); backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); background-color: rgba(0, 0, 0, 0.6); visibility: ${({ $isVisible }) => ($isVisible ? 'visible' : 'hidden')}; height: 100%; diff --git a/src/components/LayerSwitcher/LayerSwitcherButton.tsx b/src/components/LayerSwitcher/LayerSwitcherButton.tsx index 6e8f7d96f..131369962 100644 --- a/src/components/LayerSwitcher/LayerSwitcherButton.tsx +++ b/src/components/LayerSwitcher/LayerSwitcherButton.tsx @@ -26,6 +26,7 @@ const StyledLayerSwitcher = styled.button<{ isMobileMode: boolean }>` background-color: ${({ theme }) => convertHexToRgba(theme.palette.background.paper, 0.7)}; backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); font-size: 12px; color: ${({ theme }) => theme.palette.text.primary}; outline: 0; diff --git a/src/components/Map/MapFooter/MapFooter.tsx b/src/components/Map/MapFooter/MapFooter.tsx index e8db5c5f6..53a430428 100644 --- a/src/components/Map/MapFooter/MapFooter.tsx +++ b/src/components/Map/MapFooter/MapFooter.tsx @@ -28,8 +28,8 @@ const FooterContainer = styled.div<{ $hasShadow: boolean }>` color: ${({ theme }) => theme.palette.text.primary}; background-color: ${({ theme }) => convertHexToRgba(theme.palette.background.paper, 0.5)}; - -webkit-backdrop-filter: blur(15px); backdrop-filter: blur(15px); + -webkit-backdrop-filter: blur(15px); ${({ $hasShadow }) => $hasShadow ? 'box-shadow: 0 0 30px rgba(0, 0, 0, 0.3);' : ''} `; diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 6c08dbbdd..85d51b31f 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -62,6 +62,7 @@ export const GlobalStyle = createGlobalStyle` background-color: ${({ theme }) => convertHexToRgba(theme.palette.background.paper, 0.7)} !important; backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); .maplibregl-ctrl-icon { filter: ${({ theme }) => theme.palette.invertFilter}; From 9cf452f0575d4bf32b4cb8492dc43b68bf7e7536 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 6 Jul 2024 17:13:53 +0200 Subject: [PATCH 14/15] cr --- src/components/LayerSwitcher/LayerSwitcherButton.tsx | 1 - src/components/Map/TopMenu/HamburgerIconButton.tsx | 5 +---- src/components/Map/TopMenu/LoginIconButton.tsx | 5 +---- src/helpers/GlobalStyle.tsx | 2 +- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/components/LayerSwitcher/LayerSwitcherButton.tsx b/src/components/LayerSwitcher/LayerSwitcherButton.tsx index 131369962..6e8f7d96f 100644 --- a/src/components/LayerSwitcher/LayerSwitcherButton.tsx +++ b/src/components/LayerSwitcher/LayerSwitcherButton.tsx @@ -26,7 +26,6 @@ const StyledLayerSwitcher = styled.button<{ isMobileMode: boolean }>` background-color: ${({ theme }) => convertHexToRgba(theme.palette.background.paper, 0.7)}; backdrop-filter: blur(15px); - -webkit-backdrop-filter: blur(15px); font-size: 12px; color: ${({ theme }) => theme.palette.text.primary}; outline: 0; diff --git a/src/components/Map/TopMenu/HamburgerIconButton.tsx b/src/components/Map/TopMenu/HamburgerIconButton.tsx index 4325c3c40..ac95306d9 100644 --- a/src/components/Map/TopMenu/HamburgerIconButton.tsx +++ b/src/components/Map/TopMenu/HamburgerIconButton.tsx @@ -11,10 +11,7 @@ const StyledIconButton = styled(IconButton)` svg { filter: drop-shadow(0 0 2px #ffffff); - } - @media ${isMobileMode} { - svg { - filter: none; + @media ${isMobileMode} { filter: invert(100%); } } diff --git a/src/components/Map/TopMenu/LoginIconButton.tsx b/src/components/Map/TopMenu/LoginIconButton.tsx index 4de702b83..28d194130 100644 --- a/src/components/Map/TopMenu/LoginIconButton.tsx +++ b/src/components/Map/TopMenu/LoginIconButton.tsx @@ -10,11 +10,8 @@ const StyledIconButton = styled(IconButton)` svg { filter: drop-shadow(0 0 2px #ffffff); - } - @media ${isMobileMode} { - svg { - filter: none; + @media ${isMobileMode} { filter: invert(100%); } } diff --git a/src/helpers/GlobalStyle.tsx b/src/helpers/GlobalStyle.tsx index 85d51b31f..629fd5be7 100644 --- a/src/helpers/GlobalStyle.tsx +++ b/src/helpers/GlobalStyle.tsx @@ -120,7 +120,7 @@ export const GlobalStyle = createGlobalStyle` background-color: rgba(0, 0, 0, 0.2) !important; } - /* Hide compass by default */ + /* Hide compass by default - selects .maplibregl-ctrl which holds [+,-,compass] */ .hidden-compass .maplibregl-ctrl:has(> .maplibregl-ctrl-compass) { display: none; } From 8f264336df5c1e181e3b5dd50fe22739093da85e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20V=C3=A1clav=C3=ADk?= Date: Sat, 6 Jul 2024 17:26:54 +0200 Subject: [PATCH 15/15] fix test --- src/services/__tests__/osmToFeature.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/__tests__/osmToFeature.test.ts b/src/services/__tests__/osmToFeature.test.ts index c1529f8d9..49078e20d 100644 --- a/src/services/__tests__/osmToFeature.test.ts +++ b/src/services/__tests__/osmToFeature.test.ts @@ -40,7 +40,7 @@ const geojson = { imageTags: [ { imageUrl: - 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Lomy_nad_Velkou_-_Borová_věž.jpg/400px-Lomy_nad_Velkou_-_Borová_věž.jpg', + 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/63/Lomy_nad_Velkou_-_Borová_věž.jpg/410px-Lomy_nad_Velkou_-_Borová_věž.jpg', k: 'wikimedia_commons', pathTag: '0.32,0.902|0.371,0.537B|0.406,0.173A', path: [ @@ -53,7 +53,7 @@ const geojson = { }, { imageUrl: - 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Lomy_nad_Velkou_-_Borová_věž3.jpg/400px-Lomy_nad_Velkou_-_Borová_věž3.jpg', + 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/4f/Lomy_nad_Velkou_-_Borová_věž3.jpg/410px-Lomy_nad_Velkou_-_Borová_věž3.jpg', k: 'wikimedia_commons:2', pathTag: '0.924,0.797|0.773,0.428B|0.562,0.056A', path: [