feat: added nav

This commit is contained in:
Boris Cherepanov
2025-10-03 01:10:06 +03:00
parent 8472e21955
commit bfa2878109
19 changed files with 369 additions and 250 deletions

View File

@@ -0,0 +1 @@
export * from './nav-menu';

View File

@@ -0,0 +1 @@
export * from './nav-menu';

View File

@@ -0,0 +1,31 @@
import { Link, useLocation } from 'react-router';
import { clsx } from 'clsx';
interface NavMenuItems {
href: string;
label: string;
}
interface NavMenuProps {
items: NavMenuItems[];
}
export const NavMenu = (props: NavMenuProps) => {
const { items } = props;
const { pathname } = useLocation();
return (
<div className="tabs">
{items.map(({ href, label }) => (
<Link
className={clsx('tab', {
active: href === pathname,
})}
to={href}
>
{label}
</Link>
))}
</div>
);
};

View File

@@ -0,0 +1,52 @@
import type { RouteObject } from 'react-router';
export const Certificates = () => {
return (
<div id="certificates" className="tab-content active">
<div className="section">
<h2>Add Certificate</h2>
<form id="certificateForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="certName" required />
</div>
<div className="form-group">
<label>Domain:</label>
<input
type="text"
id="certDomain"
placeholder="example.com"
required
/>
</div>
<div className="form-group">
<label>Certificate Type:</label>
<select id="certType" required>
<option value="self_signed">Self-Signed</option>
</select>
</div>
<div className="form-group">
<label>
<input type="checkbox" id="certAutoRenew" checked /> Auto Renew
</label>
</div>
<button type="submit" className="btn btn-primary">
Generate Certificate
</button>
</form>
</div>
<div className="section">
<h2>Certificates List</h2>
<div id="certificatesList" className="loading">
Loading...
</div>
</div>
</div>
);
};
export const CertificatesRoute: RouteObject = {
path: '/certificates',
Component: Certificates,
};

View File

@@ -0,0 +1 @@
export * from './certificates';

View File

@@ -0,0 +1,29 @@
import type { RouteObject } from 'react-router';
export const Dashboard = () => {
return (
<div id="dashboard" className="tab-content active">
<div className="section">
<h2>Statistics</h2>
<p>
Servers: <span id="serverCount">Loading...</span>
</p>
<p>
Templates: <span id="templateCount">Loading...</span>
</p>
<p>
Certificates: <span id="certCount">Loading...</span>
</p>
<p>
Users: <span id="userCount">Loading...</span>
</p>
</div>
</div>
);
};
export const DashboardRoute: RouteObject = {
index: true,
path: '/',
Component: Dashboard,
};

View File

@@ -0,0 +1 @@
export * from './dashboard';

View File

