feat: add site-wide glossary with hover tooltips
CI / TypeScript — type-check (push) Successful in 8s
CI / Publish — build & push image (push) Successful in 8s
CI / Deploy — pull & restart on host (push) Successful in 2s

Every abbreviation and technical term used in the site's copy (RBAC,
NAPALM, config drift, ...) now links to a new /glossary page and shows
a short definition on hover, wherever it appears in body text. Product
and vendor brand names are deliberately excluded — the glossary stays
a dictionary of vocabulary, not a company directory.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Christian Manivong
2026-07-02 18:37:35 +02:00
co-authored by Claude Sonnet 5
parent 2a8a87bdd1
commit 38c7fb1db9
14 changed files with 758 additions and 31 deletions
+6 -5
View File
@@ -1,6 +1,7 @@
import { Link } from 'react-router-dom'
import { ShieldCheckIcon } from '@heroicons/react/24/outline'
import { useLang } from '../context/LangContext'
import { linkify } from '../lib/glossary'
type Coverage = 'covered' | 'partial' | 'roadmap' | 'na'
type Requirement = { article: string; label: string; coverage: Coverage; netork: string }
@@ -147,7 +148,7 @@ export default function Nis2() {
<ShieldCheckIcon className="h-5 w-5 text-sky-400" />
</div>
<h1 className="text-4xl md:text-5xl font-bold text-slate-100 mb-4">{t.nis2.heading}</h1>
<p className="text-base text-slate-400 leading-relaxed max-w-2xl">{t.nis2.sub}</p>
<p className="text-base text-slate-400 leading-relaxed max-w-2xl">{linkify(t.nis2.sub)}</p>
</div>
<div className="mb-20">
@@ -164,7 +165,7 @@ export default function Nis2() {
</div>
<CoverageTag coverage={r.coverage} labels={coverageLabels} />
</div>
<p className="text-sm text-slate-500 leading-relaxed md:pl-24">{r.netork}</p>
<p className="text-sm text-slate-500 leading-relaxed md:pl-24">{linkify(r.netork)}</p>
</div>
))}
</div>
@@ -182,7 +183,7 @@ export default function Nis2() {
<h2 className="text-xl font-semibold text-slate-200 mb-2 pb-2 border-b border-slate-800">
{t.nis2.evidenceHeading}
</h2>
<p className="text-sm text-slate-500 mb-6">{t.nis2.evidenceSub}</p>
<p className="text-sm text-slate-500 mb-6">{linkify(t.nis2.evidenceSub)}</p>
<div className="space-y-6">
{evidence.map((e) => (
<div key={e.trigger} className="rounded-xl border border-slate-800 bg-slate-900 p-5">
@@ -191,7 +192,7 @@ export default function Nis2() {
{e.produces.map((item) => (
<li key={item} className="flex items-start gap-2 text-sm text-slate-400">
<span className="mt-1.5 h-1.5 w-1.5 shrink-0 rounded-full bg-sky-500" />
{item}
{linkify(item)}
</li>
))}
</ul>
@@ -210,7 +211,7 @@ export default function Nis2() {
<div className="mt-2 shrink-0 h-1.5 w-1.5 rounded-full bg-sky-500" />
<div>
<p className="text-sm font-medium text-slate-200">{item.title}</p>
<p className="text-sm text-slate-500 mt-0.5">{item.detail}</p>
<p className="text-sm text-slate-500 mt-0.5">{linkify(item.detail)}</p>
</div>
</div>
))}