feat: add site-wide glossary with hover tooltips
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:
co-authored by
Claude Sonnet 5
parent
2a8a87bdd1
commit
38c7fb1db9
@@ -35,6 +35,7 @@ export default function Footer() {
|
||||
<li><Link to="/docs/architecture" className="text-slate-500 hover:text-slate-100 transition-colors">{t.footer.architecture}</Link></li>
|
||||
<li><span className="text-slate-600">{t.footer.changelog}</span></li>
|
||||
<li><Link to="/nis2" className="text-slate-500 hover:text-slate-100 transition-colors">{t.footer.nis2}</Link></li>
|
||||
<li><Link to="/glossary" className="text-slate-500 hover:text-slate-100 transition-colors">{t.footer.glossary}</Link></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useLang } from '../context/LangContext'
|
||||
import { GLOSSARY } from '../glossary/terms'
|
||||
|
||||
const BY_ID = new Map(GLOSSARY.map((entry) => [entry.id, entry]))
|
||||
|
||||
export default function GlossaryMark({ id, children }: { id: string; children: ReactNode }) {
|
||||
const { lang } = useLang()
|
||||
const entry = BY_ID.get(id)
|
||||
if (!entry) return <>{children}</>
|
||||
|
||||
const name = entry.fullName ? entry.fullName[lang] : entry.display
|
||||
|
||||
return (
|
||||
<Link
|
||||
to={`/glossary#${entry.id}`}
|
||||
className="group relative border-b border-dotted border-sky-500/60 hover:border-sky-400 hover:text-sky-300 transition-colors"
|
||||
>
|
||||
{children}
|
||||
<span
|
||||
className="pointer-events-none absolute bottom-full left-1/2 z-20 mb-2 w-64 -translate-x-1/2 rounded-lg
|
||||
border border-slate-700 bg-slate-900 p-3 text-left text-xs font-normal normal-case
|
||||
text-slate-400 opacity-0 shadow-2xl transition-opacity group-hover:opacity-100"
|
||||
>
|
||||
<span className="mb-1 block font-semibold text-slate-200">{name}</span>
|
||||
{entry.definition[lang]}
|
||||
</span>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
@@ -31,7 +31,8 @@ export default function Nav() {
|
||||
: 'text-slate-400 hover:text-slate-100'
|
||||
}`
|
||||
|
||||
const isDocsActive = location.pathname.startsWith('/docs') || location.pathname === '/nis2'
|
||||
const isDocsActive =
|
||||
location.pathname.startsWith('/docs') || location.pathname === '/nis2' || location.pathname === '/glossary'
|
||||
|
||||
return (
|
||||
<nav className="sticky top-0 z-10 bg-slate-900/80 backdrop-blur border-b border-slate-800">
|
||||
@@ -84,6 +85,12 @@ export default function Nav() {
|
||||
>
|
||||
{t.nav.docsItems.nis2}
|
||||
</Link>
|
||||
<Link
|
||||
to="/glossary"
|
||||
className="block px-4 py-2 text-sm text-slate-400 hover:text-slate-100 hover:bg-slate-800 transition-colors"
|
||||
>
|
||||
{t.nav.docsItems.glossary}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user