Skip to content

Commit

Permalink
layers: Add attribution to layers (zbycz#154)
Browse files Browse the repository at this point in the history
* layers: Add attribution to layers

* fix window in SSR

* mapfooter client-only

* fix attribution for user layers
  • Loading branch information
zbycz authored Jun 14, 2023
1 parent eae3f19 commit 92467f8
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 52 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
/coverage
/build
/dist
/tsconfig.tsbuildinfo
.next
.DS_Store
.env
Expand Down
28 changes: 23 additions & 5 deletions src/components/LayerSwitcher/osmappLayers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,42 @@ import SatelliteIcon from '@material-ui/icons/Satellite';
import DirectionsBikeIcon from '@material-ui/icons/DirectionsBike';
import { Layer } from '../utils/MapStateContext';
import { t } from '../../services/intl';
import { isBrowser } from '../helpers';

interface Layers {
[key: string]: Layer;
}

const retina = (window.devicePixelRatio || 1) >= 2 ? '@2x' : '';
const retina =
((isBrowser() && window.devicePixelRatio) || 1) >= 2 ? '@2x' : '';

export const osmappLayers: Layers = {
basic: { name: t('layers.basic'), type: 'basemap', Icon: ExploreIcon },
outdoor: { name: t('layers.outdoor'), type: 'basemap', Icon: FilterHdrIcon },
basic: {
name: t('layers.basic'),
type: 'basemap',
Icon: ExploreIcon,
attribution: ['maptiler', 'osm'],
},
outdoor: {
name: t('layers.outdoor'),
type: 'basemap',
Icon: FilterHdrIcon,
attribution: ['maptiler', 'osm'],
},
s1: { type: 'spacer' },
mapnik: {
name: t('layers.mapnik'),
type: 'basemap',
url: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
Icon: MapIcon,
attribution: ['osm'],
},
sat: {
name: t('layers.sat'),
type: 'basemap',
url: 'https://api.maptiler.com/tiles/satellite-v2/tiles.json?key=7dlhLl3hiXQ1gsth0kGu',
Icon: SatelliteIcon,
attribution: ['maptiler'],
},
// mtb: {
// name: t('layers.mtb'),
Expand All @@ -36,12 +50,16 @@ export const osmappLayers: Layers = {
bike: {
name: t('layers.bike'),
type: 'basemap',
url: `https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}${retina}.png?apikey=00291b657a5d4c91bbacb0ff096e2c25`,
url: `https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}${retina}.png?apikey=18c0cb31f2fd41d28ac90abe4059e359`,
Icon: DirectionsBikeIcon,
attribution: [
'&copy; <a href="https://www.thunderforest.com/">Thunderforest</a>',
'osm',
],
},
// snow: {
// name: t('layers.snow'),
// type: 'basemap',
// type: 'overlay',
// url: 'https://www.opensnowmap.org/tiles-pistes/{z}/{x}/{y}.png',
// },
// s2: { type: 'spacer' },
Expand Down
105 changes: 68 additions & 37 deletions src/components/Map/MapFooter/MapFooter.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import getConfig from 'next/config';
import { Tooltip, useMediaQuery } from '@material-ui/core';
import uniq from 'lodash/uniq';
import { t, Translation } from '../../../services/intl';
import GithubIcon from '../../../assets/GithubIcon';
import { MoreMenu } from './MoreMenu';
import { LangSwitcher } from './LangSwitcher';
import { useMapStateContext } from '../../utils/MapStateContext';
import { osmappLayers } from '../../LayerSwitcher/osmappLayers';

const {
publicRuntimeConfig: { osmappVersion, commitHash, commitMessage },
Expand Down Expand Up @@ -49,46 +52,74 @@ const OsmappLink = () => (
</>
);

const Attribution = ({ label, link, title }) => (
<>
©{' '}
<Tooltip arrow title={title}>
<a href={link} target="_blank" rel="noopener">
{label}
</a>
</Tooltip>
</>
);

const MapDataLink = () => {
const short = useMediaQuery('(max-width: 500px)');

return (
<>
©{' '}
<Tooltip
arrow
title={<Translation id="map.maptiler_copyright_tooltip" />}
>
<a
href="https://www.maptiler.com/copyright/"
target="_blank"
rel="noopener"
>
MapTiler
</a>
</Tooltip>{' '}
©{' '}
<Tooltip arrow title={<Translation id="map.osm_copyright_tooltip" />}>
<a
href="https://www.openstreetmap.org/copyright"
target="_blank"
rel="noopener"
>
{short ? 'OSM' : 'OpenStreetMap'}
</a>
</Tooltip>
</>
const { activeLayers } = useMapStateContext();
const attributions = uniq(
activeLayers.flatMap((layer) =>
osmappLayers[layer]
? osmappLayers[layer].attribution
: decodeURI(new URL(layer)?.hostname),
),
);

const nodes = attributions.map((attribution) => {
if (attribution === 'maptiler')
return (
<Attribution
label="MapTiler"
link="https://www.maptiler.com/"
title={<Translation id="map.maptiler_copyright_tooltip" />}
/>
);
if (attribution === 'osm')
return (
<Attribution
label={short ? 'OSM' : 'OpenStreetMap'}
link="https://www.openstreetmap.org/"
title={<Translation id="map.osm_copyright_tooltip" />}
/>
);

return <span dangerouslySetInnerHTML={{ __html: attribution }} />;
});

// place a separator between attributions
for (let i = 1; i < nodes.length; i += 2) {
nodes.splice(i, 0, ' ');
}

return nodes;
};

const ClientOnly = ({ children }) => {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
return mounted ? children : null;
};

export const MapFooter = () => (
<Wrapper>
<OsmappLink />
{' | '}
<LangSwitcher />
{' | '}
<MapDataLink />
{' | '}
<MoreMenu />
</Wrapper>
// TODO find a way how to render this in SSR (keep layer in cookies?)
<ClientOnly>
<Wrapper>
<OsmappLink />
{' | '}
<LangSwitcher />
{' | '}
<MapDataLink />
{' | '}
<MoreMenu />
</Wrapper>
</ClientOnly>
);
33 changes: 23 additions & 10 deletions src/components/Map/MapFooter/MaptilerLogo.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import styled from 'styled-components';
import { useMapStateContext } from '../../utils/MapStateContext';
import { osmappLayers } from '../../LayerSwitcher/osmappLayers';

const Link = styled.a`
position: absolute;
Expand All @@ -8,13 +10,24 @@ const Link = styled.a`
z-index: 999;
`;

export const MaptilerLogo = () => (
<Link href="https://www.maptiler.com" rel="noopener" target="_blank">
<img
src="/logo/maptiler-api.svg"
alt="MapTiler logo"
width={67}
height={20}
/>
</Link>
);
export const MaptilerLogo = () => {
const { activeLayers } = useMapStateContext();
const hasMaptiler = activeLayers.some((layer) =>
osmappLayers[layer]?.attribution?.includes('maptiler'),
);

if (!hasMaptiler) {
return null;
}

return (
<Link href="https://www.maptiler.com" rel="noopener" target="_blank">
<img
src="/logo/maptiler-api.svg"
alt="MapTiler logo"
width={67}
height={20}
/>
</Link>
);
};
1 change: 1 addition & 0 deletions src/components/utils/MapStateContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface Layer {
url?: string;
key?: string;
Icon?: React.FC<any>;
attribution?: string[]; // missing in spacer TODO refactor ugly
}

// // [b.getWest(), b.getNorth(), b.getEast(), b.getSouth()]
Expand Down
1 change: 1 addition & 0 deletions src/locales/vocabulary.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,5 +155,6 @@ export default {
'layers.snow': 'Snow',
'layers.mapnik': 'OSM Mapnik',
'layers.sat': 'Satellite (z<14)',
'layers.bingSat': 'Bing satellite',
'layers.bike': 'Bike',
};

0 comments on commit 92467f8

Please sign in to comment.