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
35 changes: 35 additions & 0 deletions Frontend/dashboard.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Sentinel AI — Dashboard (Static)</title>
<style>
:root{--bg:#000;--bg2:#0a0a0a;--card:#111;--borders:#1f1f1f;--text:#fff;--muted:#9a9a9a;--accent:#3b82f6}
body{margin:0;background:var(--bg2);color:var(--text);font-family:Inter,system-ui,Segoe UI,Roboto,Arial}
.wrap{max-width:1100px;margin:36px auto;padding:20px}
.header{display:flex;justify-content:space-between;align-items:center;padding:12px 0;border-bottom:1px solid var(--borders)}
.dash-cards{display:flex;gap:12px;margin-top:20px}
.card{background:var(--card);padding:18px;border-radius:10px;border:1px solid var(--borders);min-width:180px}
.muted{color:var(--muted)}
</style>
</head>
<body>
<div class="wrap">
<div class="header">
<div class="brand">Sentinel AI</div>
<div class="muted">Simulated Session</div>
</div>

<main>
<h1>Dashboard</h1>
<p class="muted">Welcome to your simulated Sentinel AI dashboard.</p>
<div class="dash-cards">
<div class="card">Portfolio Value<br/><strong>$1,234,567</strong></div>
<div class="card">Daily P&L<br/><strong>+0.42%</strong></div>
<div class="card">Active Agents<br/><strong>5</strong></div>
</div>
</main>
</div>
</body>
</html>
12 changes: 12 additions & 0 deletions Frontend/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Sentinel AI</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
20 changes: 20 additions & 0 deletions Frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "sentinel-ai-frontend",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"serve:static": "node server.js"
},
"dependencies": {
"react": "18.2.0",
"react-dom": "18.2.0",
"react-router-dom": "6.14.1"
},
"devDependencies": {
"vite": "5.2.0",
"@vitejs/plugin-react": "5.0.0"
}
}
53 changes: 53 additions & 0 deletions Frontend/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
const http = require('http')
const fs = require('fs')
const path = require('path')

const port = process.env.PORT ? Number(process.env.PORT) : 5173
const root = __dirname

const mime = {
'.html': 'text/html; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.js': 'application/javascript; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.svg': 'image/svg+xml',
'.ico': 'image/x-icon'
}

function sendFile(filePath, res) {
fs.readFile(filePath, (error, content) => {
if (error) {
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' })
res.end('Not Found')
return
}

const ext = path.extname(filePath).toLowerCase()
res.writeHead(200, { 'Content-Type': mime[ext] || 'application/octet-stream' })
res.end(content)
})
}

const server = http.createServer((req, res) => {
const urlPath = decodeURIComponent((req.url || '/').split('?')[0])

if (urlPath === '/' || urlPath === '/index.html') {
sendFile(path.join(root, 'static.html'), res)
return
}

if (urlPath === '/dashboard' || urlPath === '/dashboard.html') {
sendFile(path.join(root, 'dashboard.html'), res)
return
}

const safePath = path.normalize(urlPath).replace(/^([.][.][/\\])+/, '')
sendFile(path.join(root, safePath), res)
Comment on lines +35 to +48
})

server.listen(port, '127.0.0.1', () => {
console.log(`Sentinel AI static server running at http://127.0.0.1:${port}`)
})
Comment on lines +51 to +53
13 changes: 13 additions & 0 deletions Frontend/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import { Routes, Route } from 'react-router-dom'
import Landing from './pages/Landing'
import Dashboard from './pages/Dashboard'

export default function App() {
return (
<Routes>
<Route path="/" element={<Landing />} />
<Route path="/dashboard" element={<Dashboard />} />
</Routes>
)
}
37 changes: 37 additions & 0 deletions Frontend/src/components/Hero.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react'

function AgentBubble({ name }) {
return (
<div className="agent-bubble">
<div className="agent-name">{name}</div>
<div className="agent-message" />
</div>
)
}

