diff --git a/src/hooks/useTag2link.ts b/src/hooks/useTag2link.ts new file mode 100644 index 0000000..f24fcf3 --- /dev/null +++ b/src/hooks/useTag2link.ts @@ -0,0 +1,45 @@ +// copied from https://github.com/openstreetmap/iD/blob/575046c/modules/services/tag2Link.js + +import { useEffect, useState } from 'react'; + +type RawTag2Link = { + key: `Key:${string}`; + url: string; + source: `${'osmwiki' | 'wikidata'}:P${number}`; + rank: 'preferred' | 'normal' | 'deprecated'; +}; + +const RANKS = ['deprecated', 'normal', 'preferred']; + +async function getTag2Link() { + const array: RawTag2Link[] = await fetch( + 'https://cdn.jsdelivr.net/gh/JOSM/tag2link@master/index.json', + ).then((r) => r.json()); + + const map = new Map(); + + const allKeys = new Set(array.map((item) => item.key)); + + for (const key of allKeys) { + // find an item with the best rank + const bestDefinition = array + .filter((item) => item.key === key) + .sort((a, b) => RANKS.indexOf(b.rank) - RANKS.indexOf(a.rank))[0]; + + map.set(key.replace('Key:', ''), bestDefinition.url); + } + + return map; +} + +let promise: ReturnType | undefined; + +export function useTag2link() { + const [value, setValue] = useState>(); + + useEffect(() => { + (promise ||= getTag2Link()).then(setValue).catch(console.error); + }, []); + + return value; +} diff --git a/src/pages/upload/components/DiffForFeature.tsx b/src/pages/upload/components/DiffForFeature.tsx index 3e5ae4c..fdc64b3 100644 --- a/src/pages/upload/components/DiffForFeature.tsx +++ b/src/pages/upload/components/DiffForFeature.tsx @@ -6,8 +6,10 @@ import type { OsmPatchFeature } from '../../../types'; import { MAP } from '../../HistoryRestorer/util'; import { AuthContext } from '../../../wrappers'; import classes from '../Upload.module.css'; +import { useTag2link } from '../../../hooks/useTag2link'; import { OpenInLinks } from './OpenInLinks'; import { LatLngDiff } from './LatLngDiff'; +import { MaybeLink } from './MaybeLink'; const EMPTY_CELL =  ; @@ -15,6 +17,7 @@ export const DiffForFeature: React.FC<{ feature: OsmPatchFeature; original: OsmFeature | undefined; }> = ({ feature, original }) => { + const tag2link = useTag2link(); const { user: me } = useContext(AuthContext); const type = MAP[`${feature.id}`[0] as keyof typeof MAP]; @@ -141,6 +144,8 @@ export const DiffForFeature: React.FC<{ : classes.removed : classes.added; + const formatter = tag2link?.get(key); + return ( {key} @@ -149,9 +154,11 @@ export const DiffForFeature: React.FC<{ colour === classes.changedNew ? classes.changedOld : '' } > - {originalValue} + + + + - {newValue} ); })} diff --git a/src/pages/upload/components/MaybeLink.tsx b/src/pages/upload/components/MaybeLink.tsx new file mode 100644 index 0000000..ab42edc --- /dev/null +++ b/src/pages/upload/components/MaybeLink.tsx @@ -0,0 +1,26 @@ +export function getUrlHost(url: string) { + try { + return new URL(url).host.replace(/^www\./, ''); + } catch { + return undefined; + } +} + +export const MaybeLink: React.FC<{ + value: string; + formatter: string | undefined; +}> = ({ formatter, value }) => { + if (!formatter) return value; + + const url = formatter.replaceAll('$1', value); + return ( + + {value} + + ); +};