Skip to content

Commit

Permalink
climbing: introduce ClimbingPanel for climbing=crag (#189)
Browse files Browse the repository at this point in the history
  • Loading branch information
jvaclavik authored Feb 11, 2024
1 parent 59f0071 commit 8c76aca
Show file tree
Hide file tree
Showing 65 changed files with 5,554 additions and 36 deletions.
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{}
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"isomorphic-xml2js": "^0.1.3",
"jest": "^27.0.4",
"js-cookie": "^2.2.1",
"js-md5": "^0.8.3",
"jss": "^10.6.0",
"lodash": "^4.17.21",
"maplibre-gl": "^3.3.1",
Expand All @@ -52,6 +53,8 @@
"react-custom-scrollbars": "^4.2.1",
"react-dom": "^18.2.0",
"react-jss": "^10.6.0",
"react-split-pane": "^0.1.92",
"react-zoom-pan-pinch": "^3.3.0",
"simple-opening-hours": "^0.1.1",
"styled-components": "^5.3.0",
"styled-jsx": "^3.4.4"
Expand Down
12 changes: 11 additions & 1 deletion src/components/App/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { TitleAndMetaTags } from '../../helpers/TitleAndMetaTags';
import { InstallDialog } from '../HomepagePanel/InstallDialog';
import { setIntlForSSR } from '../../services/intl';
import { EditDialogProvider } from '../FeaturePanel/helpers/EditDialogContext';
import { ClimbingDialog } from '../FeaturePanel/Climbing/ClimbingDialog';
import { ClimbingContextProvider } from '../FeaturePanel/Climbing/contexts/ClimbingContext';
import { StarsProvider } from '../utils/StarsContext';

const usePersistMapView = () => {
Expand Down Expand Up @@ -64,7 +66,7 @@ const useUpdateViewFromHash = () => {
};

const IndexWithProviders = () => {
const { featureShown, preview } = useFeatureContext();
const { feature, featureShown, preview } = useFeatureContext();
const router = useRouter();
useUpdateViewFromFeature();
usePersistMapView();
Expand All @@ -79,11 +81,19 @@ const IndexWithProviders = () => {
};

// TODO add correct error boundaries

const isClimbingDialogShown = router.query.all?.[2] === 'climbing';
return (
<>
<SearchBox />
<Loading />
{featureShown && <FeaturePanel />}
{isClimbingDialogShown && (
<ClimbingContextProvider feature={feature}>
<ClimbingDialog />
</ClimbingContextProvider>
)}

<HomepagePanel />
{router.pathname === '/install' && <InstallDialog />}
<Map />
Expand Down
103 changes: 103 additions & 0 deletions src/components/FeaturePanel/Climbing/ClimbingDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, { useRef } from 'react';
import styled from 'styled-components';
import {
Button,
Dialog,
DialogActions,
DialogContent,
} from '@material-ui/core';
import AddIcon from '@material-ui/icons/Add';
import Router from 'next/router';
import { ClimbingView } from './ClimbingView';
import { useClimbingContext } from './contexts/ClimbingContext';
import { ClimbingDialogHeader } from './ClimbingDialogHeader';
import { getOsmappLink } from '../../../services/helpers';
import { useFeatureContext } from '../../utils/FeatureContext';
import { useGetHandleSave } from './useGetHandleSave';

const Flex = styled.div`
display: flex;
justify-content: space-between;
width: 100%;
`;

export const ClimbingDialog = () => {
const contentRef = useRef(null);

const {
setScrollOffset,
isPointMoving,
setIsEditMode,
isEditMode,
getMachine,
showDebugMenu,
} = useClimbingContext();
const { feature } = useFeatureContext();
const handleSave = useGetHandleSave(setIsEditMode);

const machine = getMachine();

const onScroll = (e) => {
setScrollOffset({
x: e.target.scrollLeft,
y: e.target.scrollTop,
units: 'px',
});
};

const handleClose = () => {
Router.push(`${getOsmappLink(feature)}${window.location.hash}`);
};

const onNewRouteCreate = () => {
machine.execute('createRoute');
};

return (
<Dialog fullScreen open onClose={handleClose}>
<ClimbingDialogHeader onClose={handleClose} />

<DialogContent
dividers
style={{
overscrollBehavior: isPointMoving ? 'none' : undefined,
padding: 0,
}}
ref={contentRef}
onScroll={onScroll}
>
<ClimbingView />
</DialogContent>

{isEditMode && (
<DialogActions>
<Flex>
{isEditMode && (
<Button
onClick={onNewRouteCreate}
color="primary"
startIcon={<AddIcon />}
>
Add new route
</Button>
)}
<div>
<Button autoFocus onClick={handleClose}>
Cancel
</Button>
{showDebugMenu && (
<Button
onClick={handleSave}
variant="contained"
color="primary"
>
Save
</Button>
)}
</div>
</Flex>
</DialogActions>
)}
</Dialog>
);
};
115 changes: 115 additions & 0 deletions src/components/FeaturePanel/Climbing/ClimbingDialogHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React, { useState } from 'react';
import styled from 'styled-components';
import { AppBar, Toolbar, Typography, IconButton } from '@material-ui/core';
import CloseIcon from '@material-ui/icons/Close';
import TuneIcon from '@material-ui/icons/Tune';
import { useClimbingContext } from './contexts/ClimbingContext';
import { ClimbingSettings } from './ClimbingSettings';
import { PhotoLink } from './PhotoLink';
import { useFeatureContext } from '../../utils/FeatureContext';
import { getLabel } from '../../../helpers/featureLabel';

const Title = styled.div`
flex: 1;
overflow: hidden;
`;
const PhotosContainer = styled.div`
display: flex;
flex-direction: row;
gap: 4px;
`;
const PhotosTitle = styled.div`
color: ${({ theme }) => theme.textSubdued};
`;
const PhotoLinks = styled.div`
display: flex;
flex-wrap: wrap;
flex-direction: row;
gap: 4px;
margin-bottom: 2px;
`;

export const ClimbingDialogHeader = ({ onClose }) => {
const [isSettingsOpened, setIsSettingsOpened] = useState<boolean>(false);
const [clickCounter, setClickCounter] = useState<number>(0);
const {
areRoutesVisible,
setPhotoPath,
photoPath,
loadPhotoRelatedData,
setAreRoutesLoading,
photoPaths,
setShowDebugMenu,
} = useClimbingContext();

const onPhotoChange = (photo: string) => {
setAreRoutesLoading(true);
setPhotoPath(photo);
setTimeout(() => {
// @TODO fix it without timeout
loadPhotoRelatedData();
}, 100);
};
const { feature } = useFeatureContext();

const label = getLabel(feature);

const handleOnClick = () => {
setClickCounter(clickCounter + 1);
if (clickCounter === 4) {
setShowDebugMenu(true);
setClickCounter(0);
}
};

return (
<AppBar position="static" color="transparent">
<Toolbar variant="dense">
<Title>
<Typography
noWrap
variant="h6"
component="div"
onClick={handleOnClick}
>
{label}
</Typography>
{photoPaths?.length > 1 && (
<PhotosContainer>
<PhotosTitle>Photos:</PhotosTitle>
<PhotoLinks>
{photoPaths.map((photo, index) => (
<PhotoLink
onClick={() => onPhotoChange(photo)}
isCurrentPhoto={photo === photoPath}
>
{index}
</PhotoLink>
))}
</PhotoLinks>
</PhotosContainer>
)}
</Title>

<IconButton
color="primary"
edge="end"
title={areRoutesVisible ? 'Hide routes' : 'Show routes'}
onClick={() => {
setIsSettingsOpened(!isSettingsOpened);
}}
>
<TuneIcon fontSize="small" />
</IconButton>

<IconButton color="primary" edge="end" onClick={onClose}>
<CloseIcon fontSize="small" />
</IconButton>
</Toolbar>
<ClimbingSettings
isSettingsOpened={isSettingsOpened}
setIsSettingsOpened={setIsSettingsOpened}
/>
</AppBar>
);
};
115 changes: 115 additions & 0 deletions src/components/FeaturePanel/Climbing/ClimbingPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import React from 'react';
import styled from 'styled-components';
import { CircularProgress } from '@material-ui/core';
import Router from 'next/router';
import { useClimbingContext } from './contexts/ClimbingContext';
import { PanelScrollbars, PanelWrapper } from '../../utils/PanelHelpers';
import { RoutesLayer } from './Editor/RoutesLayer';
import { RouteList } from './RouteList/RouteList';
import { FullscreenIconContainer, ShowFullscreen } from './ShowFullscreen';
import { useFeatureContext } from '../../utils/FeatureContext';
import { getLabel } from '../../../helpers/featureLabel';
import { getCommonsImageUrl } from '../../../services/images/getWikiImage';
import { getOsmappLink } from '../../../services/helpers';

const ThumbnailContainer = styled.div<{ height: number }>`
width: 100%;
height: ${({ height }) => height}px;
position: relative;
:hover ${FullscreenIconContainer} {
visibility: visible;
backdrop-filter: blur(3px);
background-color: rgba(0, 0, 0, 0.5);
cursor: pointer;
}
`;

const Heading = styled.div`
margin: 12px 8px 4px;
font-size: 36px;
line-height: 0.98;
color: ${({ theme }) => theme.palette.text.panelHeading};
:hover {
text-decoration: underline;
cursor: pointer;
}
`;
const Thumbnail = styled.img<{ isLoading: boolean }>`
width: 100%;
position: absolute;
visibility: ${({ isLoading }) => (isLoading ? 'hidden' : 'visible')};
`;

const LoadingContainer = styled.div`
position: absolute;
left: 0;
top: 0;
display: flex;
justify-content: center;
width: 100%;
height: 100%;
align-items: center;
`;

export const ClimbingPanel = ({ footer }) => {
const { feature } = useFeatureContext();
const label = getLabel(feature);

const {
loadPhotoRelatedData,
imageSize,
photoPath,
photoRef,
preparePhotosAndSetFirst,
} = useClimbingContext();

const onFullScreenClick = () => {
Router.push(`${getOsmappLink(feature)}/climbing${window.location.hash}`);
};

preparePhotosAndSetFirst();

const imageUrl = getCommonsImageUrl(`File:${photoPath}`, 500);

const onPhotoLoad = () => {
loadPhotoRelatedData();
};

const isPhotoLoading = imageSize.height === 0;
return (
<>
<PanelWrapper>
<PanelScrollbars>
{photoPath && imageUrl && (
<ThumbnailContainer
height={isPhotoLoading ? 200 : imageSize.height}
>
{isPhotoLoading && (
<LoadingContainer>
<CircularProgress />
</LoadingContainer>
)}

<Thumbnail
src={imageUrl}
ref={photoRef}
onLoad={onPhotoLoad}
isLoading={isPhotoLoading}
/>

{!isPhotoLoading && <RoutesLayer onClick={() => null} />}
<ShowFullscreen onClick={onFullScreenClick} />
</ThumbnailContainer>
)}
<Heading onClick={onFullScreenClick}>{label}</Heading>

<RouteList />

{/* @TODO unite with parent panel */}
<div style={{ padding: '20px 15px 0 15px' }}>{footer}</div>
</PanelScrollbars>
</PanelWrapper>
</>
);
};
Loading

0 comments on commit 8c76aca

Please sign in to comment.