export default function Hero({ onConnect }) {
return (
<section className="hero">
<div className="hero-copy">
<h1>Your Autonomous AI Investment Committee</h1>
<p className="sub">A team of AI agents that debate, vote, and execute investment decisions on your behalf.</p>
<div className="hero-ctas">
<button className="btn btn-primary" onClick={onConnect}>Connect Wallet</button>
<button className="btn btn-ghost">View Demo</button>
</div>
</div>

<div className="hero-visual" aria-hidden>
<div className="glass-panel">
<div className="agents-row">
<AgentBubble name="Bull Agent" />
<AgentBubble name="Bear Agent" />
<AgentBubble name="Neutral Agent" />
<AgentBubble name="Onchain Agent" />
<AgentBubble name="Yield Agent" />
</div>
</div>
</div>
</section>
)
}
12 changes: 12 additions & 0 deletions Frontend/src/components/Loading.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react'

export default function Loading() {
return (
<div className="loading-overlay">
<div className="loader">
<div className="spinner" />
<div className="loader-text">Connecting Sentinel Committee…</div>
</div>
</div>
)
}
13 changes: 13 additions & 0 deletions Frontend/src/main.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router-dom'
import App from './App'
import './styles.css'

createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
)
20 changes: 20 additions & 0 deletions Frontend/src/pages/Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react'

export default function Dashboard() {
return (
<div className="dashboard-root">
<header className="dash-header">
<div className="brand">Sentinel AI</div>
</header>
<main className="dash-main">
<h1>Dashboard</h1>
<p className="muted">Welcome to your simulated Sentinel AI dashboard.</p>
<div className="dash-cards">
<div className="card">Portfolio Value<br/><strong>$1,234,567</strong></div>
<div className="card">Daily P&L<br/><strong>+0.42%</strong></div>
<div className="card">Active Agents<br/><strong>5</strong></div>
</div>
</main>
</div>
)
}
71 changes: 71 additions & 0 deletions Frontend/src/pages/Landing.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React, { useState } from 'react'
import { useNavigate } from 'react-router-dom'
import Hero from '../components/Hero'
import Loading from '../components/Loading'

