Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions web/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.node_modules
.env
dist
.cache
.DS_Store
/node_modules
/build
/.next
5 changes: 5 additions & 0 deletions web/next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
8 changes: 5 additions & 3 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
"start": "next start -p $PORT"
},
"dependencies": {
"@monaco-editor/react": "^4.4.3",
"next": "14.0.0",
"react": "18.2.0",
"react-dom": "18.2.0",
"@monaco-editor/react": "^5.0.1"
"react-dom": "18.2.0"
},
"devDependencies": {
"typescript": "5.5.0"
"@types/node": "25.1.0",
"@types/react": "19.2.10",
"typescript": "^5.4.4"
}
}
93 changes: 62 additions & 31 deletions web/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,68 @@
import React from 'react'
import type { GetServerSideProps } from 'next'
import Head from 'next/head'
import Image from 'next/image'
import Link from 'next/link'
import '../styles/landing.css'

type Props = {
collections: string[]
error?: string
}
export default function Landing() {
return (
<div className="landing-root">
<header className="hero">
<div className="hero-inner">
<div className="hero-copy">
<h1>Nexus — Terminal-first API toolkit</h1>
<p className="tagline">Build, test, mock and collaborate on APIs — fast, Git-native, and privacy-first.</p>

export default function Home({ collections, error }: Props) {
if (error) return <div>Error: {error}</div>
<div className="cta">
<a className="btn primary" href="/collections">Open the app</a>
<a className="btn ghost" href="https://github.com/ayushedith/nexus" target="_blank" rel="noreferrer">Star on GitHub</a>
</div>
</div>

return (
<main style={{ padding: 24, fontFamily: 'Inter, system-ui' }}>
<h1>Nexus — Collections</h1>
<p>Collections stored in repository</p>
<ul>
{collections.map((c) => (
<li key={c}>{c}</li>
))}
</ul>
</main>
)
}
<div className="hero-image">
<Image src="/assets/nexus.jpg" alt="Nexus" width={420} height={300} />
</div>
</div>
</header>

<Head>
<title>Nexus — API Collections Runner</title>
<meta name="description" content="Run, test and mock APIs locally — with collaboration and AI helpers." />
<link rel="icon" href="/favicon.ico" />
</Head>

export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const backend = process.env.BACKEND_URL || 'http://localhost:8080'
try {
const res = await fetch(`${backend}/api/collections`)
if (!res.ok) {
return { props: { collections: [], error: `backend responded ${res.status}` } }
}
const data = await res.json()
return { props: { collections: data.collections || [] } }
} catch (err: any) {
return { props: { collections: [], error: err.message } }
}
<section className="features">
<div className="container">
<h2>What it does</h2>
<div className="grid">
<div className="card">
<h3>Terminal-first TUI</h3>
<p>Interactive Bubbletea-based UI for building and running collections with keyboard-friendly controls.</p>
</div>

<div className="card">
<h3>Git-native storage</h3>
<p>Store collections as files in your repo, with commits and history for reproducible tests.</p>
</div>

<div className="card">
<h3>Mock & Load</h3>
<p>Run a mock server for integration tests and basic load testing out of the box.</p>
</div>

<div className="card">
<h3>AI helpers</h3>
<p>Generate request bodies and test assertions using pluggable AI adapters.</p>
</div>
</div>
</div>
</section>

<footer className="site-footer">
<div className="container">
<div>Made with ❤️ — <a href="https://github.com/ayushedith/nexus" target="_blank" rel="noreferrer">ayushedith/nexus</a></div>
</div>
</footer>
</div>
)
}
34 changes: 34 additions & 0 deletions web/styles/landing.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
:root{
--bg:#0f1724;
--card:#0b1220;
--muted:#94a3b8;
--accent:#7c3aed;
}

.landing-root{font-family:Inter,ui-sans-serif,system-ui, -apple-system, 'Segoe UI', Roboto; color:#e6eef6; background: linear-gradient(180deg, #071025 0%, #071629 60%); min-height:100vh}
.container{max-width:1100px;margin:0 auto;padding:40px 20px}

.hero{padding:80px 0}
.hero-inner{display:flex;gap:48px;align-items:center;justify-content:space-between}
.hero-copy h1{font-size:48px;margin:0 0 12px}
.tagline{color:var(--muted);margin:0 0 20px}
.cta{display:flex;gap:12px}
.btn{padding:10px 16px;border-radius:8px;text-decoration:none;color:inherit;border:1px solid rgba(255,255,255,0.06)}
.btn.primary{background:linear-gradient(90deg,var(--accent),#5b21b6);box-shadow:0 6px 18px rgba(124,58,237,0.18)}
.btn.ghost{background:transparent;border:1px solid rgba(255,255,255,0.06)}

.hero-image img{max-width:420px;border-radius:12px;box-shadow:0 10px 30px rgba(2,6,23,0.6)}

.features{padding:48px 0;background:linear-gradient(180deg, transparent 0%, rgba(255,255,255,0.02) 100%)}
.features h2{color:#dbeafe;margin-bottom:18px}
.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
.card{background:rgba(255,255,255,0.02);padding:18px;border-radius:10px;border:1px solid rgba(255,255,255,0.02)}
.card h3{margin:0 0 8px}
.card p{margin:0;color:var(--muted)}

.site-footer{padding:28px 0;color:var(--muted);border-top:1px solid rgba(255,255,255,0.02)}

@media (max-width:900px){
.hero-inner{flex-direction:column;align-items:flex-start}
.grid{grid-template-columns:1fr}
}
19 changes: 15 additions & 4 deletions web/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES2020",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
Expand All @@ -12,8 +16,15 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
"jsx": "preserve",
"incremental": true
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
Loading
Loading