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
+15
-14
@@ -7,6 +7,7 @@ import {
|
||||
ShieldCheckIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import { useLang } from '../context/LangContext'
|
||||
import { linkify } from '../lib/glossary'
|
||||
|
||||
const DRIVERS = [
|
||||
'Arista EOS', 'Cisco IOS', 'Cisco IOS-XE', 'Cisco NX-OS', 'Fritz!Box',
|
||||
@@ -290,7 +291,7 @@ export default function Home() {
|
||||
<span className="text-sky-400">{h.hero.line2}</span>
|
||||
</h1>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-2xl mx-auto mb-10">
|
||||
{h.hero.sub}
|
||||
{linkify(h.hero.sub)}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-4 justify-center">
|
||||
<a
|
||||
@@ -319,7 +320,7 @@ export default function Home() {
|
||||
{/* 2 — Problem Statement */}
|
||||
<section className="py-16">
|
||||
<div className="max-w-3xl mx-auto px-6 text-center">
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.problem}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{linkify(h.problem)}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -334,21 +335,21 @@ export default function Home() {
|
||||
<MagnifyingGlassIcon className="h-5 w-5 text-sky-400" />
|
||||
</div>
|
||||
<h3 className="mb-2 text-lg font-semibold text-slate-100">{h.cap1.title}</h3>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">{h.cap1.body}</p>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">{linkify(h.cap1.body)}</p>
|
||||
</div>
|
||||
<div className="rounded-xl border border-slate-800 bg-slate-900 p-6">
|
||||
<div className="mb-4 flex h-10 w-10 items-center justify-center rounded-lg bg-sky-600/10">
|
||||
<ChartBarIcon className="h-5 w-5 text-sky-400" />
|
||||
</div>
|
||||
<h3 className="mb-2 text-lg font-semibold text-slate-100">{h.cap2.title}</h3>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">{h.cap2.body}</p>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">{linkify(h.cap2.body)}</p>
|
||||
</div>
|
||||
<div className="rounded-xl border border-slate-800 bg-slate-900 p-6">
|
||||
<div className="mb-4 flex h-10 w-10 items-center justify-center rounded-lg bg-sky-600/10">
|
||||
<WrenchScrewdriverIcon className="h-5 w-5 text-sky-400" />
|
||||
</div>
|
||||
<h3 className="mb-2 text-lg font-semibold text-slate-100">{h.cap3.title}</h3>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">{h.cap3.body}</p>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">{linkify(h.cap3.body)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -360,7 +361,7 @@ export default function Home() {
|
||||
<section className="py-24">
|
||||
<div className="max-w-7xl mx-auto px-6 text-center">
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.driversHeading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-xl mx-auto mb-10">{h.driversSub}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-xl mx-auto mb-10">{linkify(h.driversSub)}</p>
|
||||
<div className="flex flex-wrap justify-center gap-3">
|
||||
{DRIVERS.map((d) => (
|
||||
<span key={d} className="inline-flex items-center gap-1.5 px-3 py-1 rounded-full border border-slate-700 bg-slate-900 text-xs font-medium text-slate-300">
|
||||
@@ -384,7 +385,7 @@ export default function Home() {
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.screenshot1.heading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.screenshot1.body}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{linkify(h.screenshot1.body)}</p>
|
||||
</div>
|
||||
<BrowserFrame label="netork.local / devices / ap-001">
|
||||
<MockDeviceDetail />
|
||||
@@ -396,13 +397,13 @@ export default function Home() {
|
||||
</BrowserFrame>
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.screenshot2.heading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.screenshot2.body}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{linkify(h.screenshot2.body)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.screenshot3.heading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.screenshot3.body}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{linkify(h.screenshot3.body)}</p>
|
||||
</div>
|
||||
<BrowserFrame label="netork.local / devices / ap-001 / security">
|
||||
<MockSecurity />
|
||||
@@ -414,7 +415,7 @@ export default function Home() {
|
||||
</BrowserFrame>
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.screenshot4.heading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.screenshot4.body}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{linkify(h.screenshot4.body)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -429,7 +430,7 @@ export default function Home() {
|
||||
<div>
|
||||
<p className="text-xs font-semibold tracking-widest uppercase text-sky-500 mb-3">{h.nis2Label}</p>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.nis2Heading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed mb-8">{h.nis2Body}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed mb-8">{linkify(h.nis2Body)}</p>
|
||||
<div className="mb-8">
|
||||
<Link to="/nis2" className="inline-flex items-center gap-2 text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium">
|
||||
<ShieldCheckIcon className="h-4 w-4" />
|
||||
@@ -442,7 +443,7 @@ export default function Home() {
|
||||
<span className="mt-0.5 shrink-0 w-28 text-xs font-mono text-sky-500">{m.art}</span>
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-200">{m.label}</p>
|
||||
<p className="text-xs text-slate-500 mt-0.5">{m.detail}</p>
|
||||
<p className="text-xs text-slate-500 mt-0.5">{linkify(m.detail)}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
@@ -465,7 +466,7 @@ export default function Home() {
|
||||
<PuzzlePieceIcon className="h-5 w-5 text-sky-400" />
|
||||
</div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.pluginsHeading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-2xl mb-6">{h.pluginsBody}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-2xl mb-6">{linkify(h.pluginsBody)}</p>
|
||||
<Link to="/plugins" className="text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium">
|
||||
{h.pluginsLink}
|
||||
</Link>
|
||||
@@ -481,7 +482,7 @@ export default function Home() {
|
||||
<div className="grid md:grid-cols-2 gap-12 items-start">
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.deployHeading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.deployBody}</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{linkify(h.deployBody)}</p>
|
||||
</div>
|
||||
<pre className="rounded-xl border border-slate-800 bg-slate-900 p-6 font-mono text-sm text-slate-300 overflow-x-auto">
|
||||
<code>{`# Clone + configure
|
||||
|
||||
Reference in New Issue
Block a user