export default function Landing() {
const navigate = useNavigate()
const [loading, setLoading] = useState(false)

function handleConnect() {
setLoading(true)
// simulate elegant 2s loading
setTimeout(() => {
setLoading(false)
navigate('/dashboard')
}, 2000)
}
Comment on lines +1 to +17

return (
<div className="page-root">
{loading && <Loading />}
<header className="site-header">
<div className="brand">Sentinel AI</div>
<nav className="nav-actions">
<button className="btn btn-ghost">View Demo</button>
</nav>
</header>

<main className="container">
<Hero onConnect={handleConnect} />

<section className="how-it-works">
<h3>How It Works</h3>
<ol>
<li>Connect Wallet</li>
<li>Set Risk Profile</li>
<li>AI Committee Debates</li>
<li>Portfolio Executes</li>
<li>Autonomous Rebalancing</li>
</ol>
</section>

<section className="committee">
<h3>AI Committee</h3>
<div className="agent-grid">
<div className="agent-card">Bull Agent</div>
<div className="agent-card">Bear Agent</div>
<div className="agent-card">Neutral Agent</div>
<div className="agent-card">Onchain Agent</div>
<div className="agent-card">Yield Agent</div>
</div>
</section>

<section className="features">
<h3>Features</h3>
<ul>
<li>Multi Agent Intelligence</li>
<li>Real-Time Portfolio Monitoring</li>
<li>Smart Account Automation</li>
<li>Autonomous Rebalancing</li>
<li>Institutional Risk Controls</li>
</ul>
</section>
</main>

<footer className="site-footer">
<div>© {new Date().getFullYear()} Sentinel AI — Institutional grade AI investing</div>
</footer>
</div>
)
}
61 changes: 61 additions & 0 deletions Frontend/src/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
:root{
--bg: #000000;
--bg-2: #0a0a0a;
--card: #111111;
--borders: #1f1f1f;
--text: #ffffff;
--muted: #9a9a9a;
--accent: #3b82f6;
--success: #10b981;
--warning: #f59e0b;
--glass: rgba(255,255,255,0.04);
}
*{box-sizing:border-box}
html,body,#root{height:100%}
body{
margin:0;
background:var(--bg);
color:var(--text);
font-family: Inter, ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial;
-webkit-font-smoothing:antialiased;
-moz-osx-font-smoothing:grayscale;
}
.site-header{
display:flex;align-items:center;justify-content:space-between;padding:20px 40px;border-bottom:1px solid var(--borders);background:linear-gradient(180deg, rgba(255,255,255,0.02), transparent)
}
.brand{font-weight:700;font-size:18px}
.container{max-width:1100px;margin:40px auto;padding:0 20px}
.hero{display:flex;gap:40px;align-items:center}
.hero-copy{flex:1}
.hero-copy h1{font-size:44px;margin:0 0 10px;font-weight:800}
.hero-copy .sub{color:var(--muted);margin-bottom:20px}
.hero-ctas{display:flex;gap:12px}
.btn{padding:10px 18px;border-radius:10px;border:1px solid var(--borders);background:transparent;color:var(--text);cursor:pointer}
.btn-primary{background:linear-gradient(90deg,var(--accent),#60a5fa);border:none;font-weight:700}
.btn-ghost{background:transparent;border:1px solid rgba(255,255,255,0.04)}
.hero-visual{width:480px}
.glass-panel{background:linear-gradient(135deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));border:1px solid rgba(255,255,255,0.04);backdrop-filter: blur(8px);padding:20px;border-radius:14px}
.agents-row{display:flex;gap:12px;align-items:center;justify-content:space-between}
.agent-bubble{width:80px;height:80px;background:var(--card);border-radius:12px;padding:10px;display:flex;flex-direction:column;align-items:flex-start;justify-content:center;position:relative;overflow:hidden;border:1px solid var(--borders)}
.agent-name{font-weight:700;font-size:12px}
.agent-message{position:absolute;right:8px;bottom:8px;width:8px;height:8px;border-radius:50%;background:var(--accent);opacity:0;animation:ping 2s infinite}
@keyframes ping{0%{opacity:0;transform:scale(0.6)}30%{opacity:1;transform:scale(1.4)}100%{opacity:0;transform:scale(2)}}

.how-it-works, .committee, .features{margin-top:40px;padding:20px;background:linear-gradient(180deg, rgba(255,255,255,0.01), transparent);border:1px solid rgba(255,255,255,0.02);border-radius:10px}
.agent-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-top:12px}
.agent-card{background:var(--card);padding:16px;border-radius:8px;border:1px solid var(--borders)}
.features ul{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
.site-footer{padding:24px 40px;border-top:1px solid var(--borders);color:var(--muted);font-size:14px}

.loading-overlay{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:linear-gradient(180deg, rgba(0,0,0,0.6), rgba(0,0,0,0.75));backdrop-filter: blur(4px);z-index:60}
.loader{display:flex;flex-direction:column;align-items:center;gap:12px}
.spinner{width:64px;height:64px;border-radius:50%;border:6px solid rgba(255,255,255,0.06);border-top-color:var(--accent);animation:spin 1s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.loader-text{color:var(--muted)}

.dashboard-root{min-height:100vh;background:var(--bg-2)}
.dash-header{padding:20px 40px;border-bottom:1px solid var(--borders)}
.dash-main{max-width:1100px;margin:40px auto;padding:20px}
.dash-cards{display:flex;gap:12px;margin-top:20px}
.card{background:var(--card);padding:20px;border-radius:10px;border:1px solid var(--borders);min-width:180px}
.muted{color:var(--muted)}
Loading