diff --git a/package.json b/package.json
index acd193ae..ab5994b4 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
"showdown": "^1.8.6",
"stream": "^0.0.3",
"superagent": "^3.5.2",
+ "tag2link": "^2025.5.21",
"terra-draw": "^1.1.0",
"terra-draw-maplibre-gl-adapter": "^1.0.1"
},
diff --git a/src/components/element_info.js b/src/components/element_info.js
index dab90b57..7fb2c3b5 100644
--- a/src/components/element_info.js
+++ b/src/components/element_info.js
@@ -8,6 +8,7 @@ import { Dropdown } from './dropdown';
import { Button } from './button';
import thumbsDown from '../assets/thumbs-down.svg';
import type { RootStateType } from '../store';
+import { TagValue } from './tag_value.js';
/*
* Displays info about an element that was created/modified/deleted.
@@ -303,7 +304,9 @@ function TagsTable({ action }) {
{key}
- {newval}
+
+
+
|
);
@@ -314,7 +317,9 @@ function TagsTable({ action }) {
{key}
- {newval}
+
+
+
|
);
@@ -325,7 +330,9 @@ function TagsTable({ action }) {
{key}
- {oldval}
+
+
+
|
);
@@ -336,9 +343,13 @@ function TagsTable({ action }) {
{key}
- {oldval}
+
+
+
{' → '}
- {newval}
+
+
+
|
);
diff --git a/src/components/tag_value.js b/src/components/tag_value.js
new file mode 100644
index 00000000..6959b3a3
--- /dev/null
+++ b/src/components/tag_value.js
@@ -0,0 +1,56 @@
+// @ts-check
+import { Fragment } from 'react';
+import tag2linkRaw from 'tag2link';
+
+const RANKS = ['deprecated', 'normal', 'preferred'];
+
+/**
+ * @typedef {{
+ * key: `Key:${string}`;
+ * url: string;
+ * source: string;
+ * rank: "normal" | "preferred";
+ * }} Tag2LinkItem
+ */
+
+/** @param {Tag2LinkItem[]} input */
+function convertSourceData(input) {
+ /** @type {Record} */
+ const output = {};
+
+ const allKeys = new Set(input.map(item => item.key));
+
+ for (const key of allKeys) {
+ // find the item with the best rank
+ const bestDefinition = input
+ .filter(item => item.key === key)
+ .sort((a, b) => RANKS.indexOf(b.rank) - RANKS.indexOf(a.rank))[0];
+
+ output[key.replace('Key:', '')] = bestDefinition.url;
+ }
+
+ return output;
+}
+
+export const TAG2LINK = convertSourceData(tag2linkRaw);
+
+/** @type {React.FC<{ k: string; v: string }>} */
+export const TagValue = ({ k, v }) => {
+ const placeholderUrl = TAG2LINK[k];
+
+ // simple key, not clickable
+ if (!placeholderUrl) return v;
+
+ return v.split(';').map((chunk, index) => ((
+
+ {!!index && ';'}
+
+ {chunk}
+
+
+ )));
+};
diff --git a/yarn.lock b/yarn.lock
index a04d581c..5994df2d 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -14381,6 +14381,11 @@ table@4.0.2:
slice-ansi "1.0.0"
string-width "^2.1.1"
+tag2link@^2025.5.21:
+ version "2025.5.21"
+ resolved "https://registry.yarnpkg.com/tag2link/-/tag2link-2025.5.21.tgz#5f02fd412e854744a141b4d6217e6acf33e23d93"
+ integrity sha512-vcz6/6U5V3QYPA7geLrtzLMqhCwg6OvoGP665DbGgPRSWASjFn0J4jA/NyifD3Tmp2yf8RnEuI6QBvhXGBVSHg==
+
tailwindcss@^3.0.2:
version "3.4.15"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.15.tgz#04808bf4bf1424b105047d19e7d4bfab368044a9"