@@ -1,5 +1,7 @@
import { Outlet } from 'react-router';
import './home.css';
import { NavMenu } from '../../components/nav-menu/nav-menu';
import { navItems } from './utils';
export const Home = () => {
return (
@@ -10,266 +12,21 @@ export const Home = () => {
{/* <!-- Toast notifications container --> */}
<div className="toast-container" id="toastContainer"></div>
<div className="tabs">
<div
className="tab active"
// onClick="showTab('dashboard')"
>
Dashboard
</div>
<div
className="tab"
// onClick="showTab('servers')"
>
Servers
</div>
<div
className="tab"
//onClick="showTab('templates')"
>
Inbound Templates
</div>
<div
className="tab"
// onClick="showTab('certificates')"
>
Certificates
</div>
<div
className="tab"
// onClick="showTab('inbounds')"
>
Inbound Binding
</div>
<div
className="tab"
// onClick="showTab('users')"
>
Users
</div>
</div>
<NavMenu items={navItems} />
{/* <!-- Dashboard --> */}
<div id="dashboard" className="tab-content active">
<div className="section">
<h2>Statistics</h2>
<p>
Servers: <span id="serverCount">Loading...</span>
</p>
<p>
Templates: <span id="templateCount">Loading...</span>
</p>
<p>
Certificates: <span id="certCount">Loading...</span>
</p>
<p>
Users: <span id="userCount">Loading...</span>
</p>
</div>
</div>
<Outlet />
{/* <!-- Servers --> */}
<div id="servers" className="tab-content">
<div className="section">
<h2>Add Server</h2>
<form id="serverForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="serverName" required />
</div>
<div className="form-group">
<label>Hostname:</label>
<input type="text" id="serverHostname" required />
</div>
<div className="form-group">
<label>gRPC Port:</label>
<input type="number" id="serverPort" value="2053" />
</div>
<button type="submit" className="btn btn-primary">
Add Server
</button>
</form>
</div>
<div className="section">
<h2>Servers List</h2>
<div id="serversList" className="loading">
Loading...
</div>
</div>
</div>
{/* <!-- Templates --> */}
<div id="templates" className="tab-content">
<div className="section">
<h2>Add Template</h2>
<form id="templateForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="templateName" required />
</div>
<div className="form-group">
<label>Protocol:</label>
<select id="templateProtocol" required>
<option value="vless">VLESS</option>
<option value="vmess">VMess</option>
<option value="trojan">Trojan</option>
<option value="shadowsocks">Shadowsocks</option>
</select>
</div>
<div className="form-group">
<label>Default Port:</label>
<input type="number" id="templatePort" value="443" required />
</div>
<div className="form-group">
<label>
<input type="checkbox" id="templateTls" /> Requires TLS
</label>
</div>
<div className="form-group">
<label>Configuration Template:</label>
<textarea
id="templateConfig"
rows={6}
style={{
width: '300px',
}}
></textarea>
</div>
<button type="submit" className="btn btn-primary">
Add Template
</button>
</form>
</div>
<div className="section">
<h2>Templates List</h2>
<div id="templatesList" className="loading">
Loading...
</div>
</div>
</div>
{/* <!-- Certificates --> */}
<div id="certificates" className="tab-content">
<div className="section">
<h2>Add Certificate</h2>
<form id="certificateForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="certName" required />
</div>
<div className="form-group">
<label>Domain:</label>
<input
type="text"
id="certDomain"
placeholder="example.com"
required
/>
</div>
<div className="form-group">
<label>Certificate Type:</label>
<select id="certType" required>
<option value="self_signed">Self-Signed</option>
</select>
</div>
<div className="form-group">
<label>
<input type="checkbox" id="certAutoRenew" checked /> Auto
Renew
</label>
</div>
<button type="submit" className="btn btn-primary">
Generate Certificate
</button>
</form>
</div>
<div className="section">
<h2>Certificates List</h2>
<div id="certificatesList" className="loading">
Loading...
</div>
</div>
</div>
{/* <!-- Server Inbounds --> */}
<div id="inbounds" className="tab-content">
<div className="section">
<h2>Bind Template to Server</h2>
<form id="inboundForm">
<div className="form-group">
<label>Server:</label>
<select id="inboundServer" required>
<option value="">Select Server...</option>
</select>
</div>
<div className="form-group">
<label>Template:</label>
<select id="inboundTemplate" required>
<option value="">Select Template...</option>
</select>
</div>
<div className="form-group">
<label>Port:</label>
<input type="number" id="inboundPort" value="443" required />
</div>
<div className="form-group">
<label>Certificate:</label>
<select id="inboundCertificate">
<option value="">No Certificate</option>
</select>
</div>
<div className="form-group">
<label>
<input type="checkbox" id="inboundActive" checked /> Active
</label>
</div>
<button type="submit" className="btn btn-primary">
Bind Template
</button>
</form>
</div>
<div className="section">
<h2>Server Inbounds</h2>
<div id="inboundsList" className="loading">
Loading...
</div>
</div>
</div>
{/* <!-- Users --> */}
<div id="users" className="tab-content">
<div className="section">
<h2>Add User</h2>
<form id="userForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="userName" required />
</div>
<div className="form-group">
<label>Comment:</label>
<input type="text" id="userComment" />
</div>
<div className="form-group">
<label>Telegram ID:</label>
<input type="number" id="userTelegram" />
</div>
<button type="submit" className="btn btn-primary">
Add User
</button>
</form>
</div>
<div className="section">
<h2>Users List</h2>
<div id="usersList" className="loading">
Loading...
</div>
</div>
</div>
</div>
{/* <!-- Modal dialogs --> */}
@@ -333,7 +90,6 @@ export const Home = () => {
</div>
</div>
</div>
<Outlet />
</div>
);
};

View File

@@ -0,0 +1,26 @@
export const navItems = [
{
href: '/',
label: 'Dashboard',
},
{
href: '/servers',
label: 'Servers',
},
{
href: '/inbound-templates',
label: 'Inbound Templates',
},
{
href: '/certificates',
label: 'Certificates',
},
{
href: '/inbound-binding',
label: 'Inbound Binding',
},
{
href: '/users',
label: 'Users',
},
];

View File

@@ -0,0 +1,55 @@
import type { RouteObject } from 'react-router';
export const InboundBinding = () => {
return (
<div id="inbounds" className="tab-content active">
<div className="section">
<h2>Bind Template to Server</h2>
<form id="inboundForm">
<div className="form-group">
<label>Server:</label>
<select id="inboundServer" required>
<option value="">Select Server...</option>
</select>
</div>
<div className="form-group">
<label>Template:</label>
<select id="inboundTemplate" required>
<option value="">Select Template...</option>
</select>
</div>
<div className="form-group">
<label>Port:</label>
<input type="number" id="inboundPort" value="443" required />
</div>
<div className="form-group">
<label>Certificate:</label>
<select id="inboundCertificate">
<option value="">No Certificate</option>
</select>
</div>
<div className="form-group">
<label>
<input type="checkbox" id="inboundActive" checked /> Active
</label>
</div>
<button type="submit" className="btn btn-primary">
Bind Template
</button>
</form>
</div>
<div className="section">
<h2>Server Inbounds</h2>
<div id="inboundsList" className="loading">
Loading...
</div>
</div>
</div>
);
};
export const InboundBindingRoute: RouteObject = {
path: '/inbound-binding',
Component: InboundBinding,
};

View File

@@ -0,0 +1 @@
export * from './inbound-binding';

View File

@@ -0,0 +1,60 @@
import type { RouteObject } from 'react-router';
export const InboundTemplates = () => {
return (
<div id="templates" className="tab-content active">
<div className="section">
<h2>Add Template</h2>
<form id="templateForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="templateName" required />
</div>
<div className="form-group">
<label>Protocol:</label>
<select id="templateProtocol" required>
<option value="vless">VLESS</option>
<option value="vmess">VMess</option>
<option value="trojan">Trojan</option>
<option value="shadowsocks">Shadowsocks</option>
</select>
</div>
<div className="form-group">
<label>Default Port:</label>
<input type="number" id="templatePort" value="443" required />
</div>
<div className="form-group">
<label>
<input type="checkbox" id="templateTls" /> Requires TLS
</label>
</div>
<div className="form-group">
<label>Configuration Template:</label>
<textarea
id="templateConfig"
rows={6}
style={{
width: '300px',
}}
></textarea>
</div>
<button type="submit" className="btn btn-primary">
Add Template
</button>
</form>
</div>
<div className="section">
<h2>Templates List</h2>
<div id="templatesList" className="loading">
Loading...
</div>
</div>
</div>
);
};
export const InboundTemplatesRoute: RouteObject = {
path: '/inbound-templates',
Component: InboundTemplates,
};

View File

@@ -0,0 +1 @@
export * from './inboud-templates';

View File

@@ -1 +1,7 @@
export * from './home';
export * from './certificates';
export * from './dashboard';
export * from './inbound-binding';
export * from './inbound-templates';
export * from './servers';
export * from './users';

View File

@@ -0,0 +1 @@
export * from './servers';

View File

@@ -0,0 +1,40 @@
import type { RouteObject } from 'react-router';
export const Servers = () => {
return (
<div id="servers" className="tab-content active">
<div className="section">
<h2>Add Server</h2>
<form id="serverForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="serverName" required />
</div>
<div className="form-group">
<label>Hostname:</label>
<input type="text" id="serverHostname" required />
</div>
<div className="form-group">
<label>gRPC Port:</label>
<input type="number" id="serverPort" value="2053" />
</div>
<button type="submit" className="btn btn-primary">
Add Server
</button>
</form>
</div>
<div className="section">
<h2>Servers List</h2>
<div id="serversList" className="loading">
Loading...
</div>
</div>
</div>
);
};
export const ServersRoute: RouteObject = {
path: '/servers',
Component: Servers,
};

View File

@@ -0,0 +1 @@
export * from './users';

View File

@@ -0,0 +1,40 @@
import type { RouteObject } from 'react-router';
export const Users = () => {
return (
<div id="users" className="tab-content active">
<div className="section">
<h2>Add User</h2>
<form id="userForm">
<div className="form-group">
<label>Name:</label>
<input type="text" id="userName" required />
</div>
<div className="form-group">
<label>Comment:</label>
<input type="text" id="userComment" />
</div>
<div className="form-group">
<label>Telegram ID:</label>
<input type="number" id="userTelegram" />
</div>
<button type="submit" className="btn btn-primary">
Add User
</button>
</form>
</div>
<div className="section">
<h2>Users List</h2>
<div id="usersList" className="loading">
Loading...
</div>
</div>
</div>
);
};
export const UsersRoute: RouteObject = {
path: '/users',
Component: Users,
};

View File

@@ -1,9 +1,25 @@
import { createBrowserRouter } from 'react-router';
import { Home } from '../pages';
import {
Home,
DashboardRoute,
ServersRoute,
InboundTemplatesRoute,
CertificatesRoute,
InboundBindingRoute,
UsersRoute,
} from '../pages';
export const router = createBrowserRouter([
{
path: '/',
Component: Home,
children: [
DashboardRoute,
ServersRoute,
InboundTemplatesRoute,
CertificatesRoute,
InboundBindingRoute,
UsersRoute,
],
},
]);