feat: initial website implementation
CI / TypeScript — type-check (push) Successful in 8s
CI / Publish — build & push image (push) Successful in 11s
CI / Deploy — pull & restart on host (push) Failing after 3s

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:
Christian Manivong
2026-06-28 10:19:50 +02:00
co-authored by Claude Sonnet 4.6
parent 00c483c2a2
commit efa01b5f41
26 changed files with 4118 additions and 1 deletions
+138
View File
@@ -0,0 +1,138 @@
import { Link } from 'react-router-dom'
function CodeBlock({ code }: { code: string }) {
return (
<pre className="rounded-xl border border-slate-800 bg-slate-900 p-6 font-mono text-sm text-slate-300 overflow-x-auto">
<code>{code}</code>
</pre>
)
}
function Step({ n, title, children }: { n: number; title: string; children: React.ReactNode }) {
return (
<div className="flex gap-6">
<div className="shrink-0 flex h-8 w-8 items-center justify-center rounded-full bg-sky-600/20 text-sky-400 text-sm font-semibold">
{n}
</div>
<div className="flex-1 pb-10">
<h2 className="text-xl font-semibold text-slate-200 mb-4">{title}</h2>
{children}
</div>
</div>
)
}
export default function GettingStarted() {
return (
<div className="py-16 md:py-24">
<div className="max-w-3xl mx-auto px-6">
<div className="mb-12">
<p className="text-sm font-medium text-sky-400 mb-2">Documentation</p>
<h1 className="text-4xl md:text-5xl font-bold text-slate-100 mb-4">Getting Started</h1>
<p className="text-base text-slate-400 leading-relaxed">
Get netOrk running from zero to a managed device in under 10 minutes.
</p>
</div>
<div className="border-t border-slate-800 pt-10">
<Step n={1} title="Prerequisites">
<ul className="space-y-2 mb-0">
{[
'Docker + Docker Compose (v2)',
'A Linux host reachable from the server by SSH',
'PostgreSQL (or use the bundled Compose profile)',
'Redis (or use the bundled Compose profile)',
].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}
</li>
))}
</ul>
</Step>
<Step n={2} title="Quick start">
<p className="text-sm text-slate-400 mb-4">
Clone the repository, copy the example environment file, and deploy with a single command.
</p>
<CodeBlock code={`git clone https://gitea.example.com/netork/netork.git
cd netork
cp .env.example .env
# Edit .env — set DB_URL, REDIS_URL, SECRET_KEY
bash scripts/deploy.sh 192.168.1.10`} />
<p className="mt-4 text-sm text-slate-400">
The deploy script builds images, pushes them to the target host, and starts Docker Compose.
Alembic migrations run automatically on first start.
</p>
</Step>
<Step n={3} title="First run">
<p className="text-sm text-slate-400 mb-4">
Once the containers are up, navigate to your server IP in a browser.
</p>
<CodeBlock code={`http://192.168.1.10`} />
<ul className="mt-4 space-y-2">
{[
'Complete the setup wizard — it creates the admin user and writes the initial config',
'Log in with the admin credentials you just set',
'You land on the device inventory — currently empty',
].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}
</li>
))}
</ul>
</Step>
<Step n={4} title="Adding your first device">
<ol className="space-y-3">
{[
'Click "Add device" and fill in hostname / IP, driver, and credentials',
'Click "Poll" to verify connectivity — you should see facts populate (vendor, OS, model)',
'Set a poll interval (e.g. 5 minutes) for continuous monitoring',
'Save — the device is now active and polled on the configured schedule',
].map((item, i) => (
<li key={i} className="flex items-start gap-3 text-sm text-slate-400">
<span className="shrink-0 text-xs font-mono text-sky-400 mt-0.5">{i + 1}.</span>
{item}
</li>
))}
</ol>
</Step>
<Step n={5} title="Next steps">
<div className="grid sm:grid-cols-3 gap-4">
{[
{ heading: 'NetBox sync', body: 'Connect netOrk to your NetBox instance to keep device records in sync automatically.' },
{ heading: 'Wazuh', body: 'Enable the Wazuh plugin to track agent enrollment and CVE counts per device.' },
{ heading: 'Scheduled reboots', body: 'Configure scheduled AP reboots for OpenWRT devices (GTK key rotation workaround).' },
].map((card) => (
<div key={card.heading} className="rounded-xl border border-slate-800 bg-slate-900 p-4">
<h3 className="text-sm font-semibold text-slate-100 mb-2">{card.heading}</h3>
<p className="text-xs text-slate-400 leading-relaxed">{card.body}</p>
</div>
))}
</div>
</Step>
</div>
<div className="border-t border-slate-800 pt-8 flex gap-4">
<Link
to="/drivers"
className="text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium"
>
Supported drivers →
</Link>
<Link
to="/features"
className="text-sky-400 hover:text-sky-300 transition-colors text-sm font-medium"
>
Full feature list →
</Link>
</div>
</div>
</div>
)
}