mirror of
https://github.com/DevVoxel/VectorDNS.git
synced 2026-02-27 05:47:38 +00:00
Roadmap Added
This commit is contained in:
@@ -50,6 +50,12 @@ export default function Home() {
|
|||||||
>
|
>
|
||||||
Docs
|
Docs
|
||||||
</Link>
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/roadmap"
|
||||||
|
className="text-sm text-muted-foreground transition-colors hover:text-foreground"
|
||||||
|
>
|
||||||
|
Roadmap
|
||||||
|
</Link>
|
||||||
<ThemeToggle />
|
<ThemeToggle />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
114
app/roadmap/page.tsx
Normal file
114
app/roadmap/page.tsx
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { Globe, Map, Info } from "lucide-react";
|
||||||
|
import { ThemeToggle } from "@/components/theme-toggle";
|
||||||
|
import { RoadmapFlowchart } from "@/components/roadmap-flowchart";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
CardDescription,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Roadmap",
|
||||||
|
description: "Visual roadmap and development phases for VectorDNS.",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RoadmapPage() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen flex-col">
|
||||||
|
{/* Header */}
|
||||||
|
<header className="border-b bg-background/95 backdrop-blur supports-backdrop-filter:bg-background/60 sticky top-0 z-50">
|
||||||
|
<div className="container mx-auto flex h-14 items-center justify-between px-4">
|
||||||
|
<Link href="/" className="flex items-center gap-2">
|
||||||
|
<Globe className="size-5 text-primary" />
|
||||||
|
<span className="text-lg font-semibold tracking-tight">
|
||||||
|
VectorDNS
|
||||||
|
</span>
|
||||||
|
</Link>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<Link
|
||||||
|
href="/docs"
|
||||||
|
className="text-sm text-muted-foreground transition-colors hover:text-foreground"
|
||||||
|
>
|
||||||
|
Docs
|
||||||
|
</Link>
|
||||||
|
<Link
|
||||||
|
href="/roadmap"
|
||||||
|
className="text-sm font-medium text-foreground transition-colors"
|
||||||
|
>
|
||||||
|
Roadmap
|
||||||
|
</Link>
|
||||||
|
<ThemeToggle />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<main className="flex-1">
|
||||||
|
<div className="container mx-auto px-4 py-12">
|
||||||
|
{/* Page Header */}
|
||||||
|
<div className="mb-12 flex flex-col items-center text-center gap-4">
|
||||||
|
<Badge
|
||||||
|
variant="outline"
|
||||||
|
className="px-3 py-1 gap-1.5 border-primary/20 bg-primary/5 text-primary"
|
||||||
|
>
|
||||||
|
<Map className="size-3.5" />
|
||||||
|
Project Roadmap
|
||||||
|
</Badge>
|
||||||
|
<h1 className="text-4xl font-extrabold tracking-tight lg:text-5xl">
|
||||||
|
Building the Future of{" "}
|
||||||
|
<span className="text-primary">DNS Monitoring</span>
|
||||||
|
</h1>
|
||||||
|
<p className="max-w-2xl text-lg text-muted-foreground">
|
||||||
|
Follow our journey from foundation to a full-featured domain
|
||||||
|
toolkit. Drag, zoom, and explore the development phases below.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Interactive Flowchart */}
|
||||||
|
<div className="mb-12">
|
||||||
|
<RoadmapFlowchart />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Additional Context Cards */}
|
||||||
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
<Card className="border-primary/10 bg-primary/5">
|
||||||
|
<CardHeader>
|
||||||
|
<div className="flex items-center gap-2 text-primary mb-1">
|
||||||
|
<Info className="size-5" />
|
||||||
|
<CardTitle className="text-lg">Project Philosophy</CardTitle>
|
||||||
|
</div>
|
||||||
|
<CardDescription>
|
||||||
|
VectorDNS is built on three core pillars: speed, accuracy, and
|
||||||
|
transparency. Every phase of our roadmap is designed to ensure
|
||||||
|
the highest quality data while maintaining a modern,
|
||||||
|
user-friendly experience.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-lg">Contributing</CardTitle>
|
||||||
|
<CardDescription>
|
||||||
|
We are currently in the early development stages. If
|
||||||
|
you're interested in contributing to the Go DNS API or
|
||||||
|
the Next.js frontend, please check out our GitHub repository
|
||||||
|
and open an issue or PR.
|
||||||
|
</CardDescription>
|
||||||
|
</CardHeader>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
{/* Footer */}
|
||||||
|
<footer className="border-t py-6">
|
||||||
|
<div className="container mx-auto px-4 text-center text-sm text-muted-foreground">
|
||||||
|
<p>© {new Date().getFullYear()} VectorDNS</p>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { usePathname } from "next/navigation";
|
import { usePathname } from "next/navigation";
|
||||||
import {
|
import {
|
||||||
|
SquareKanban,
|
||||||
BookOpen,
|
BookOpen,
|
||||||
Layers,
|
Layers,
|
||||||
ArrowRightLeft,
|
ArrowRightLeft,
|
||||||
@@ -13,6 +14,10 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
|
||||||
const sections = [
|
const sections = [
|
||||||
|
{
|
||||||
|
title: "Roadmap",
|
||||||
|
items: [{ title: "Project Roadmap", href: "/roadmap", icon: SquareKanban }],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: "Getting Started",
|
title: "Getting Started",
|
||||||
items: [{ title: "Overview", href: "/docs", icon: BookOpen }],
|
items: [{ title: "Overview", href: "/docs", icon: BookOpen }],
|
||||||
|
|||||||
309
components/roadmap-flowchart.tsx
Normal file
309
components/roadmap-flowchart.tsx
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ReactFlow,
|
||||||
|
Background,
|
||||||
|
type Node,
|
||||||
|
type Edge,
|
||||||
|
type NodeProps,
|
||||||
|
Handle,
|
||||||
|
Position,
|
||||||
|
MarkerType,
|
||||||
|
} from "@xyflow/react";
|
||||||
|
import "@xyflow/react/dist/style.css";
|
||||||
|
import {
|
||||||
|
CheckCircle2,
|
||||||
|
Circle,
|
||||||
|
Flag,
|
||||||
|
Rocket,
|
||||||
|
Settings,
|
||||||
|
ShieldCheck,
|
||||||
|
Database,
|
||||||
|
Layout,
|
||||||
|
Activity,
|
||||||
|
TestTube,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
type PhaseNodeData = {
|
||||||
|
label: string;
|
||||||
|
status: "todo" | "doing" | "done";
|
||||||
|
icon: React.ElementType;
|
||||||
|
color: string;
|
||||||
|
items: { text: string; completed: boolean }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function PhaseNode({ data }: NodeProps<Node<PhaseNodeData>>) {
|
||||||
|
const Icon = data.icon;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="rounded-xl border bg-card p-6 shadow-lg transition-all hover:border-primary/50"
|
||||||
|
style={{ minWidth: 320 }}
|
||||||
|
>
|
||||||
|
<Handle type="target" position={Position.Top} className="opacity-0" />
|
||||||
|
<Handle type="source" position={Position.Bottom} className="opacity-0" />
|
||||||
|
|
||||||
|
<div className="flex items-center gap-4 border-b pb-4 mb-4">
|
||||||
|
<div
|
||||||
|
className="flex size-12 items-center justify-center rounded-lg"
|
||||||
|
style={{ backgroundColor: data.color }}
|
||||||
|
>
|
||||||
|
<Icon className="size-6 text-white" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-lg font-bold text-foreground leading-tight">
|
||||||
|
{data.label}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={`text-xs font-semibold uppercase tracking-wider mt-0.5 ${
|
||||||
|
data.status === "done"
|
||||||
|
? "text-green-500"
|
||||||
|
: data.status === "doing"
|
||||||
|
? "text-blue-500"
|
||||||
|
: "text-muted-foreground"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{data.status}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="space-y-3">
|
||||||
|
{data.items.map((item, i) => (
|
||||||
|
<li
|
||||||
|
key={i}
|
||||||
|
className="flex items-start gap-3 text-sm leading-relaxed text-muted-foreground"
|
||||||
|
>
|
||||||
|
{item.completed ? (
|
||||||
|
<CheckCircle2 className="mt-0.5 size-4 shrink-0 text-green-500" />
|
||||||
|
) : (
|
||||||
|
<Circle className="mt-0.5 size-4 shrink-0 text-muted-foreground/40" />
|
||||||
|
)}
|
||||||
|
<span className={item.completed ? "line-through opacity-50" : ""}>
|
||||||
|
{item.text}
|
||||||
|
</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeTypes = { phase: PhaseNode };
|
||||||
|
|
||||||
|
const nodes: Node<PhaseNodeData>[] = [
|
||||||
|
{
|
||||||
|
id: "p1",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 1 — Foundation",
|
||||||
|
status: "todo",
|
||||||
|
icon: Database,
|
||||||
|
color: "#6366f1",
|
||||||
|
items: [
|
||||||
|
{ text: "TypeScript types", completed: false },
|
||||||
|
{ text: "Supabase schema & migrations", completed: false },
|
||||||
|
{ text: "Supabase client setup (@supabase/ssr)", completed: false },
|
||||||
|
{ text: "Project config & env setup", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p2",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 400, y: 0 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 2 — Core Services",
|
||||||
|
status: "todo",
|
||||||
|
icon: Settings,
|
||||||
|
color: "#8b5cf6",
|
||||||
|
items: [
|
||||||
|
{ text: "DNS service (tangerine)", completed: false },
|
||||||
|
{ text: "WHOIS service (whoiser)", completed: false },
|
||||||
|
{ text: "Availability service (IANA RDAP)", completed: false },
|
||||||
|
{ text: "Public lookup APIs", completed: false },
|
||||||
|
{ text: "Integration tests", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p3",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 800, y: 0 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 3 — Authentication",
|
||||||
|
status: "todo",
|
||||||
|
icon: ShieldCheck,
|
||||||
|
color: "#ec4899",
|
||||||
|
items: [
|
||||||
|
{ text: "Supabase Auth (GitHub, Google, Email)", completed: false },
|
||||||
|
{ text: "Auth server actions", completed: false },
|
||||||
|
{ text: "OAuth callback route", completed: false },
|
||||||
|
{ text: "Middleware protection", completed: false },
|
||||||
|
{ text: "Login/signup pages", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p4",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 0, y: 450 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 4 — Public UI",
|
||||||
|
status: "doing",
|
||||||
|
icon: Layout,
|
||||||
|
color: "#3b82f6",
|
||||||
|
items: [
|
||||||
|
{ text: "App shell layout", completed: false },
|
||||||
|
{ text: "Homepage Hero & Search", completed: true },
|
||||||
|
{ text: "DNS results page", completed: false },
|
||||||
|
{ text: "Save to Dashboard button", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p5",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 400, y: 450 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 5 — Dashboard",
|
||||||
|
status: "todo",
|
||||||
|
icon: Rocket,
|
||||||
|
color: "#06b6d4",
|
||||||
|
items: [
|
||||||
|
{ text: "Dashboard layout & stats", completed: false },
|
||||||
|
{ text: "Saved domains CRUD", completed: false },
|
||||||
|
{ text: "Domain detail page & history", completed: false },
|
||||||
|
{ text: "Notes & tags (auto-save)", completed: false },
|
||||||
|
{ text: "Manual re-check triggers", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p6",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 800, y: 450 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 6 — Monitoring & Alerts",
|
||||||
|
status: "todo",
|
||||||
|
icon: Activity,
|
||||||
|
color: "#10b981",
|
||||||
|
items: [
|
||||||
|
{ text: "Change detection logic", completed: false },
|
||||||
|
{ text: "Vercel Daily Cron job", completed: false },
|
||||||
|
{ text: "In-app notification system", completed: false },
|
||||||
|
{ text: "Email alerts via Resend", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p7",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 200, y: 900 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 7 — Settings & Polish",
|
||||||
|
status: "todo",
|
||||||
|
icon: Flag,
|
||||||
|
color: "#f59e0b",
|
||||||
|
items: [
|
||||||
|
{ text: "User profile & preferences", completed: false },
|
||||||
|
{ text: "Error boundaries & 404s", completed: false },
|
||||||
|
{ text: "Toast notifications (sonner)", completed: false },
|
||||||
|
{ text: "SEO & OG image generation", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "p8",
|
||||||
|
type: "phase",
|
||||||
|
position: { x: 600, y: 900 },
|
||||||
|
data: {
|
||||||
|
label: "Phase 8 — Testing & QA",
|
||||||
|
status: "todo",
|
||||||
|
icon: TestTube,
|
||||||
|
color: "#64748b",
|
||||||
|
items: [
|
||||||
|
{ text: "End-to-end integration tests", completed: false },
|
||||||
|
{ text: "Build verification (zero TS errors)", completed: false },
|
||||||
|
{ text: "Manual QA pass (Light/Dark mode)", completed: false },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const edges: Edge[] = [
|
||||||
|
{
|
||||||
|
id: "e1-2",
|
||||||
|
source: "p1",
|
||||||
|
target: "p2",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e2-3",
|
||||||
|
source: "p2",
|
||||||
|
target: "p3",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e3-4",
|
||||||
|
source: "p3",
|
||||||
|
target: "p4",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8", strokeWidth: 2 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e4-5",
|
||||||
|
source: "p4",
|
||||||
|
target: "p5",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e5-6",
|
||||||
|
source: "p5",
|
||||||
|
target: "p6",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e6-7",
|
||||||
|
source: "p6",
|
||||||
|
target: "p7",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8", strokeWidth: 2 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "e7-8",
|
||||||
|
source: "p7",
|
||||||
|
target: "p8",
|
||||||
|
markerEnd: { type: MarkerType.ArrowClosed, color: "#94a3b8" },
|
||||||
|
style: { stroke: "#94a3b8" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function RoadmapFlowchart() {
|
||||||
|
return (
|
||||||
|
<div className="h-275 w-full rounded-2xl border bg-muted/30 backdrop-blur-sm shadow-inner">
|
||||||
|
<ReactFlow
|
||||||
|
nodes={nodes}
|
||||||
|
edges={edges}
|
||||||
|
nodeTypes={nodeTypes}
|
||||||
|
fitView
|
||||||
|
fitViewOptions={{ padding: 0.1 }}
|
||||||
|
proOptions={{ hideAttribution: true }}
|
||||||
|
nodesDraggable={false}
|
||||||
|
nodesConnectable={false}
|
||||||
|
elementsSelectable={false}
|
||||||
|
panOnDrag={false}
|
||||||
|
zoomOnScroll={false}
|
||||||
|
zoomOnPinch={false}
|
||||||
|
zoomOnDoubleClick={false}
|
||||||
|
preventScrolling={false}
|
||||||
|
>
|
||||||
|
<Background gap={32} size={1} className="opacity-15" />
|
||||||
|
</ReactFlow>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user