Skip to content

Commit

Permalink
Merge branch 'master' into editdialog-fields
Browse files Browse the repository at this point in the history
  • Loading branch information
zbycz authored Nov 6, 2024
2 parents b39ecdd + 8a0e9a4 commit bed6695
Show file tree
Hide file tree
Showing 80 changed files with 2,198 additions and 501 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ See also [SotM 2021 talk](https://github.com/zbycz/osmapp-talk).

Open climbing maps and topos. Photos are uploaded to _Wikimedia Commons_ and route data stored in _OpenStreetMap_ ([spec](https://wiki.openstreetmap.org/wiki/Key:wikimedia_commons:path)).

- **[Story behind openclimbing.org](https://medium.com/@jvaclavik/story-behind-openclimbing-org-ab448939c6ac)**
- master branch: https://openclimbing.org
- examples: [Prokopské údolí](https://openclimbing.org/relation/17262674),
[Roviště](https://openclimbing.org/relation/17130100),
Expand All @@ -35,7 +36,7 @@ You may [add issues](https://github.com/zbycz/osmapp/issues) here on GitHub, or

- **clickable map** – poi, cities, localities, ponds (more coming soon)
- **feature panel** – presets and fields from iD editor
- Display multiple images from Wikipedia, Wikidata, Commons, Mapillary or Fody
- Display multiple images from Wikipedia, Wikidata, Commons, Mapillary, KartaView, Panoramax or Fody
- Line numbers on public transport stops
- Runway table on airports
- **editing** – Save changes with osm login. Insert note for anonymous users.
Expand Down
3 changes: 3 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,15 @@
yarn
nodePackages.typescript-language-server
prettierd

libuuid # For jest
];
shellHook = ''
if [ ! -d node_modules ]; then
echo "Use yarn to install dependencies"
fi
'';
env = {LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.libuuid];};
};
});
};
Expand Down
12 changes: 0 additions & 12 deletions src/components/Directions/DirectionsButton.tsx

This file was deleted.

128 changes: 2 additions & 126 deletions src/components/FeaturePanel/Coordinates.tsx
Original file line number Diff line number Diff line change
@@ -1,142 +1,18 @@
import React, { forwardRef } from 'react';
import styled from '@emotion/styled';
import { MenuItem, IconButton, Menu, Divider } from '@mui/material';
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { useMapStateContext } from '../utils/MapStateContext';
import { isMobileDevice, useBoolState } from '../helpers';
import React from 'react';
import { useFeatureContext } from '../utils/FeatureContext';
import { getIdEditorLink, positionToDeg, positionToDM } from '../../utils';
import { positionToDeg } from '../../utils';
import { PositionBoth } from '../../services/types';
import { getFullOsmappLink, getShortLink } from '../../services/helpers';
import { t } from '../../services/intl';

const StyledMenuItem = styled(MenuItem)`
svg {
font-size: 12px;
color: #bbb;
margin: -7px 0 0 5px;
}
&:focus {
text-decoration: none;
svg {
outline: 0;
}
}
` as unknown as any; // <Menu> expects "li", but it as "a"

const StyledToggleButton = styled(IconButton)`
margin: -10px 0 -5px 0 !important;
svg {
font-size: 17px;
}
`;

export const ToggleButton = forwardRef<any, any>(
({ onClick, isShown = false }, ref) => (
<StyledToggleButton onClick={onClick} aria-label="Toggle">
{!isShown && <ExpandMoreIcon fontSize="small" ref={ref} />}
{isShown && <ExpandLessIcon fontSize="small" ref={ref} />}
</StyledToggleButton>
),
);
ToggleButton.displayName = 'ToggleButton';

const CopyTextItem = ({ text }: { text: string | null }) =>
text === null ? null : (
<MenuItem onClick={() => navigator.clipboard.writeText(text)}>
{t('coordinates.copy_value', {
value: text.replace(/^https:\/\//, ''),
})}
</MenuItem>
);

const LinkItem = ({ href, label }) => (
<StyledMenuItem component="a" href={href} target="_blank">
{label} <OpenInNewIcon />
</StyledMenuItem>
);

// Our map uses 512 tiles, so our zoom is "one less"
// https://wiki.openstreetmap.org/wiki/Zoom_levels#Mapbox_GL
const MAPLIBREGL_ZOOM_DIFFERENCE = 1;

const useGetItems = ([lon, lat]: PositionBoth) => {
const { feature } = useFeatureContext();
const { view } = useMapStateContext();
const [ourZoom] = view;

const zoom = parseFloat(ourZoom) + MAPLIBREGL_ZOOM_DIFFERENCE;
const zoomInt = Math.round(zoom);
const osmQuery = feature?.osmMeta?.id
? `${feature.osmMeta.type}/${feature.osmMeta.id}`
: `?mlat=${lat}&mlon=${lon}&zoom=${zoomInt}`;

return [
{
label: 'OpenStreetMap.org',
href: `https://openstreetmap.org/${osmQuery}`,
},
{
label: 'OpenStreetMap.cz',
href: `https://openstreetmap.cz/${osmQuery}`,
},
{
label: 'Mapy.cz',
href: `https://mapy.cz/zakladni?q=${lat}%C2%B0%20${lon}%C2%B0`,
},
{
label: 'Google Maps',
href: `https://google.com/maps/search/${lat}%C2%B0%20${lon}%C2%B0/@${lat},${lon},${zoomInt}z`,
},
{
label: 'iD editor',
href: getIdEditorLink(feature, view), // TODO coordsFeature has random id which gets forwarded LOL
},
...(isMobileDevice()
? [
{
label: t('coordinates.geo_uri'),
href: `geo:${lat},${lon}`,
},
]
: []),
];
};

type Props = { coords: PositionBoth };

export const Coords = ({ coords }: Props) => {
const [opened, open, close] = useBoolState(false);
const anchorRef = React.useRef();
const items = useGetItems(coords);
const { feature } = useFeatureContext();
const osmappLink = getFullOsmappLink(feature);
const shortLink = getShortLink(feature);

return (
<span title="latitude, longitude (y, x)" ref={anchorRef}>
{positionToDeg(coords)}
{feature.countryCode && ` (${feature.countryCode.toUpperCase()})`}
<Menu
anchorEl={anchorRef.current}
open={opened}
onClose={close}
disableAutoFocusItem
>
{items.map(({ label, href }) => (
<LinkItem key={label} href={href} label={label} />
))}
<Divider />
<CopyTextItem text={positionToDeg(coords)} />
<CopyTextItem text={positionToDM(coords)} />
<CopyTextItem text={osmappLink} />
<CopyTextItem text={shortLink} />
</Menu>
<ToggleButton onClick={open} />
</span>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useEditDialogContext } from '../../helpers/EditDialogContext';
import { useEditContext } from '../EditContext';
import { OpeningHoursEditor } from './OpeningHoursEditor/OpeningHoursEditor';
import styled from '@emotion/styled';
import { CharacterCount } from './helpers';
import { CharacterCount, getInputTypeForKey } from './helpers';

export const majorKeys = [
'name',
Expand All @@ -21,7 +21,7 @@ export const majorKeys = [

const MAX_INPUT_LENGTH = 255;

const getData = (numberOfWikimediaItems) => {
const getData = (numberOfWikimediaItems: number) => {
const wikimediaCommonTags = Array(numberOfWikimediaItems)
.fill('')
.reduce((acc, _, index) => {
Expand All @@ -47,19 +47,30 @@ const InputContainer = styled.div`
position: relative;
`;

type TextFieldProps = {
k: string;
label: string;
onChange: React.ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement>;
value?: string;
autoFocus?: boolean;
};

const TextFieldWithCharacterCount = ({
k,
label,
autoFocus,
onChange,
value,
}) => {
}: TextFieldProps) => {
const [isFocused, setIsFocused] = useState(false);
const inputType = getInputTypeForKey(k);

return (
<InputContainer>
<TextField
label={label}
multiline
type={inputType}
multiline={inputType === 'text'}
value={value}
InputLabelProps={{ shrink: true }}
variant="outlined"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { DialogHeading } from '../components';
import { t, Translation } from '../../../../services/intl';
import { useOsmAuthContext } from '../../../utils/OsmAuthContext';
import { useToggleState } from '../../../helpers';
import { getIdEditorLink } from '../../../../utils';
import { getIdEditorLink } from '../../helpers/externalLinks';

export const PlaceCancelledToggle = () => {
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useEditDialogContext } from '../../../helpers/EditDialogContext';
import { useEditContext } from '../../EditContext';
import { IconButton, Stack, TextField } from '@mui/material';
import DeleteIcon from '@mui/icons-material/Delete';
import { getInputTypeForKey } from '../helpers';

const useHidableDeleteButton = () => {
const buttonRef = useRef<HTMLButtonElement>(null);
Expand Down Expand Up @@ -34,7 +35,10 @@ const DeleteButton = ({ deleteButton, index }: DeleteButtonProps) => {
setTagsEntries((state) => state.toSpliced(index, 1));
};

return deleteButton.shown ? (
if (!deleteButton.shown) {
return null;
}
return (
<IconButton
size="small"
onClick={onClick}
Expand All @@ -43,7 +47,7 @@ const DeleteButton = ({ deleteButton, index }: DeleteButtonProps) => {
>
<DeleteIcon fontSize="small" />
</IconButton>
) : null;
);
};

type Props = { index: number };
Expand All @@ -65,6 +69,7 @@ export const ValueInput = ({ index }: Props) => {
return (
<Stack direction="row" spacing={1} alignItems="center">
<TextField
type={getInputTypeForKey(currentKey)}
value={currentValue}
onChange={handleChange}
fullWidth
Expand Down
22 changes: 22 additions & 0 deletions src/components/FeaturePanel/EditDialog/EditContent/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,25 @@ export const CharacterCount = ({
</Stack>
</CharacterCountContainer>
) : null;

export const getInputTypeForKey = (key: string) => {
switch (key) {
case 'fax':
case 'phone':
case 'mobile':
case 'contact:phone':
case 'contact:whatsapp':
case 'contact:mobile':
case 'contact:tty':
case 'contact:sms':
case 'contact:fax':
return 'tel';
case 'contact:website':
case 'website':
return 'url';
case 'contact:email':
case 'email':
return 'email';
}
return 'text';
};
4 changes: 4 additions & 0 deletions src/components/FeaturePanel/EditDialog/useGetHandleSave.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export const useGetHandleSave = () => {
showToast(t('editdialog.osm_session_expired'), 'error');
handleLogout();
} else {
showToast(
`${t('editdialog.save_refused')} ${err.responseText ?? err.message}`,
'error',
);
console.error(err); // eslint-disable-line no-console
}
setTimeout(() => setIsSaving(false), 500);
Expand Down
3 changes: 2 additions & 1 deletion src/components/FeaturePanel/EditDialog/useGetOnClose.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ export const useGetOnClose = () => {
return () => {
close();
if (successInfo?.redirect) {
router.replace(successInfo.redirect); // only useRouter reloads the panel client-side
// Reloads the panel client-side
router.replace('/').then(() => router.replace(successInfo?.redirect));
}
};
};
5 changes: 2 additions & 3 deletions src/components/FeaturePanel/FeatureHeading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import EditIcon from '@mui/icons-material/Edit';
import { IconButton, useMediaQuery } from '@mui/material';
import { useEditDialogContext } from './helpers/EditDialogContext';
import { PoiDescription } from './helpers/PoiDescription';
import { StarButton } from './helpers/StarButton';
import { getLabel, getSecondaryLabel } from '../../helpers/featureLabel';
import { useFeatureContext } from '../utils/FeatureContext';
import { t } from '../../services/intl';
import { isMobileDevice } from '../helpers';
import { QuickActions } from './QuickActions/QuickActions';

const StyledEditButton = styled(IconButton)`
visibility: hidden;
Expand Down Expand Up @@ -95,7 +95,6 @@ const SecondaryHeading = styled.h2<{ $deleted: boolean }>`
export const FeatureHeading = React.forwardRef<HTMLDivElement>((_, ref) => {
// thw pwa needs space at the bottom
const isStandalone = useMediaQuery('(display-mode: standalone)');
const { feature } = useFeatureContext();

return (
<Container ref={ref} isStandalone={isStandalone}>
Expand All @@ -106,8 +105,8 @@ export const FeatureHeading = React.forwardRef<HTMLDivElement>((_, ref) => {
{/* <YellowedBadge /> */}
<EditNameButton />
</NameWithEdit>
{!feature.point && <StarButton />}
</HeadingContainer>
<QuickActions />
</Container>
);
});
Expand Down
4 changes: 3 additions & 1 deletion src/components/FeaturePanel/ImagePane/Image/InfoButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ const TooltipContent = ({ image }: { image: ImageType }) => (
<>
<br />
<br />
{t('featurepanel.uncertain_image')}
{t('featurepanel.uncertain_image', {
from: image.provider ?? 'Mapillary',
})}
</>
)}
</>
Expand Down
6 changes: 6 additions & 0 deletions src/components/FeaturePanel/Properties/getUrlForTag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ export const getUrlForTag = (k: string, v: string) => {
if (k === 'website') {
return v.match(urlRegExp) ? v : `http://${v}`;
}
if (k === 'mapillary' && v.match(/^\d+$/)) {
return `https://www.mapillary.com/app/?pKey=${v}&focus=photo`;
}
if (k === 'panoramax') {
return `https://panoramax.xyz/#focus=pic&pic=${v}`;
}
if (k.match(/^(contact:)?email$/)) {
return `mailto:${v}`;
}
Expand Down
Loading

0 comments on commit bed6695

Please sign in to comment.