docs: update landing page UI and add comparison tables
This commit is contained in:
1 parent
496186e2af
commit
133c707f27
1 file changed
+627
-317
+627
-317
@@ -1,324 +1,634 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>BZOD — Private • Fast • Beautiful URL Shortener</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.6.0/css/all.min.css"
|
||||
/>
|
||||
<style>
|
||||
body {
|
||||
font-family: "Inter", system-ui, sans-serif;
|
||||
<!DOCTYPE html>
|
||||
<!-- saved from url=(0062)#compare -->
|
||||
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="BZOD — Self-hosted Multi-User URL Management Platform written in Rust with landing pages, QR codes, analytics, audit logging, and SQLite backend.">
|
||||
<title>BZOD | Self-Hosted URL Management in Rust</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com/">
|
||||
<link href="./index_files/css2" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0b0f14; --bg2: #131820; --bg3: #1a202a; --bg4: #212733;
|
||||
--border: #29303d; --border2: #384152;
|
||||
--a1: #6db1ff; --a2: #56d364; --a3: #f85149; --a4: #d2a8ff; --a5: #f0883e;
|
||||
--rust: #e05c2f;
|
||||
--t1: #e6edf3; --t2: #8d96a0; --t3: #656d76;
|
||||
--glow: rgba(109, 177, 255, 0.08);
|
||||
--mono: 'JetBrains Mono', monospace;
|
||||
--sans: 'Inter', system-ui, sans-serif;
|
||||
--r: 8px; --rl: 16px;
|
||||
}
|
||||
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
|
||||
html{scroll-behavior:smooth}
|
||||
body{background:var(--bg);color:var(--t1);font-family:var(--sans);font-size:15px;line-height:1.8;overflow-x:hidden}
|
||||
::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:var(--bg)}::-webkit-scrollbar-thumb{background:var(--border2);border-radius:4px}
|
||||
a{color:var(--a1);text-decoration:none;transition: color 0.2s}a:hover{color:var(--t1)}
|
||||
|
||||
/* NAV */
|
||||
nav{position:fixed;top:0;left:0;right:0;z-index:200;background:rgba(11, 15, 20, 0.85);backdrop-filter:blur(16px);border-bottom:1px solid var(--border);height:64px;display:flex;align-items:center;padding:0 2rem;gap:1.5rem}
|
||||
.nav-logo{display:flex;align-items:center;gap:.75rem;font-family:var(--sans);font-weight:700;font-size:1.05rem;color:var(--t1);white-space:nowrap;letter-spacing:-0.02em}
|
||||
.logo-box{width:32px;height:32px;background:linear-gradient(135deg,var(--rust) 0%,#ff7b47 100%);border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.85rem;font-weight:700;color:#fff;flex-shrink:0;box-shadow:0 2px 10px rgba(224,92,47,0.3)}
|
||||
.nav-links{display:flex;gap:1.5rem;list-style:none;margin-left:1rem}
|
||||
.nav-links a{color:var(--t2);font-size:.85rem;font-weight:500;transition:color .2s;display:flex;align-items:center;gap:0.4rem}
|
||||
.nav-links svg{width:14px;height:14px;opacity:0.75;transition:opacity 0.2s}
|
||||
.nav-links a:hover{color:var(--t1);text-decoration:none}
|
||||
.nav-links a:hover svg{opacity:1}
|
||||
.nav-right{margin-left:auto;display:flex;gap:.75rem;align-items:center;flex-wrap:wrap;justify-content:flex-end}
|
||||
.btn-sm{padding:.4rem 1rem;border-radius:var(--r);font-size:.8rem;font-weight:500;cursor:pointer;font-family:var(--sans);transition:all .2s;text-decoration:none!important;display:inline-flex;align-items:center;justify-content:center;gap:.4rem}
|
||||
.btn-sm svg{width:14px;height:14px}
|
||||
.btn-ghost{border:1px solid var(--border);background:var(--bg2);color:var(--t1)}.btn-ghost:hover{border-color:var(--border2);background:var(--bg3)}
|
||||
.btn-solid{background:var(--t1);color:var(--bg);border:none;font-weight:600}.btn-solid:hover{background:#ffffff;transform:translateY(-1px)}
|
||||
|
||||
/* LAYOUT */
|
||||
.container{max-width:1140px;margin:0 auto;width:100%}
|
||||
section{padding:5.5rem 2rem}
|
||||
.eyebrow{font-family:var(--sans);font-weight:600;font-size:.75rem;letter-spacing:.08em;color:var(--t2);text-transform:uppercase;margin-bottom:.75rem}
|
||||
.section-title{font-size:clamp(1.75rem,3vw,2.5rem);font-weight:700;line-height:1.2;margin-bottom:1rem;letter-spacing:-0.03em}
|
||||
.section-sub{color:var(--t2);max-width:640px;font-size:1rem;margin-bottom:3rem;line-height:1.7}
|
||||
.divider{height:1px;background:var(--border);max-width:1140px;margin:0 auto}
|
||||
|
||||
/* HERO */
|
||||
.hero{min-height:100vh;display:flex;align-items:center;padding:100px 2rem 4rem;position:relative;overflow:hidden}
|
||||
.hero-bg{position:absolute;inset:0;background:radial-gradient(circle at 70% 30%, var(--glow) 0%, transparent 60%)}
|
||||
.hero-inner{max-width:1140px;margin:0 auto;width:100%;position:relative;z-index:1;display:grid;grid-template-columns:1.15fr .85fr;gap:4rem;align-items:center}
|
||||
.hero-badge{display:inline-flex;align-items:center;gap:.6rem;padding:.35rem 1rem;border-radius:999px;border:1px solid var(--border);background:var(--bg2);color:var(--t1);font-size:.8rem;font-weight:500;margin-bottom:1.5rem}
|
||||
.pulse{width:8px;height:8px;border-radius:50%;background:var(--a2);box-shadow: 0 0 10px var(--a2)}
|
||||
.hero h1{font-size:clamp(2.5rem,4.5vw,3.8rem);font-weight:700;line-height:1.1;letter-spacing:-0.03em;margin-bottom:1.25rem}
|
||||
.hero h1 .hl{color:var(--t1)}.hero h1 .hr{color:var(--rust)}
|
||||
.hero-desc{color:var(--t2);font-size:1.05rem;line-height:1.7;margin-bottom:2rem;max-width:500px}
|
||||
.hero-ctas{display:flex;gap:1rem;flex-wrap:wrap}
|
||||
.btn-lg{padding:.75rem 1.75rem;border-radius:var(--r);font-size:.95rem;font-weight:500;cursor:pointer;font-family:var(--sans);transition:all .2s;text-decoration:none!important;display:inline-flex;align-items:center;justify-content:center}
|
||||
.btn-lg.p{background:var(--t1);color:var(--bg)}.btn-lg.p:hover{background:#ffffff;transform:translateY(-2px);box-shadow:0 8px 24px rgba(255,255,255,0.1)}
|
||||
.btn-lg.o{border:1px solid var(--border);color:var(--t1);background:var(--bg2)}.btn-lg.o:hover{border-color:var(--border2);background:var(--bg3)}
|
||||
.hero-meta{margin-top:2rem;display:flex;gap:1.5rem;flex-wrap:wrap}
|
||||
.meta-tag{font-family:var(--mono);font-size:.75rem;color:var(--t3);display:flex;align-items:center;gap:.4rem}
|
||||
|
||||
/* TERMINAL */
|
||||
.terminal{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rl);overflow:hidden;box-shadow:0 24px 80px rgba(0,0,0,.5)}
|
||||
.t-bar{background:var(--bg3);padding:.8rem 1.2rem;display:flex;align-items:center;gap:.5rem;border-bottom:1px solid var(--border)}
|
||||
.dot{width:12px;height:12px;border-radius:50%}
|
||||
.d-r{background:#ff5f57}.d-y{background:#ffbd2e}.d-g{background:#27c93f}
|
||||
.t-title{margin:0 auto;font-family:var(--sans);font-weight:500;font-size:.8rem;color:var(--t3)}
|
||||
.t-body{padding:1.5rem;font-family:var(--mono);font-size:.85rem;line-height:1.7;white-space:pre-wrap}
|
||||
.tp{color:var(--t3)}.tc{color:var(--t1)}.to{color:var(--t2)}.tk{color:var(--a4)}.tv{color:var(--a1)}.tg{color:var(--a2)}
|
||||
.t-spacer{display:block;height:.75rem}
|
||||
|
||||
/* STATS */
|
||||
.stats-band{border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:2.5rem 2rem}
|
||||
.stats-grid{max-width:1140px;margin:0 auto;display:grid;grid-template-columns:repeat(7,1fr);gap:1rem;text-align:center}
|
||||
.stat-n{font-family:var(--sans);font-size:1.75rem;font-weight:600;color:var(--t1);display:block;letter-spacing:-0.02em}
|
||||
.stat-l{font-size:.8rem;color:var(--t2);margin-top:.4rem;font-weight:400}
|
||||
|
||||
/* CARDS */
|
||||
.grid-2{display:grid;grid-template-columns:repeat(2,1fr);gap:1.5rem}
|
||||
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem}
|
||||
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:1.5rem}
|
||||
.card{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rl);padding:1.75rem;transition:transform .3s ease, border-color .3s ease;position:relative}
|
||||
.card:hover{border-color:var(--border2);transform:translateY(-4px);box-shadow:0 12px 32px rgba(0,0,0,0.2)}
|
||||
.card-icon{font-size:1.5rem;margin-bottom:1rem;display:inline-block}
|
||||
.card-title{font-weight:600;font-size:1.05rem;margin-bottom:.5rem;color:var(--t1)}
|
||||
.card-desc{color:var(--t2);font-size:.9rem;line-height:1.6}
|
||||
|
||||
/* TABLES & TREES */
|
||||
.compare-tbl{width:100%;border-collapse:collapse;font-size:.9rem;text-align:left;background:var(--bg2);border-radius:var(--rl);overflow:hidden;border:1px solid var(--border)}
|
||||
.compare-tbl th{background:var(--bg3);padding:1rem 1.5rem;font-weight:600;color:var(--t1);border-bottom:1px solid var(--border);white-space:nowrap}
|
||||
.compare-tbl td{padding:1rem 1.5rem;border-bottom:1px solid var(--border);color:var(--t2)}
|
||||
.compare-tbl tr:last-child td{border-bottom:none}
|
||||
.compare-tbl tr:hover td{background:rgba(255,255,255,.02)}
|
||||
.compare-tbl td:first-child{font-weight:500;color:var(--t1)}
|
||||
.check-yes{color:var(--a2);font-weight:700}
|
||||
.check-no{color:var(--a3)}
|
||||
.check-partial{color:var(--a5)}
|
||||
|
||||
.file-tree{font-family:var(--mono);font-size:.85rem;line-height:1.8;color:var(--t2);background:var(--bg2);padding:1.5rem;border-radius:var(--rl);border:1px solid var(--border)}
|
||||
.file-tree .dir{color:var(--a1);font-weight:600}
|
||||
.file-tree .file{color:var(--t1)}
|
||||
.file-tree .comment{color:var(--t3);font-style:italic;margin-left:1rem}
|
||||
|
||||
/* CODE & TABS */
|
||||
pre.cb{background:var(--bg2);border:1px solid var(--border);border-radius:var(--r);padding:1.25rem;font-family:var(--mono);font-size:.85rem;line-height:1.7;overflow-x:auto;color:var(--t1);white-space:pre}
|
||||
.cb .kw{color:var(--a1)}.cb .cm{color:var(--t3)}.cb .str{color:var(--a2)}
|
||||
.tab-shell{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rl);overflow:hidden}
|
||||
.tab-strip{display:flex;border-bottom:1px solid var(--border);overflow-x:auto;background:var(--bg3)}
|
||||
.tab-btn{padding:1rem 1.5rem;border:none;background:transparent;color:var(--t2);font-family:var(--sans);font-weight:500;font-size:.9rem;cursor:pointer;white-space:nowrap;border-bottom:2px solid transparent;transition:all .2s}
|
||||
.tab-btn.on{color:var(--t1);border-bottom-color:var(--a1)}
|
||||
.tab-btn:hover:not(.on){color:var(--t1);background:var(--bg4)}
|
||||
.tab-panel{display:none;padding:2rem}
|
||||
.tab-panel.on{display:block}
|
||||
|
||||
/* ARCHITECTURE */
|
||||
.arch-wrap{display:grid;grid-template-columns:1fr 1fr;gap:3rem;align-items:center}
|
||||
.flow-diagram{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rl);padding:2rem;font-family:var(--mono);font-size:.8rem;line-height:2;text-align:center}
|
||||
.fbox{border:1px solid var(--border);border-radius:6px;padding:.5rem 1rem;display:inline-block;color:var(--t1);background:var(--bg3);margin:.25rem 0}
|
||||
.farrow{color:var(--t3);font-size:1rem;margin:.25rem 0}
|
||||
|
||||
/* STEPS */
|
||||
.steps{display:flex;flex-direction:column;gap:1.5rem}
|
||||
.step{display:grid;grid-template-columns:32px 1fr;gap:1rem;align-items:start}
|
||||
.step-n{width:32px;height:32px;border-radius:50%;background:var(--bg3);border:1px solid var(--border);display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:.8rem;color:var(--t1);flex-shrink:0}
|
||||
.step-title{font-weight:600;font-size:.95rem;margin-bottom:.25rem;color:var(--t1)}
|
||||
|
||||
/* FAQ */
|
||||
.faq{display:flex;flex-direction:column;gap:1rem}
|
||||
.faq-item{background:var(--bg2);border:1px solid var(--border);border-radius:var(--r);overflow:hidden}
|
||||
.faq-q{padding:1.25rem 1.5rem;cursor:pointer;display:flex;justify-content:space-between;align-items:center;font-weight:500;font-size:.95rem;user-select:none;transition:background .2s}
|
||||
.faq-q:hover{background:var(--bg3)}
|
||||
.faq-chevron{color:var(--t3);font-size:.8rem;transition:transform .3s ease}
|
||||
.faq-item.open .faq-chevron{transform:rotate(180deg);color:var(--t1)}
|
||||
.faq-a{display:none;padding:0 1.5rem 1.25rem;color:var(--t2);font-size:.95rem;line-height:1.7}
|
||||
.faq-item.open .faq-a{display:block}
|
||||
|
||||
/* CTA */
|
||||
.cta-box{background:var(--bg2);border:1px solid var(--border);border-radius:var(--rl);padding:4rem 2rem;text-align:center}
|
||||
.cta-box h2{font-size:2rem;font-weight:700;margin-bottom:1rem;letter-spacing:-0.02em}
|
||||
.cta-box p{color:var(--t2);margin-bottom:2rem;font-size:1.05rem}
|
||||
.cta-actions{display:flex;gap:1rem;justify-content:center;flex-wrap:wrap}
|
||||
|
||||
/* FOOTER */
|
||||
footer{background:var(--bg);border-top:1px solid var(--border);padding:4rem 2rem 2rem}
|
||||
.footer-grid{max-width:1140px;margin:0 auto;display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:3rem;margin-bottom:3rem}
|
||||
.footer-brand{font-family:var(--sans);font-weight:700;font-size:1.05rem;display:flex;align-items:center;gap:.75rem;margin-bottom:1rem;letter-spacing:-0.02em}
|
||||
.footer-about{color:var(--t2);font-size:.9rem;line-height:1.7;max-width:300px}
|
||||
.footer-col-title{font-weight:600;font-size:.9rem;margin-bottom:1.25rem;color:var(--t1)}
|
||||
.footer-links{list-style:none;display:flex;flex-direction:column;gap:.75rem}
|
||||
.footer-links a{color:var(--t2);font-size:.9rem;transition:color .2s}.footer-links a:hover{color:var(--t1)}
|
||||
.footer-bottom{max-width:1140px;margin:0 auto;padding-top:2rem;border-top:1px solid var(--border);display:flex;justify-content:space-between;align-items:center;font-size:.85rem;color:var(--t3)}
|
||||
|
||||
@media(max-width:1024px){
|
||||
.hero-inner,.arch-wrap,.grid-2{grid-template-columns:1fr}
|
||||
.terminal{display:none}
|
||||
.nav-links{display:none}
|
||||
.stats-grid{grid-template-columns:repeat(4,1fr)}
|
||||
.compare-tbl {display: block; overflow-x: auto;}
|
||||
}
|
||||
@media(max-width:768px){
|
||||
.grid-3,.grid-4{grid-template-columns:repeat(2,1fr)}
|
||||
.footer-grid{grid-template-columns:1fr 1fr}
|
||||
}
|
||||
@media(max-width:480px){
|
||||
.stats-grid{grid-template-columns:repeat(2,1fr)}
|
||||
.grid-3,.grid-4{grid-template-columns:1fr}
|
||||
.footer-grid{grid-template-columns:1fr}
|
||||
.footer-bottom{flex-direction:column;gap:1rem;text-align:center}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav>
|
||||
<a class="nav-logo" href="#home">
|
||||
<div class="logo-box">BZ</div>
|
||||
BZOD
|
||||
</a>
|
||||
<ul class="nav-links">
|
||||
<li><a href="#features"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="sparkles" aria-hidden="true" class="lucide lucide-sparkles"><path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"></path><path d="M20 2v4"></path><path d="M22 4h-4"></path><circle cx="4" cy="20" r="2"></circle></svg> Features</a></li>
|
||||
<li><a href="#architecture"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="layers" aria-hidden="true" class="lucide lucide-layers"><path d="M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z"></path><path d="M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12"></path><path d="M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17"></path></svg> Architecture</a></li>
|
||||
<li><a href="#databases"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="database" aria-hidden="true" class="lucide lucide-database"><ellipse cx="12" cy="5" rx="9" ry="3"></ellipse><path d="M3 5V19A9 3 0 0 0 21 19V5"></path><path d="M3 12A9 3 0 0 0 21 12"></path></svg> Databases</a></li>
|
||||
<li><a href="#api"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="terminal" aria-hidden="true" class="lucide lucide-terminal"><path d="M12 19h8"></path><path d="m4 17 6-6-6-6"></path></svg> API</a></li>
|
||||
<li><a href="#cli"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="terminal-square" aria-hidden="true" class="lucide lucide-terminal-square"><path d="m7 11 2-2-2-2"></path><path d="M11 13h4"></path><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect></svg> CLI</a></li>
|
||||
<li><a href="#compare"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="git-compare" aria-hidden="true" class="lucide lucide-git-compare"><circle cx="18" cy="18" r="3"></circle><circle cx="6" cy="6" r="3"></circle><path d="M13 6h3a2 2 0 0 1 2 2v7"></path><path d="M11 18H8a2 2 0 0 1-2-2V9"></path></svg> Compare</a></li>
|
||||
</ul>
|
||||
<div class="nav-right">
|
||||
<a class="btn-sm btn-ghost" href="./login"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="log-in" aria-hidden="true" class="lucide lucide-log-in"><path d="m10 17 5-5-5-5"></path><path d="M15 12H3"></path><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path></svg> User Login</a>
|
||||
<a class="btn-sm btn-ghost" href="./admin"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="shield" aria-hidden="true" class="lucide lucide-shield"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"></path></svg> Admin Panel</a>
|
||||
<a class="btn-sm btn-ghost" href="https://github.com/thakares/nx9-url-shortener" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.02c3.18-.35 6.5-1.5 6.5-7a4.6 4.6 0 0 0-1.39-3.23 4.2 4.2 0 0 0-.1-3.2s-1.1-.35-3.5 1.25a11.39 11.39 0 0 0-7 0C6.2 2.75 5 3.1 5 3.1a4.2 4.2 0 0 0-.1 3.2A4.6 4.6 0 0 0 3.5 9.5c0 5.5 3.32 6.65 6.5 7-.33.26-.6.7-.7 1.35-.62.27-2.2.8-3.2-1.35-.1-.2-.3-.3-.5-.3-.2 0-.3.1-.1.3 1.1 2.3 3.1 2.5 3.8 2.5.1 1.2.2 2.6.2 3.1"></path><path d="M9 20c-1.5.5-3 0-3-2"></path></svg>
|
||||
GitHub
|
||||
</a>
|
||||
<a class="btn-sm btn-ghost" href="https://codeberg.org/thakares/nx9-url-shortener" target="_blank">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m8 3 4 8 5-5 5 15H2L8 3z"></path></svg>
|
||||
CodeBerg
|
||||
</a>
|
||||
<a class="btn-sm btn-solid" href="#install"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="rocket" aria-hidden="true" class="lucide lucide-rocket"><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"></path><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09"></path><path d="M9 12a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.4 22.4 0 0 1-4 2z"></path><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 .05 5 .05"></path></svg> Install</a>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<header class="hero" id="home">
|
||||
<div class="hero-bg"></div>
|
||||
<div class="hero-inner">
|
||||
<div>
|
||||
<div class="hero-badge"><span class="pulse"></span> Production Ready</div>
|
||||
<h1>Control Your URLs<br><span class="hl">Self-Hosted with</span> <span class="hr">Rust</span></h1>
|
||||
<p class="hero-desc">BZOD is a complete multi-user URL management platform featuring custom landing pages, analytics, audit logging, and automated disaster recovery. Powered entirely by SQLite.</p>
|
||||
<div class="hero-ctas">
|
||||
<a href="#install" class="btn-lg p">Deployment Guide</a>
|
||||
<a href="./login" class="btn-lg o">User Panel</a>
|
||||
</div>
|
||||
<div class="hero-meta">
|
||||
<span class="meta-tag">Rust 2021</span>
|
||||
<span class="meta-tag">Axum</span>
|
||||
<span class="meta-tag">SQLite</span>
|
||||
<span class="meta-tag">Docker Ready</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="terminal">
|
||||
<div class="t-bar"><span class="dot d-r"></span><span class="dot d-y"></span><span class="dot d-g"></span><span class="t-title">bzod — bash</span></div>
|
||||
<div class="t-body">
|
||||
<span class="tp">$</span> <span class="tc">git clone https://github.com/thakares/nx9-url-shortener bzod</span>
|
||||
<span class="to">Cloning into 'bzod'...</span>
|
||||
<span class="t-spacer"></span>
|
||||
<span class="tp">$</span> <span class="tc">cargo build --release</span>
|
||||
<span class="to"> Compiling bzod v0.5.0</span>
|
||||
<span class="tg"> Finished release [optimized] in 12.58s</span>
|
||||
<span class="t-spacer"></span>
|
||||
<span class="tp">$</span> <span class="tc">./target/release/bzod serve</span>
|
||||
<span class="t-spacer"></span>
|
||||
<span class="to">[INFO]</span> <span class="tc">database=SQLite multi_user=enabled</span>
|
||||
<span class="to">[INFO]</span> <span class="tc">Listening on 0.0.0.0:8654</span>
|
||||
<span class="t-spacer"></span>
|
||||
<span class="tp">$</span> <span class="tc">curl -X POST http://localhost:8654/api/v1/urls \</span>
|
||||
<span class="tc"> -H "Authorization: bzo_TOKEN" \</span>
|
||||
<span class="tc"> -d '{"target_url":"https://example.com","code":"my-link"}'</span>
|
||||
<span class="tg">✅ Created: http://localhost:8654/my-link</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="stats-band">
|
||||
<div class="stats-grid">
|
||||
<div><span class="stat-n">∞</span><div class="stat-l">Short URLs</div></div>
|
||||
<div><span class="stat-n">QR</span><div class="stat-l">Generation</div></div>
|
||||
<div><span class="stat-n">Realtime</span><div class="stat-l">Analytics</div></div>
|
||||
<div><span class="stat-n">Multi</span><div class="stat-l">User Config</div></div>
|
||||
<div><span class="stat-n">Logs</span><div class="stat-l">Audit Trail</div></div>
|
||||
<div><span class="stat-n">Backup</span><div class="stat-l">& Restore</div></div>
|
||||
<div><span class="stat-n">GPLv3</span><div class="stat-l">Open Source</div></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section id="features">
|
||||
<div class="container">
|
||||
<div class="eyebrow">Core Features</div>
|
||||
<h2 class="section-title">Professional URL Management</h2>
|
||||
<p class="section-sub">A highly optimized architecture providing your organization with total ownership of internal and external links, operational data, and analytics.</p>
|
||||
<div class="grid-4" style="margin-bottom:1.5rem">
|
||||
<div class="card"><span class="card-icon">🔗</span><div class="card-title">URL Shortening</div><p class="card-desc">Create memorable URLs. Features include password protection, expirations, and elegant preview cards.</p></div>
|
||||
<div class="card"><span class="card-icon">📄</span><div class="card-title">Landing Pages</div><p class="card-desc">Host structured landing pages with built-in analytics, dynamic QR codes, and integrated domains.</p></div>
|
||||
<div class="card"><span class="card-icon">📊</span><div class="card-title">Analytics</div><p class="card-desc">Accurate visitor tracking encompassing browser metrics, referrers, and seamless CSV exports.</p></div>
|
||||
<div class="card"><span class="card-icon">🛡️</span><div class="card-title">Memory Safe</div><p class="card-desc">Engineered in Rust to fundamentally eliminate memory leaks, null pointers, and thread data races.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section id="architecture">
|
||||
<div class="container">
|
||||
<div class="eyebrow">System Architecture</div>
|
||||
<h2 class="section-title">High-Level Data Flow</h2>
|
||||
<p class="section-sub">A tenant-isolated structure pairing the Axum async framework with optimized SQLite database files, segregating content from high-volume analytics.</p>
|
||||
<div class="arch-wrap">
|
||||
<div>
|
||||
<div class="flow-diagram">
|
||||
<div><span class="fbox">Client Browser</span></div>
|
||||
<div class="farrow">↓ HTTP/REST</div>
|
||||
<div><span class="fbox" style="border-color:var(--a1)">Axum Routing Engine</span></div>
|
||||
<div class="farrow">↓ system.db lookup</div>
|
||||
<div><span class="fbox">Global Slug Registry</span></div>
|
||||
<div class="farrow">↓ Resolve Tenant</div>
|
||||
<div style="display:flex;justify-content:center;gap:1.5rem;margin:1rem 0">
|
||||
<div><div style="font-size:0.75rem;margin-bottom:0.25rem">URL Data</div><span class="fbox">content.db</span></div>
|
||||
<div><div style="font-size:0.75rem;margin-bottom:0.25rem">Tracking</div><span class="fbox">analytics.db</span></div>
|
||||
</div>
|
||||
<div class="farrow">↓ Write Event</div>
|
||||
<div><span class="fbox" style="border-color:var(--a3)">Audit Log (system.db)</span></div>
|
||||
<div class="farrow">↓</div>
|
||||
<div><span class="fbox">Response / Redirect</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="steps">
|
||||
<div class="step">
|
||||
<div class="step-n">1</div>
|
||||
<div><div class="step-title">Web Layer (Axum)</div><p style="color:var(--t2);font-size:.9rem;line-height:1.6">High-performance async HTTP server handling routing, middleware validation, CSRF protection, and structured error responses.</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-n">2</div>
|
||||
<div><div class="step-title">Global Namespace</div><p style="color:var(--t2);font-size:.9rem;line-height:1.6">All public URLs are tracked in the <code>system.db -> global_slugs</code> table to prevent collisions across different isolated users.</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-n">3</div>
|
||||
<div><div class="step-title">Analytics Pipeline</div><p style="color:var(--t2);font-size:.9rem;line-height:1.6">Lightweight, thread-safe tracking workers capture device profiles and traffic origins into tenant databases without degrading redirect speeds.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section id="databases">
|
||||
<div class="container">
|
||||
<div class="eyebrow">Storage Architecture</div>
|
||||
<h2 class="section-title">Strict Tenant Isolation</h2>
|
||||
<p class="section-sub">Instead of a monolithic database, BZOD securely segments administrative data from tenant analytics and content via dedicated SQLite files operating in WAL mode.</p>
|
||||
<div class="arch-wrap">
|
||||
<div>
|
||||
<div class="file-tree">
|
||||
data/<br>
|
||||
├── <span class="dir">admin/</span> <span class="comment"># Global Metadata</span><br>
|
||||
│ ├── <span class="file">admin.db</span> <span class="comment"># Internal management</span><br>
|
||||
│ ├── <span class="file">system.db</span> <span class="comment"># Global slugs & audit logs</span><br>
|
||||
│ └── <span class="file">users.db</span> <span class="comment"># Auth, sessions, quotas</span><br>
|
||||
│<br>
|
||||
└── <span class="dir">users/</span> <span class="comment"># Tenant Isolation</span><br>
|
||||
├── <span class="dir">1/</span> <span class="comment"># User 1</span><br>
|
||||
│ ├── <span class="file">analytics.db</span> <span class="comment"># Isolated metrics</span><br>
|
||||
│ └── <span class="file">content.db</span> <span class="comment"># Isolated URLs/Pages</span><br>
|
||||
│<br>
|
||||
└── <span class="dir">2/</span> <span class="comment"># User 2</span><br>
|
||||
├── <span class="file">analytics.db</span><br>
|
||||
└── <span class="file">content.db</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="steps">
|
||||
<div class="step">
|
||||
<div class="step-n">1</div>
|
||||
<div><div class="step-title">No Cross-Tenant Bleed</div><p style="color:var(--t2);font-size:.9rem;line-height:1.6">By assigning physical <code>content.db</code> and <code>analytics.db</code> files to each user, cross-user data leakage is eliminated at the file-system level.</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-n">2</div>
|
||||
<div><div class="step-title">Identity & Quotas</div><p style="color:var(--t2);font-size:.9rem;line-height:1.6">The centralized <code>users.db</code> acts as the primary identity database, securely tracking authentication, API tokens, and enforcing resource quotas.</p></div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-n">3</div>
|
||||
<div><div class="step-title">WAL Concurrency</div><p style="color:var(--t2);font-size:.9rem;line-height:1.6">Write-Ahead Logging provides robust concurrency and zero-contention crash recovery without the operational overhead of PostgreSQL.</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section id="api">
|
||||
<div class="container">
|
||||
<div class="eyebrow">REST API</div>
|
||||
<h2 class="section-title">Programmatic Access</h2>
|
||||
<p class="section-sub">Integrate BZOD with CI/CD pipelines, home automation, or custom applications using secure, token-based authentication.</p>
|
||||
<div class="grid-2">
|
||||
<div>
|
||||
<h3 style="font-size:1rem;font-weight:600;margin-bottom:1rem;color:var(--t1)">Create a Short URL</h3>
|
||||
<pre class="cb"><span class="kw">POST</span> /api/v1/urls
|
||||
Authorization: Bearer bzo_xxxxxxxxxxxx
|
||||
|
||||
{
|
||||
<span class="str">"code"</span>: <span class="str">"rust"</span>,
|
||||
<span class="str">"target_url"</span>: <span class="str">"https://www.rust-lang.org"</span>,
|
||||
<span class="str">"description"</span>: <span class="str">"Rust Language"</span>
|
||||
}</pre>
|
||||
</div>
|
||||
<div>
|
||||
<h3 style="font-size:1rem;font-weight:600;margin-bottom:1rem;color:var(--t1)">Fetch Global Statistics</h3>
|
||||
<pre class="cb"><span class="kw">GET</span> /api/v1/stats
|
||||
Authorization: Bearer bzo_xxxxxxxxxxxx
|
||||
|
||||
{
|
||||
<span class="str">"success"</span>: true,
|
||||
<span class="str">"data"</span>: {
|
||||
<span class="str">"total_urls"</span>: 125,
|
||||
<span class="str">"total_clicks"</span>: 8431,
|
||||
<span class="str">"total_pages"</span>: 12
|
||||
}
|
||||
.hero-bg {
|
||||
background: linear-gradient(135deg, #1a1a2e 0%, #0f0f1e 100%);
|
||||
}</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section id="cli">
|
||||
<div class="container">
|
||||
<div class="eyebrow">Operations & CLI</div>
|
||||
<h2 class="section-title">Built for Systems Administrators</h2>
|
||||
<p class="section-sub">Full control via a comprehensive command-line interface. Handle migrations, disaster recovery, and user management directly from the terminal.</p>
|
||||
<div class="tab-shell">
|
||||
<div class="tab-strip">
|
||||
<button class="tab-btn on" onclick="switchTab(event, 'cli-backup')">Backup & Restore</button>
|
||||
<button class="tab-btn" onclick="switchTab(event, 'cli-users')">User Management</button>
|
||||
<button class="tab-btn" onclick="switchTab(event, 'cli-diag')">Diagnostics</button>
|
||||
</div>
|
||||
<div id="cli-backup" class="tab-panel on">
|
||||
<pre class="cb"><span class="cm"># Create a full compressed snapshot of the entire platform</span>
|
||||
<span class="kw">bzod</span> backup
|
||||
|
||||
<span class="cm"># Restore platform from a specific archive</span>
|
||||
<span class="kw">bzod</span> restore backup-20260619-020000.zip
|
||||
|
||||
<span class="cm"># Backup and export only a single tenant's data</span>
|
||||
<span class="kw">bzod</span> backup-user 42</pre>
|
||||
</div>
|
||||
<div id="cli-users" class="tab-panel">
|
||||
<pre class="cb"><span class="cm"># Bootstrap a new administrator</span>
|
||||
<span class="kw">bzod</span> create-admin admin
|
||||
|
||||
<span class="cm"># Provision a new standard user</span>
|
||||
<span class="kw">bzod</span> create-user alice
|
||||
|
||||
<span class="cm"># Immediately invalidate user sessions and prevent login</span>
|
||||
<span class="kw">bzod</span> disable-user alice</pre>
|
||||
</div>
|
||||
<div id="cli-diag" class="tab-panel">
|
||||
<pre class="cb"><span class="cm"># Run SQLite integrity checks, WAL validation, and storage checks</span>
|
||||
<span class="kw">bzod</span> doctor
|
||||
|
||||
<span class="cm"># Verify all registered short link destinations exist</span>
|
||||
<span class="kw">bzod</span> validate
|
||||
|
||||
<span class="cm"># Apply schema upgrades safely</span>
|
||||
<span class="kw">bzod</span> migrate</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section id="compare">
|
||||
<div class="container">
|
||||
<div class="eyebrow">Market Comparison</div>
|
||||
<h2 class="section-title">How BZOD Compares</h2>
|
||||
<p class="section-sub">Unlike standard shorteners, BZOD provides a comprehensive suite of features—from landing pages to multi-tenant user isolation—in a single, compiled binary.</p>
|
||||
|
||||
<table class="compare-tbl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Feature</th>
|
||||
<th>BZOD v0.5.0</th>
|
||||
<th>Shlink</th>
|
||||
<th>YOURLS</th>
|
||||
<th>Chhoto URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Language</td>
|
||||
<td>Rust 🦀</td>
|
||||
<td>PHP</td>
|
||||
<td>PHP</td>
|
||||
<td>Rust</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deployment</td>
|
||||
<td><span class="check-yes">✅ Single Binary</span></td>
|
||||
<td><span class="check-no">❌ Requires PHP/Web Server</span></td>
|
||||
<td><span class="check-no">❌ Requires PHP/Web Server</span></td>
|
||||
<td><span class="check-yes">✅ Single Binary</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>External DB Required</td>
|
||||
<td><span class="check-yes">✅ None (SQLite)</span></td>
|
||||
<td><span class="check-partial">⚠️ Usually (PostgreSQL/Maria)</span></td>
|
||||
<td><span class="check-partial">⚠️ Usually (MySQL)</span></td>
|
||||
<td><span class="check-yes">✅ None</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Landing Pages</td>
|
||||
<td><span class="check-yes">✅ Native</span></td>
|
||||
<td><span class="check-no">❌ No</span></td>
|
||||
<td><span class="check-partial">⚠️ Via Plugin</span></td>
|
||||
<td><span class="check-no">❌ No</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>QR + Analytics</td>
|
||||
<td><span class="check-yes">✅ Native</span></td>
|
||||
<td><span class="check-partial">⚠️ Partial</span></td>
|
||||
<td><span class="check-partial">⚠️ Via Plugin</span></td>
|
||||
<td><span class="check-partial">⚠️ Partial</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multi-User / Quotas</td>
|
||||
<td><span class="check-yes">✅ Native (Isolated)</span></td>
|
||||
<td><span class="check-partial">⚠️ Partial</span></td>
|
||||
<td><span class="check-partial">⚠️ Via Plugin</span></td>
|
||||
<td><span class="check-no">❌ No</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Backup & Recovery</td>
|
||||
<td><span class="check-yes">✅ Built-in CLI & Web UI</span></td>
|
||||
<td><span class="check-no">❌ External Tools Needed</span></td>
|
||||
<td><span class="check-no">❌ External Tools Needed</span></td>
|
||||
<td><span class="check-no">❌ No</span></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="divider"></div>
|
||||
|
||||
<section id="install">
|
||||
<div class="container">
|
||||
<div class="eyebrow">Deployment</div>
|
||||
<h2 class="section-title">Get Started in Minutes</h2>
|
||||
<p class="section-sub">Deploy via Docker for containerized environments, or compile directly from source for bare-metal performance.</p>
|
||||
<div class="tab-shell">
|
||||
<div class="tab-strip">
|
||||
<button class="tab-btn on" onclick="switchTab(event, 'install-docker')">Docker Compose</button>
|
||||
<button class="tab-btn" onclick="switchTab(event, 'install-native')">Native Binary</button>
|
||||
</div>
|
||||
<div id="install-docker" class="tab-panel on">
|
||||
<pre class="cb"><span class="cm"># Clone the official repository</span>
|
||||
<span class="kw">git</span> clone https://github.com/thakares/nx9-url-shortener bzod
|
||||
<span class="kw">cd</span> bzod
|
||||
|
||||
<span class="cm"># Launch containerized services</span>
|
||||
<span class="kw">docker compose</span> up -d --build
|
||||
|
||||
<span class="cm"># Initialize base admin</span>
|
||||
<span class="kw">docker exec</span> -it bzod bzod create-admin</pre>
|
||||
</div>
|
||||
<div id="install-native" class="tab-panel">
|
||||
<pre class="cb"><span class="cm"># Clone the official repository</span>
|
||||
<span class="kw">git</span> clone https://github.com/thakares/nx9-url-shortener bzod
|
||||
<span class="kw">cd</span> bzod
|
||||
|
||||
<span class="cm"># Compile optimized release</span>
|
||||
<span class="kw">cargo</span> build --release
|
||||
|
||||
<span class="cm"># Initialize base admin</span>
|
||||
./target/release/bzod create-admin
|
||||
|
||||
<span class="cm"># Serve application</span>
|
||||
./target/release/bzod serve</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<div class="footer-grid">
|
||||
<div>
|
||||
<div class="footer-brand">
|
||||
<div class="logo-box" style="width:28px;height:28px;font-size:.75rem">BZ</div>
|
||||
BZOD
|
||||
</div>
|
||||
<p class="footer-about">A streamlined, self-hosted multi-user URL management platform written in Rust. Retain absolute sovereignty over your digital links.</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class="footer-col-title">Platform</div>
|
||||
<ul class="footer-links">
|
||||
<li><a href="#features">Features Overview</a></li>
|
||||
<li><a href="#architecture">Architecture</a></li>
|
||||
<li><a href="#install">Installation</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div class="footer-col-title">Access</div>
|
||||
<ul class="footer-links">
|
||||
<li><a href="./login">User Login</a></li>
|
||||
<li><a href="./admin">Admin Panel</a></li>
|
||||
<li><a href="#api">API Documentation</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<div class="footer-col-title">Repositories</div>
|
||||
<ul class="footer-links">
|
||||
<li><a href="https://github.com/thakares/nx9-url-shortener" target="_blank">GitHub</a></li>
|
||||
<li><a href="https://codeberg.org/thakares/nx9-url-shortener" target="_blank">CodeBerg</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer-bottom">
|
||||
<span>© 2026 BZOD. Dual licensed under GPLv3 and Commercial License.</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="./index_files/lucide@latest"></script>
|
||||
<script>
|
||||
lucide.createIcons();
|
||||
|
||||
function switchTab(e, tabName) {
|
||||
const shell = e.currentTarget.closest('.tab-shell');
|
||||
const tabs = shell.querySelectorAll('.tab-panel');
|
||||
const btns = shell.querySelectorAll('.tab-btn');
|
||||
|
||||
tabs.forEach(tab => tab.classList.remove('on'));
|
||||
btns.forEach(btn => btn.classList.remove('on'));
|
||||
|
||||
document.getElementById(tabName).classList.add('on');
|
||||
e.currentTarget.classList.add('on');
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-zinc-950 text-zinc-200">
|
||||
<!-- Hero -->
|
||||
<section class="hero-bg py-24">
|
||||
<div class="max-w-5xl mx-auto px-6 text-center">
|
||||
<div
|
||||
class="inline-flex items-center gap-2 bg-zinc-900 border border-zinc-700 rounded-full px-4 py-1.5 mb-6"
|
||||
>
|
||||
<span class="text-emerald-400">●</span>
|
||||
<span class="text-sm font-medium"
|
||||
>Self-hosted • Rust • Single Binary</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<h1
|
||||
class="text-6xl md:text-7xl font-bold tracking-tighter mb-6"
|
||||
>
|
||||
Short links.<br />
|
||||
<span
|
||||
class="bg-gradient-to-r from-violet-400 to-fuchsia-400 bg-clip-text text-transparent"
|
||||
>Your domain.</span
|
||||
>
|
||||
</h1>
|
||||
function toggleFaq(e) {
|
||||
const item = e.currentTarget.closest('.faq-item');
|
||||
const content = item.querySelector('.faq-a');
|
||||
|
||||
<p class="text-2xl text-zinc-400 max-w-2xl mx-auto mb-10">
|
||||
Beautiful, private, and powerful URL shortener with rich
|
||||
landing pages, QR codes, analytics, and full CLI control.
|
||||
</p>
|
||||
|
||||
<div class="flex flex-wrap justify-center gap-4">
|
||||
<a
|
||||
href="https://github.com/thakares/nx9-url-shortener"
|
||||
target="_blank"
|
||||
class="bg-white text-black px-8 py-4 rounded-2xl font-semibold flex items-center gap-3 hover:scale-105 transition"
|
||||
>
|
||||
<i class="fab fa-github text-xl"></i>
|
||||
View on GitHub
|
||||
</a>
|
||||
<a
|
||||
href="/admin"
|
||||
class="bg-violet-600 hover:bg-violet-700 px-8 py-4 rounded-2xl font-semibold transition"
|
||||
>
|
||||
Admin Dashboard →
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="mt-16 text-sm text-zinc-500">
|
||||
Powered by
|
||||
<span class="font-mono text-emerald-400">bzo.in</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Highlights -->
|
||||
<div class="max-w-6xl mx-auto px-6 -mt-10 relative z-10">
|
||||
<div
|
||||
class="grid grid-cols-2 lg:grid-cols-5 bg-zinc-950/70 backdrop-blur-md border border-zinc-800 rounded-3xl overflow-hidden"
|
||||
>
|
||||
<!-- Single Binary -->
|
||||
<div
|
||||
class="p-8 text-center border-b lg:border-b-0 lg:border-r border-zinc-800"
|
||||
>
|
||||
<i
|
||||
class="fas fa-bolt text-emerald-400 text-4xl mb-4"
|
||||
></i>
|
||||
<h3 class="font-semibold text-xl mb-2">
|
||||
Single Binary
|
||||
</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
~18 MB Rust binary.<br />
|
||||
No runtime required.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- SQLite -->
|
||||
<div
|
||||
class="p-8 text-center border-b lg:border-b-0 lg:border-r border-zinc-800"
|
||||
>
|
||||
<i
|
||||
class="fas fa-database text-emerald-400 text-4xl mb-4"
|
||||
></i>
|
||||
<h3 class="font-semibold text-xl mb-2">SQLite</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
Zero configuration.<br />
|
||||
WAL mode enabled.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- REST API -->
|
||||
<div
|
||||
class="p-8 text-center border-b lg:border-b-0 lg:border-r border-zinc-800"
|
||||
>
|
||||
<i
|
||||
class="fas fa-code text-emerald-400 text-4xl mb-4"
|
||||
></i>
|
||||
<h3 class="font-semibold text-xl mb-2">REST API</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
Full automation.<br />
|
||||
JSON everywhere.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Self Hosted -->
|
||||
<div
|
||||
class="p-8 text-center border-b lg:border-b-0 lg:border-r border-zinc-800"
|
||||
>
|
||||
<i
|
||||
class="fas fa-server text-emerald-400 text-4xl mb-4"
|
||||
></i>
|
||||
<h3 class="font-semibold text-xl mb-2">Self Hosted</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
Your links.<br />
|
||||
Your infrastructure.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- MIT -->
|
||||
<div class="p-8 text-center">
|
||||
<i
|
||||
class="fas fa-shield-alt text-emerald-400 text-4xl mb-4"
|
||||
></i>
|
||||
<h3 class="font-semibold text-xl mb-2">MIT License</h3>
|
||||
<p class="text-zinc-400 text-sm">
|
||||
Open source.<br />
|
||||
Commercial friendly.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Install -->
|
||||
<section class="hero-bg py-24">
|
||||
<div class="max-w-4xl mx-auto px-6 text-center">
|
||||
<h2 class="text-4xl font-bold mb-4">Install BZOD</h2>
|
||||
|
||||
<p class="text-zinc-400 mb-10">
|
||||
Deploy on any Debian/Ubuntu VPS, homelab, mini-PC, or
|
||||
Raspberry Pi.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div class="bg-black max-w-6xl mx-auto px-6 -mt-10 relative z-10 rounded-3xl overflow-hidden">
|
||||
<div
|
||||
class="flex items-center justify-between px-5 py-3 border-b border-zinc-800"
|
||||
>
|
||||
<span class="text-zinc-500 text-sm">
|
||||
Downloads the latest release and installs BZOD as a systemd
|
||||
service. Linux Installation
|
||||
</span>
|
||||
<button
|
||||
onclick="copyInstallCommand()"
|
||||
class="text-sm bg-violet-600 hover:bg-violet-700 px-4 py-2 rounded-lg transition"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
<pre
|
||||
class="text-left overflow-x-auto p-6 text-emerald-400 font-mono text-sm"
|
||||
><code id="install-command">curl -fsSL https://bzo.in/deploy.sh | sudo bash</code></pre>
|
||||
</div>
|
||||
<script>
|
||||
function copyInstallCommand() {
|
||||
const text = "curl -fsSL https://bzo.in/deploy.sh | sudo bash";
|
||||
|
||||
navigator.clipboard.writeText(text);
|
||||
|
||||
const btn = event.target;
|
||||
const old = btn.innerText;
|
||||
|
||||
btn.innerText = "Copied!";
|
||||
setTimeout(() => {
|
||||
btn.innerText = old;
|
||||
}, 2000);
|
||||
if(item.classList.contains('open')){
|
||||
item.classList.remove('open');
|
||||
content.style.display = 'none';
|
||||
} else {
|
||||
item.classList.add('open');
|
||||
content.style.display = 'block';
|
||||
}
|
||||
</script>
|
||||
</section>
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Features -->
|
||||
<section class="py-20 bg-zinc-900">
|
||||
<div class="max-w-5xl mx-auto px-6">
|
||||
<h2 class="text-4xl font-bold text-center mb-16">
|
||||
Why people love BZOD
|
||||
</h2>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-8">
|
||||
<div
|
||||
class="bg-zinc-950 border border-zinc-800 rounded-3xl p-8"
|
||||
>
|
||||
<div class="text-4xl mb-6">⚡</div>
|
||||
<h3 class="text-2xl font-semibold mb-3">
|
||||
Lightning Fast
|
||||
</h3>
|
||||
<p class="text-zinc-400">
|
||||
~18 MB single Rust binary. Starts instantly. Uses
|
||||
SQLite with WAL mode. Minimal resource usage.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-zinc-950 border border-zinc-800 rounded-3xl p-8"
|
||||
>
|
||||
<div class="text-4xl mb-6">🔒</div>
|
||||
<h3 class="text-2xl font-semibold mb-3">
|
||||
Private by Design
|
||||
</h3>
|
||||
<p class="text-zinc-400">
|
||||
No telemetry. No third-party services. Everything
|
||||
runs on your server. Strong password hashing & audit
|
||||
logs.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-zinc-950 border border-zinc-800 rounded-3xl p-8"
|
||||
>
|
||||
<div class="text-4xl mb-6">🎨</div>
|
||||
<h3 class="text-2xl font-semibold mb-3">
|
||||
Beautiful Links
|
||||
</h3>
|
||||
<p class="text-zinc-400">
|
||||
Rich custom landing pages with title, description,
|
||||
OG metadata, and branded preview.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid md:grid-cols-3 gap-8 mt-8">
|
||||
<div
|
||||
class="bg-zinc-950 border border-zinc-800 rounded-3xl p-8"
|
||||
>
|
||||
<div class="text-4xl mb-6">📱</div>
|
||||
<h3 class="text-2xl font-semibold mb-3">
|
||||
QR Codes Built-in
|
||||
</h3>
|
||||
<p class="text-zinc-400">
|
||||
Generate PNG & SVG QR codes. Track scans separately
|
||||
in analytics.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-zinc-950 border border-zinc-800 rounded-3xl p-8"
|
||||
>
|
||||
<div class="text-4xl mb-6">🛠️</div>
|
||||
<h3 class="text-2xl font-semibold mb-3">CLI First</h3>
|
||||
<p class="text-zinc-400">
|
||||
backup, restore, doctor, stats, validate,
|
||||
create-admin — everything from terminal.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="bg-zinc-950 border border-zinc-800 rounded-3xl p-8"
|
||||
>
|
||||
<div class="text-4xl mb-6">🔑</div>
|
||||
<h3 class="text-2xl font-semibold mb-3">
|
||||
Powerful Features
|
||||
</h3>
|
||||
<p class="text-zinc-400">
|
||||
Password protection • Expiry • Access limits • Tags
|
||||
• REST API • Bulk QR export
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA -->
|
||||
<section class="py-20 bg-black border-t border-zinc-800">
|
||||
<div class="max-w-2xl mx-auto text-center px-6">
|
||||
<h2 class="text-4xl font-bold mb-6">
|
||||
Ready to own your short links?
|
||||
</h2>
|
||||
<p class="text-zinc-400 mb-10">
|
||||
Self-host BZOD in under 5 minutes on any VPS, homelab, or
|
||||
even a Raspberry Pi.
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
||||
<a
|
||||
href="https://github.com/thakares/nx9-url-shortener"
|
||||
target="_blank"
|
||||
class="bg-white text-black px-10 py-4 rounded-2xl font-semibold text-lg"
|
||||
>
|
||||
Get BZOD Now
|
||||
</a>
|
||||
<a
|
||||
href="/admin"
|
||||
class="border border-zinc-700 hover:bg-zinc-900 px-10 py-4 rounded-2xl font-semibold text-lg transition"
|
||||
>
|
||||
Open Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="bg-zinc-950 py-12 border-t border-zinc-800">
|
||||
<div
|
||||
class="max-w-5xl mx-auto px-6 text-center text-zinc-500 text-sm"
|
||||
>
|
||||
© 2026 BZOD • Made with ❤️ in Rust by Sunil Purushottam Thakare
|
||||
• Running on <span class="font-mono">bzo.in</span>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
</body></html>
|
||||
Reference in new issue
Block a user