feat: bilingual website (DE/EN) with language switcher
Add LangContext with localStorage persistence (default: DE). DE/EN toggle in Nav (top-right, before CTA button). All pages translated: - Home: all 8 sections incl. NIS2 block - Features: all 13 sections with full German bullet points - Drivers: headings and descriptions - Getting Started (coming soon) - Roadmap: bilingual data arrays inline (Planned + Under consideration) - NIS2: full Art. 21 mapping, evidence blocks, coming-soon list Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
f194c379e4
commit
d48c7143aa
+40
-114
@@ -6,6 +6,7 @@ import {
|
||||
PuzzlePieceIcon,
|
||||
ShieldCheckIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import { useLang } from '../context/LangContext'
|
||||
|
||||
const DRIVERS = [
|
||||
'Arista EOS', 'Cisco IOS', 'Cisco IOS-XE', 'Cisco NX-OS', 'Fritz!Box',
|
||||
@@ -243,32 +244,33 @@ function MockSecurity() {
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const { t } = useLang()
|
||||
const h = t.home
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 1 — Hero */}
|
||||
<section className="py-24 md:py-32">
|
||||
<div className="max-w-7xl mx-auto px-6 text-center">
|
||||
<h1 className="text-4xl md:text-6xl font-bold text-slate-100 leading-tight mb-6">
|
||||
Network orchestration<br />
|
||||
<span className="text-sky-400">for heterogeneous infrastructure.</span>
|
||||
{h.hero.line1}<br />
|
||||
<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">
|
||||
netOrk discovers, monitors, and manages your routers, switches, access points,
|
||||
firewalls, and servers from a single UI — regardless of vendor.
|
||||
No SaaS dependency. Runs on your infrastructure.
|
||||
{h.hero.sub}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-4 justify-center">
|
||||
<a
|
||||
href="mailto:christian@manivong.de"
|
||||
className="inline-flex items-center gap-2 px-6 py-3 rounded-lg bg-sky-600 hover:bg-sky-500 text-white font-medium transition-colors"
|
||||
>
|
||||
Get in touch →
|
||||
{h.hero.cta1}
|
||||
</a>
|
||||
<Link
|
||||
to="/features"
|
||||
className="inline-flex items-center gap-2 px-6 py-3 rounded-lg border border-slate-700 hover:border-slate-500 text-slate-300 hover:text-slate-100 transition-colors"
|
||||
>
|
||||
View features
|
||||
{h.hero.cta2}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -284,12 +286,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">
|
||||
Managing a mixed network means juggling a different admin UI for every vendor —
|
||||
one for OPNsense, one for HP ProCurve, one for OpenWRT, one for Proxmox.
|
||||
Config changes happen directly on devices with no audit trail.
|
||||
You find out something drifted when it breaks.
|
||||
</p>
|
||||
<p className="text-base text-slate-400 leading-relaxed">{h.problem}</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -303,34 +300,22 @@ export default function Home() {
|
||||
<div className="mb-4 flex h-10 w-10 items-center justify-center rounded-lg bg-sky-600/10">
|
||||
<MagnifyingGlassIcon className="h-5 w-5 text-sky-400" />
|
||||
</div>
|
||||
<h3 className="mb-2 text-lg font-semibold text-slate-100">Discover everything on your network</h3>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">
|
||||
ICMP sweep, SNMP scan, and HTTP probing find devices before you add them.
|
||||
Fingerprinting identifies vendor and platform automatically.
|
||||
Adopt results into your inventory with a single click.
|
||||
</p>
|
||||
<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>
|
||||
</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">Poll device state continuously</h3>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">
|
||||
Every device is polled on a configurable interval via NAPALM.
|
||||
Interface status, ARP tables, DHCP leases, VLAN membership,
|
||||
Docker containers, and SNMP health metrics — all in one place.
|
||||
</p>
|
||||
<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>
|
||||
</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">Detect drift. Fix it.</h3>
|
||||
<p className="text-sm text-slate-400 leading-relaxed">
|
||||
Define desired state in netOrk. On every poll, device config is compared against it.
|
||||
Drifted devices get a warning; a one-click fix stream applies the correction and
|
||||
shows you live SSH output.
|
||||
</p>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -341,24 +326,18 @@ export default function Home() {
|
||||
{/* 4 — Driver Grid */}
|
||||
<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">Works with your hardware</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-xl mx-auto mb-10">
|
||||
netOrk ships with custom NAPALM drivers for 11 device types, plus all built-in NAPALM drivers.
|
||||
New drivers follow a documented registration pattern.
|
||||
</p>
|
||||
<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>
|
||||
<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"
|
||||
>
|
||||
<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">
|
||||
{d}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<div className="mt-8">
|
||||
<Link to="/drivers" className="text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium">
|
||||
Full driver reference →
|
||||
{h.driversLink}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -369,44 +348,28 @@ export default function Home() {
|
||||
{/* 5 — Screenshot Walkthrough */}
|
||||
<section className="py-24">
|
||||
<div className="max-w-7xl mx-auto px-6 space-y-24">
|
||||
{/* Row 1 — left text, right screenshot */}
|
||||
<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">Device detail at a glance</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">
|
||||
Hostname, IP, vendor, OS version, last poll time, and active warnings on one card.
|
||||
Tabbed detail view for interfaces, LLDP neighbors, ARP table, VLAN membership,
|
||||
packages, services, and scheduled jobs.
|
||||
</p>
|
||||
<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>
|
||||
</div>
|
||||
<BrowserFrame label="netork.local / devices / ap-001">
|
||||
<MockDeviceDetail />
|
||||
</BrowserFrame>
|
||||
</div>
|
||||
|
||||
{/* Row 2 — right text, left screenshot */}
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center">
|
||||
<BrowserFrame label="netork.local / vlans">
|
||||
<MockVlans />
|
||||
</BrowserFrame>
|
||||
<div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">Intent-based VLAN and SSID management</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">
|
||||
Define VLAN names and SSID settings once. netOrk compares them against every polled
|
||||
device and pushes corrections automatically via UCI (OpenWRT) or the device's native API.
|
||||
</p>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Row 3 — left text, right screenshot */}
|
||||
<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">Security visibility per device</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">
|
||||
Wazuh agent status, CVE counts by severity, and recent alerts — all linked to the device
|
||||
record. One-click agent install if the agent is missing.
|
||||
Graylog syslog forwarding status with auto-fix.
|
||||
</p>
|
||||
<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>
|
||||
</div>
|
||||
<BrowserFrame label="netork.local / devices / ap-001 / security">
|
||||
<MockSecurity />
|
||||
@@ -422,44 +385,17 @@ export default function Home() {
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<div className="grid md:grid-cols-2 gap-12 items-center">
|
||||
<div>
|
||||
<p className="text-xs font-semibold tracking-widest uppercase text-sky-500 mb-3">NIS2 · Art. 21</p>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">
|
||||
Evidence, not paperwork.
|
||||
</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed mb-8">
|
||||
NIS2 Art. 21 mandates asset inventory, patch management, access
|
||||
control, and audit trails as baseline technical measures. netOrk
|
||||
doesn't bolt on a compliance layer — these are its day-to-day outputs.
|
||||
</p>
|
||||
<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>
|
||||
<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" />
|
||||
Full Art. 21 mapping →
|
||||
{h.nis2Link}
|
||||
</Link>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{
|
||||
art: 'Art. 21 (2e)',
|
||||
label: 'Patch & vulnerability management',
|
||||
detail: 'Per-device update status, Wazuh CVE counts by severity',
|
||||
},
|
||||
{
|
||||
art: 'Art. 21 (2h)',
|
||||
label: 'Asset management & access control',
|
||||
detail: 'Full device inventory, RBAC with four roles, complete audit log',
|
||||
},
|
||||
{
|
||||
art: 'Art. 21 (2a)',
|
||||
label: 'Risk analysis baseline',
|
||||
detail: 'Config drift detection, SNMP health metrics, security agent coverage',
|
||||
},
|
||||
{
|
||||
art: 'Art. 21 (2b)',
|
||||
label: 'Incident detection',
|
||||
detail: 'Wazuh alert history, CrowdSec decisions, Graylog syslog per device',
|
||||
},
|
||||
].map((m) => (
|
||||
{h.nis2Items.map((m) => (
|
||||
<div key={m.art} className="flex gap-4">
|
||||
<span className="mt-0.5 shrink-0 w-28 text-xs font-mono text-sky-500">{m.art}</span>
|
||||
<div>
|
||||
@@ -486,15 +422,10 @@ export default function Home() {
|
||||
<div className="mb-4 flex h-10 w-10 items-center justify-center rounded-lg bg-sky-600/10">
|
||||
<PuzzlePieceIcon className="h-5 w-5 text-sky-400" />
|
||||
</div>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">Built to extend</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-2xl mb-6">
|
||||
Integrations (Wazuh, Graylog, CrowdSec, apt-cacher-ng) are plugins that register into
|
||||
the plugin system — they can be enabled or disabled per deployment without code changes.
|
||||
Adding a new integration follows a documented pattern with a hook bus, typed metadata,
|
||||
and a plugin registry.
|
||||
</p>
|
||||
<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>
|
||||
<Link to="/plugins" className="text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium">
|
||||
Plugin system docs →
|
||||
{h.pluginsLink}
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
@@ -507,11 +438,8 @@ export default function Home() {
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<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">Self-hosted. One command.</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed">
|
||||
netOrk runs in Docker Compose. Five containers: API, two worker pools, a Beat scheduler,
|
||||
and an nginx UI server. No external dependencies beyond Redis and PostgreSQL.
|
||||
</p>
|
||||
<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>
|
||||
</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
|
||||
@@ -528,18 +456,16 @@ bash scripts/deploy.sh 192.168.1.10`}</code>
|
||||
|
||||
<div className="border-t border-slate-800" />
|
||||
|
||||
{/* 8 — CTA Footer */}
|
||||
{/* 8 — CTA */}
|
||||
<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">Interested?</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed mb-8">
|
||||
Deployment options and hosted plans are coming. Get in touch for early access.
|
||||
</p>
|
||||
<h2 className="text-2xl md:text-3xl font-bold text-slate-100 mb-4">{h.ctaHeading}</h2>
|
||||
<p className="text-base text-slate-400 leading-relaxed mb-8">{h.ctaBody}</p>
|
||||
<a
|
||||
href="mailto:christian@manivong.de"
|
||||
className="inline-flex items-center gap-2 px-6 py-3 rounded-lg bg-sky-600 hover:bg-sky-500 text-white font-medium transition-colors"
|
||||
>
|
||||
Get in touch →
|
||||
{h.ctaButton}
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user