feat: initial website implementation
React 18 + TypeScript + Vite + Tailwind CSS website for netOrk. Built by a parallel instance based on the product docs. Pages: Home (landing), Features, Drivers, Getting Started Components: Nav, Footer Assets: public/logo.png (1024x1024 RGBA) Docker: multi-stage Dockerfile (node:20 builder + nginx:alpine) Compose: netork-website service on proxy-net (Zoraxy integration) docs/DESIGN.md: Logo Assets section added (PNG only, SVG removed); wordmark pattern and <head> references documented. .gitignore: fixed (was literal \n, now proper newlines); excludes node_modules/, dist/, memory/. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
00c483c2a2
commit
efa01b5f41
@@ -0,0 +1,133 @@
|
||||
type Cap = '✓' | '—'
|
||||
|
||||
interface Driver {
|
||||
name: string
|
||||
deviceType: string
|
||||
facts: Cap
|
||||
interfaces: Cap
|
||||
lldp: Cap
|
||||
vlans: Cap
|
||||
ssids: Cap
|
||||
health: Cap
|
||||
docker: Cap
|
||||
reboot: Cap
|
||||
configPush: Cap
|
||||
status: 'stable' | 'beta'
|
||||
}
|
||||
|
||||
const DRIVERS: Driver[] = [
|
||||
{ name: 'openwrt', deviceType: 'OpenWRT access points', facts: '✓', interfaces: '✓', lldp: '—', vlans: '✓', ssids: '✓', health: '✓', docker: '—', reboot: '✓', configPush: '✓', status: 'stable' },
|
||||
{ name: 'opnsense', deviceType: 'OPNsense firewalls', facts: '✓', interfaces: '✓', lldp: '✓', vlans: '✓', ssids: '—', health: '✓', docker: '—', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'proxmox', deviceType: 'Proxmox VE hypervisors', facts: '✓', interfaces: '✓', lldp: '—', vlans: '—', ssids: '—', health: '✓', docker: '✓', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'linux', deviceType: 'Generic Linux servers', facts: '✓', interfaces: '✓', lldp: '✓', vlans: '—', ssids: '—', health: '✓', docker: '✓', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'procurve', deviceType: 'HP ProCurve / Aruba switches', facts: '✓', interfaces: '✓', lldp: '✓', vlans: '✓', ssids: '—', health: '✓', docker: '—', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'tplink_jetstream', deviceType: 'TP-Link Jetstream switches', facts: '✓', interfaces: '✓', lldp: '✓', vlans: '✓', ssids: '—', health: '—', docker: '—', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'netgear', deviceType: 'Netgear switches', facts: '✓', interfaces: '✓', lldp: '✓', vlans: '✓', ssids: '—', health: '—', docker: '—', reboot: '—', configPush: '—', status: 'beta' },
|
||||
{ name: 'fritzbox', deviceType: 'AVM Fritz!Box routers', facts: '✓', interfaces: '✓', lldp: '—', vlans: '—', ssids: '✓', health: '—', docker: '—', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'zyxel', deviceType: 'Zyxel switches', facts: '✓', interfaces: '✓', lldp: '✓', vlans: '✓', ssids: '—', health: '—', docker: '—', reboot: '—', configPush: '—', status: 'beta' },
|
||||
{ name: 'openmediavault', deviceType: 'OpenMediaVault NAS', facts: '✓', interfaces: '✓', lldp: '—', vlans: '—', ssids: '—', health: '✓', docker: '✓', reboot: '✓', configPush: '—', status: 'stable' },
|
||||
{ name: 'sonos', deviceType: 'Sonos speakers', facts: '✓', interfaces: '—', lldp: '—', vlans: '—', ssids: '—', health: '—', docker: '—', reboot: '—', configPush: '—', status: 'beta' },
|
||||
]
|
||||
|
||||
const NAPALM_BUILTIN = [
|
||||
'Cisco IOS',
|
||||
'Cisco IOS-XE',
|
||||
'Cisco NX-OS',
|
||||
'Arista EOS',
|
||||
'Juniper JunOS',
|
||||
]
|
||||
|
||||
const CAPS: { key: keyof Driver; label: string }[] = [
|
||||
{ key: 'facts', label: 'Facts' },
|
||||
{ key: 'interfaces', label: 'Ifaces' },
|
||||
{ key: 'lldp', label: 'LLDP' },
|
||||
{ key: 'vlans', label: 'VLANs' },
|
||||
{ key: 'ssids', label: 'SSIDs' },
|
||||
{ key: 'health', label: 'Health' },
|
||||
{ key: 'docker', label: 'Docker' },
|
||||
{ key: 'reboot', label: 'Reboot' },
|
||||
{ key: 'configPush', label: 'Config push' },
|
||||
]
|
||||
|
||||
function StatusBadge({ status }: { status: 'stable' | 'beta' }) {
|
||||
return (
|
||||
<span className={`text-xs font-medium px-2 py-0.5 rounded-full ${
|
||||
status === 'stable'
|
||||
? 'bg-green-500/20 text-green-400'
|
||||
: 'bg-yellow-500/20 text-yellow-400'
|
||||
}`}>
|
||||
{status}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default function Drivers() {
|
||||
return (
|
||||
<div className="py-16 md:py-24">
|
||||
<div className="max-w-7xl mx-auto px-6">
|
||||
<div className="mb-12">
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-slate-100 mb-4">Supported Devices</h1>
|
||||
<p className="text-base text-slate-400 leading-relaxed max-w-xl">
|
||||
netOrk ships with custom NAPALM drivers for 11 device types and supports all built-in NAPALM
|
||||
drivers. Capability availability varies by driver.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Custom drivers table */}
|
||||
<div className="mb-16 overflow-x-auto">
|
||||
<h2 className="text-xl font-semibold text-slate-200 mb-4">Custom Drivers</h2>
|
||||
<div className="rounded-xl border border-slate-800 overflow-hidden">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b border-slate-800 bg-slate-900">
|
||||
<th className="px-4 py-3 text-left font-medium text-slate-500">Driver</th>
|
||||
<th className="px-4 py-3 text-left font-medium text-slate-500">Device type</th>
|
||||
{CAPS.map((c) => (
|
||||
<th key={c.key} className="px-3 py-3 text-center font-medium text-slate-500 whitespace-nowrap">
|
||||
{c.label}
|
||||
</th>
|
||||
))}
|
||||
<th className="px-4 py-3 text-left font-medium text-slate-500">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{DRIVERS.map((d) => (
|
||||
<tr key={d.name} className="border-b border-slate-800 last:border-0 hover:bg-slate-800/40 transition-colors">
|
||||
<td className="px-4 py-3 font-mono text-sky-400 whitespace-nowrap">{d.name}</td>
|
||||
<td className="px-4 py-3 text-slate-300 whitespace-nowrap">{d.deviceType}</td>
|
||||
{CAPS.map((c) => (
|
||||
<td key={c.key} className="px-3 py-3 text-center">
|
||||
<span className={d[c.key] === '✓' ? 'text-green-400' : 'text-slate-700'}>
|
||||
{d[c.key]}
|
||||
</span>
|
||||
</td>
|
||||
))}
|
||||
<td className="px-4 py-3"><StatusBadge status={d.status} /></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* NAPALM built-ins */}
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-slate-200 mb-4">Built-in NAPALM Drivers</h2>
|
||||
<p className="text-sm text-slate-400 mb-6">
|
||||
All standard NAPALM drivers are supported. Capabilities depend on the upstream NAPALM implementation.
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{NAPALM_BUILTIN.map((name) => (
|
||||
<span
|
||||
key={name}
|
||||
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"
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user