diff --git a/containers/libreportal/frontend/css/ssh.css b/containers/libreportal/frontend/css/ssh.css index 965f3d6..4ea7d31 100644 --- a/containers/libreportal/frontend/css/ssh.css +++ b/containers/libreportal/frontend/css/ssh.css @@ -2,9 +2,7 @@ backup.css for the cards; this file only adds page chrome + the key list. */ .ssh-page { - max-width: 860px; - margin: 0 auto; - padding: 8px 4px 40px; + padding: 4px 2px 40px; } /* "Tools" group heading in the Admin (config) sidebar, above SSH Access. */ diff --git a/site/dist/assets/apps/adguard.svg b/site/dist/assets/apps/adguard.svg new file mode 100644 index 0000000..f6118fc --- /dev/null +++ b/site/dist/assets/apps/adguard.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/authelia.svg b/site/dist/assets/apps/authelia.svg new file mode 100644 index 0000000..9880b3b --- /dev/null +++ b/site/dist/assets/apps/authelia.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/bookstack.svg b/site/dist/assets/apps/bookstack.svg new file mode 100644 index 0000000..a6ad581 --- /dev/null +++ b/site/dist/assets/apps/bookstack.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/crowdsec.svg b/site/dist/assets/apps/crowdsec.svg new file mode 100644 index 0000000..fd4ffac --- /dev/null +++ b/site/dist/assets/apps/crowdsec.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/site/dist/assets/apps/dashy.svg b/site/dist/assets/apps/dashy.svg new file mode 100644 index 0000000..ce68744 --- /dev/null +++ b/site/dist/assets/apps/dashy.svg @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/site/dist/assets/apps/default.svg b/site/dist/assets/apps/default.svg new file mode 100644 index 0000000..343d2de --- /dev/null +++ b/site/dist/assets/apps/default.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/focalboard.svg b/site/dist/assets/apps/focalboard.svg new file mode 100644 index 0000000..b78e7e3 --- /dev/null +++ b/site/dist/assets/apps/focalboard.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/gitea.svg b/site/dist/assets/apps/gitea.svg new file mode 100644 index 0000000..11c6df8 --- /dev/null +++ b/site/dist/assets/apps/gitea.svg @@ -0,0 +1,4 @@ + + + + diff --git a/site/dist/assets/apps/gluetun.svg b/site/dist/assets/apps/gluetun.svg new file mode 100644 index 0000000..a39521c --- /dev/null +++ b/site/dist/assets/apps/gluetun.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/site/dist/assets/apps/grafana.svg b/site/dist/assets/apps/grafana.svg new file mode 100644 index 0000000..54be1e2 --- /dev/null +++ b/site/dist/assets/apps/grafana.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + diff --git a/site/dist/assets/apps/headscale.svg b/site/dist/assets/apps/headscale.svg new file mode 100644 index 0000000..06f406a --- /dev/null +++ b/site/dist/assets/apps/headscale.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/invidious.svg b/site/dist/assets/apps/invidious.svg new file mode 100644 index 0000000..80e78a4 --- /dev/null +++ b/site/dist/assets/apps/invidious.svg @@ -0,0 +1,2 @@ + + diff --git a/site/dist/assets/apps/ipinfo.svg b/site/dist/assets/apps/ipinfo.svg new file mode 100644 index 0000000..656169c --- /dev/null +++ b/site/dist/assets/apps/ipinfo.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/jellyfin.svg b/site/dist/assets/apps/jellyfin.svg new file mode 100644 index 0000000..0e56a50 --- /dev/null +++ b/site/dist/assets/apps/jellyfin.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/jitsimeet.svg b/site/dist/assets/apps/jitsimeet.svg new file mode 100644 index 0000000..5a3526a --- /dev/null +++ b/site/dist/assets/apps/jitsimeet.svg @@ -0,0 +1,650 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/site/dist/assets/apps/libreportal.svg b/site/dist/assets/apps/libreportal.svg new file mode 100644 index 0000000..a476796 --- /dev/null +++ b/site/dist/assets/apps/libreportal.svg @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/dist/assets/apps/linkding.svg b/site/dist/assets/apps/linkding.svg new file mode 100644 index 0000000..089630d --- /dev/null +++ b/site/dist/assets/apps/linkding.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/mastodon.svg b/site/dist/assets/apps/mastodon.svg new file mode 100644 index 0000000..dd5075e --- /dev/null +++ b/site/dist/assets/apps/mastodon.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/nextcloud.svg b/site/dist/assets/apps/nextcloud.svg new file mode 100644 index 0000000..336aff5 --- /dev/null +++ b/site/dist/assets/apps/nextcloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/site/dist/assets/apps/ollama.svg b/site/dist/assets/apps/ollama.svg new file mode 100644 index 0000000..6bba73a --- /dev/null +++ b/site/dist/assets/apps/ollama.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/onlyoffice.svg b/site/dist/assets/apps/onlyoffice.svg new file mode 100644 index 0000000..364522c --- /dev/null +++ b/site/dist/assets/apps/onlyoffice.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/owncloud.svg b/site/dist/assets/apps/owncloud.svg new file mode 100644 index 0000000..cf650c7 --- /dev/null +++ b/site/dist/assets/apps/owncloud.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/pihole.svg b/site/dist/assets/apps/pihole.svg new file mode 100644 index 0000000..5bda461 --- /dev/null +++ b/site/dist/assets/apps/pihole.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/portainer.svg b/site/dist/assets/apps/portainer.svg new file mode 100644 index 0000000..45cf83a --- /dev/null +++ b/site/dist/assets/apps/portainer.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/prometheus.svg b/site/dist/assets/apps/prometheus.svg new file mode 100644 index 0000000..309d704 --- /dev/null +++ b/site/dist/assets/apps/prometheus.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/searxng.svg b/site/dist/assets/apps/searxng.svg new file mode 100644 index 0000000..2ddf53b --- /dev/null +++ b/site/dist/assets/apps/searxng.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/speedtest.svg b/site/dist/assets/apps/speedtest.svg new file mode 100644 index 0000000..2fd0d2b --- /dev/null +++ b/site/dist/assets/apps/speedtest.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/traefik.svg b/site/dist/assets/apps/traefik.svg new file mode 100644 index 0000000..a86b9b7 --- /dev/null +++ b/site/dist/assets/apps/traefik.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/trilium.svg b/site/dist/assets/apps/trilium.svg new file mode 100644 index 0000000..2ecb6e4 --- /dev/null +++ b/site/dist/assets/apps/trilium.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/unbound.svg b/site/dist/assets/apps/unbound.svg new file mode 100644 index 0000000..cfc5d8d --- /dev/null +++ b/site/dist/assets/apps/unbound.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/vaultwarden.svg b/site/dist/assets/apps/vaultwarden.svg new file mode 100644 index 0000000..41ca105 --- /dev/null +++ b/site/dist/assets/apps/vaultwarden.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/apps/wireguard.svg b/site/dist/assets/apps/wireguard.svg new file mode 100644 index 0000000..b778001 --- /dev/null +++ b/site/dist/assets/apps/wireguard.svg @@ -0,0 +1 @@ + diff --git a/site/dist/assets/favicon.ico b/site/dist/assets/favicon.ico new file mode 100644 index 0000000..622f2d3 Binary files /dev/null and b/site/dist/assets/favicon.ico differ diff --git a/site/dist/assets/libreportal.svg b/site/dist/assets/libreportal.svg new file mode 100644 index 0000000..a476796 --- /dev/null +++ b/site/dist/assets/libreportal.svg @@ -0,0 +1,605 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/site/dist/assets/main.js b/site/dist/assets/main.js new file mode 100644 index 0000000..d9dda04 --- /dev/null +++ b/site/dist/assets/main.js @@ -0,0 +1,66 @@ +// LibrePortal site — interactions (mobile drawer, copy, scrollspy, reveal, app filter) +(() => { + // mobile drawer (same behaviour as the dashboard) + const menuToggle = document.getElementById('mobile-menu-toggle'); + const drawer = document.getElementById('mobile-drawer'); + if (menuToggle && drawer) { + menuToggle.addEventListener('click', () => { + const open = drawer.classList.toggle('mobile-open'); + document.body.style.overflow = open ? 'hidden' : ''; + }); + drawer.querySelectorAll('a').forEach((a) => + a.addEventListener('click', () => { drawer.classList.remove('mobile-open'); document.body.style.overflow = ''; })); + } + + // copy the install command + const cmdEl = document.querySelector('[data-install-cmd]'); + const CMD = cmdEl ? cmdEl.getAttribute('data-install-cmd') : ''; + document.querySelectorAll('.copy').forEach((btn) => { + btn.addEventListener('click', async () => { + try { await navigator.clipboard.writeText(CMD); } + catch { const t = document.createElement('textarea'); t.value = CMD; document.body.appendChild(t); t.select(); document.execCommand('copy'); t.remove(); } + btn.classList.add('done'); + const span = btn.querySelector('span'); const prev = span.textContent; span.textContent = 'Copied ✓'; + setTimeout(() => { btn.classList.remove('done'); span.textContent = prev; }, 1700); + }); + }); + + // scrollspy → light up the active topbar pill + const spies = [...document.querySelectorAll('.nav-item[data-spy]')]; + if (spies.length) { + const spyIO = new IntersectionObserver((entries) => { + entries.forEach((e) => { + if (e.isIntersecting) spies.forEach((s) => s.classList.toggle('nav-active', s.dataset.spy === e.target.id)); + }); + }, { rootMargin: '-45% 0px -50% 0px', threshold: 0 }); + spies.map((s) => document.getElementById(s.dataset.spy)).filter(Boolean).forEach((s) => spyIO.observe(s)); + } + + // reveal on scroll + const io = new IntersectionObserver((entries) => { + entries.forEach((e) => { if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); } }); + }, { threshold: 0.16, rootMargin: '0px 0px -8% 0px' }); + document.querySelectorAll('.reveal, .stagger').forEach((el) => io.observe(el)); + + // app category filter + const filters = document.querySelector('.app-filters'); + if (filters) { + const cards = [...document.querySelectorAll('.app-card')]; + const countEl = document.querySelector('.app-count'); + const update = (cat) => { + let shown = 0; + cards.forEach((c) => { + const match = cat === 'all' || (c.dataset.cats || '').split(' ').includes(cat); + c.classList.toggle('hidden', !match); + if (match) shown++; + }); + if (countEl) countEl.textContent = `${shown} app${shown === 1 ? '' : 's'}`; + }; + filters.addEventListener('click', (e) => { + const chip = e.target.closest('.chip'); + if (!chip) return; + filters.querySelectorAll('.chip').forEach((c) => c.classList.toggle('active', c === chip)); + update(chip.dataset.cat); + }); + } +})(); diff --git a/site/dist/assets/style.css b/site/dist/assets/style.css new file mode 100644 index 0000000..c187888 --- /dev/null +++ b/site/dist/assets/style.css @@ -0,0 +1,276 @@ +/* ============ NEBULA THEME (lifted from the dashboard) ============ */ +:root{ + --gradient-from:#1a1442; /* indigo */ + --gradient-mid:#1b2a5e; /* violet-blue */ + --gradient-to:#0f3b6e; /* ocean */ + --surface-solid:#0f1729; + + --accent:#00d4ff; + --accent-hover:#0099cc; + --accent-rgb:0,212,255; + --accent-soft:rgba(0,212,255,.15); + + --text-primary:#ffffff; + --text-secondary:rgba(255,255,255,.82); + --text-muted:rgba(255,255,255,.65); + --text-faint:rgba(255,255,255,.45); + --text-on-accent:#0a1426; + --text-rgb:255,255,255; + + --border:rgba(255,255,255,.16); + --border-strong:rgba(255,255,255,.26); + --border-subtle:rgba(255,255,255,.08); + + --card-bg:linear-gradient(155deg, rgba(255,255,255,.09) 0%, rgba(0,212,255,.05) 100%); + --card-border:rgba(255,255,255,.16); + --card-shadow:0 4px 18px rgba(0,0,0,.30), inset 0 1px 0 rgba(255,255,255,.06); + --card-shadow-hover:0 10px 32px rgba(0,212,255,.18), 0 4px 18px rgba(0,0,0,.40), inset 0 1px 0 rgba(255,255,255,.10); + + --topbar-bg:rgba(15,25,50,.40); + --console-bg:rgba(0,0,0,.40); + --surface-bg-solid:#0f1729; + + --font-sans:-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; + --font-mono:"SF Mono", "Monaco", "Menlo", "Ubuntu Mono", "Courier New", monospace; + + --maxw:1180px; + --ease:cubic-bezier(.22,.61,.36,1); +} + +*{box-sizing:border-box;margin:0;padding:0} +html{scroll-behavior:smooth} +body{font-family:var(--font-sans);background:var(--surface-solid);color:var(--text-primary); + line-height:1.6;overflow-x:hidden;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility} + +/* ============ AURORA BACKDROP (from aurora-background.css) ============ */ +.cosmos{position:fixed;inset:0;z-index:-2;pointer-events:none;overflow:hidden; + background: + radial-gradient(ellipse at 20% 22%, var(--gradient-mid) 0%, transparent 55%), + radial-gradient(ellipse at 82% 74%, var(--gradient-to) 0%, transparent 55%), + linear-gradient(135deg, var(--gradient-from) 0%, var(--gradient-from) 40%, var(--gradient-mid) 100%);} +.cosmos::before{content:'';position:absolute;inset:-25%; + background:conic-gradient(from 0deg at 50% 50%, + rgba(var(--accent-rgb),0) 0deg, rgba(var(--accent-rgb),.18) 60deg, + rgba(var(--accent-rgb),.22) 130deg, rgba(var(--accent-rgb),.20) 200deg, + rgba(var(--accent-rgb),.18) 280deg, rgba(var(--accent-rgb),0) 360deg); + filter:blur(70px);animation:auroraSpin 38s linear infinite;} +.cosmos::after{content:'';position:absolute;inset:-10%; + background: + radial-gradient(circle at 18% 22%, rgba(var(--accent-rgb),.38) 0%, transparent 35%), + radial-gradient(circle at 78% 18%, rgba(var(--accent-rgb),.32) 0%, transparent 32%), + radial-gradient(circle at 30% 80%, rgba(var(--accent-rgb),.30) 0%, transparent 38%), + radial-gradient(circle at 84% 82%, rgba(var(--accent-rgb),.34) 0%, transparent 36%), + radial-gradient(circle at 50% 50%, rgba(var(--accent-rgb),.14) 0%, transparent 50%); + filter:blur(50px);animation:auroraDrift 22s ease-in-out infinite alternate;} +.stars{position:fixed;inset:0;z-index:-1;pointer-events:none} +.stars::before,.stars::after{content:'';position:absolute;inset:0;background-repeat:repeat} +.stars::before{background-image: + radial-gradient(1.5px 1.5px at 12px 18px, rgba(var(--text-rgb),.9), transparent 60%), + radial-gradient(1px 1px at 47px 92px, rgba(var(--accent-rgb),.85), transparent 60%), + radial-gradient(1.2px 1.2px at 110px 40px, rgba(var(--text-rgb),.75), transparent 60%), + radial-gradient(1px 1px at 165px 130px, rgba(var(--accent-rgb),.7), transparent 60%); + background-size:200px 200px;animation:auroraTwinkleA 4.5s ease-in-out infinite;} +.stars::after{background-image: + radial-gradient(1px 1px at 30px 60px, rgba(var(--accent-rgb),.8), transparent 60%), + radial-gradient(1.4px 1.4px at 88px 22px, rgba(var(--text-rgb),.7), transparent 60%), + radial-gradient(1px 1px at 140px 100px, rgba(var(--accent-rgb),.85), transparent 60%), + radial-gradient(1.2px 1.2px at 195px 70px, rgba(var(--text-rgb),.6), transparent 60%); + background-size:240px 240px;background-position:80px 50px;animation:auroraTwinkleB 6.5s ease-in-out infinite;} +@keyframes auroraSpin{to{transform:rotate(360deg)}} +@keyframes auroraDrift{0%{transform:translate(0,0) scale(1);opacity:.85}50%{transform:translate(-3%,4%) scale(1.08);opacity:1}100%{transform:translate(2%,-3%) scale(.95);opacity:.9}} +@keyframes auroraTwinkleA{0%,100%{opacity:.55}50%{opacity:1}} +@keyframes auroraTwinkleB{0%,100%{opacity:1}50%{opacity:.45}} + +/* ============ shared ============ */ +.grad{background:linear-gradient(100deg,#7ae9ff,#00d4ff 55%,#0aa6d6); + -webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;color:transparent} +.wrap{max-width:var(--maxw);margin:0 auto;padding:0 clamp(18px,5vw,48px)} +section{position:relative;z-index:1} +.eyebrow{font-family:var(--font-mono);font-size:.74rem;letter-spacing:.22em;text-transform:uppercase;color:var(--accent);margin-bottom:16px;display:block} +h2{font-size:clamp(2rem,4.6vw,3.2rem);line-height:1.08;letter-spacing:-.02em;font-weight:800} +.lead{color:var(--text-secondary);font-size:1.08rem;max-width:54ch;margin-top:18px;font-weight:400} +.pad{padding:clamp(80px,12vh,140px) 0} +.glass{background:var(--card-bg);border:1px solid var(--card-border);box-shadow:var(--card-shadow); + backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)} + +/* ============ TOPBAR — grafted from the dashboard (topbar.css) ============ */ +.topbar{display:flex;justify-content:space-between;align-items:center;padding:0 24px;height:60px; + position:fixed;top:0;left:0;right:0;z-index:1000;background:var(--topbar-bg); + border-bottom:1px solid var(--border);backdrop-filter:blur(12px) saturate(140%);-webkit-backdrop-filter:blur(12px) saturate(140%)} +.mobile-menu-toggle{display:none;background:none;border:none;color:var(--text-primary);cursor:pointer;padding:6px;margin-right:4px} +.topbar-left{display:flex;align-items:center;flex:0 0 auto} +.libreportal-logo{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--text-primary);font-weight:700;font-size:1.05rem} +.libreportal-logo img{width:32px;height:32px} +.libreportal-logo b{color:var(--accent);font-weight:700} +.mobile-drawer{display:flex;align-items:center;flex:1;justify-content:space-between;gap:12px;min-width:0;margin-left:24px} +.topbar-nav{display:flex;gap:8px;align-items:center} +.topbar-nav .nav-item{background:rgba(var(--text-rgb),.10);border:1px solid rgba(var(--text-rgb),.20);border-radius:8px; + padding:10px 16px;font-size:14px;font-weight:500;color:var(--text-muted);text-decoration:none;display:flex;align-items:center;gap:8px; + transition:all .2s ease;cursor:pointer;min-height:42px;white-space:nowrap} +.topbar-nav .nav-item:hover{background:rgba(var(--text-rgb),.20);transform:translateY(-1px);color:var(--text-primary)} +.topbar-nav .nav-item.nav-active{background:var(--accent);color:var(--text-primary);border-color:var(--accent)} +.topbar-nav .nav-item.nav-active:hover{background:var(--accent-hover);border-color:var(--accent-hover)} +.topbar-nav .nav-item svg{width:16px;height:16px} +.topbar-controls{display:flex;align-items:center;gap:12px} +.tb-ghost{display:inline-flex;align-items:center;gap:6px;padding:8px 14px;border:1px solid var(--border);border-radius:8px; + background:rgba(var(--text-rgb),.05);color:var(--text-secondary);text-decoration:none;font-size:.85rem;font-weight:600;transition:all .2s} +.tb-ghost:hover{background:rgba(var(--text-rgb),.12);color:var(--text-primary)} +.tb-cta{display:inline-flex;align-items:center;gap:6px;padding:8px 18px;border-radius:8px;background:var(--accent); + color:var(--text-on-accent);text-decoration:none;font-size:.85rem;font-weight:700;transition:all .2s} +.tb-cta:hover{background:#22dbff;transform:translateY(-1px);box-shadow:0 8px 22px -8px rgba(var(--accent-rgb),.6)} +@media(max-width:768px){ + .topbar{padding:0 12px;gap:8px;justify-content:flex-start} + .mobile-menu-toggle{display:flex;align-items:center} + .mobile-drawer{position:fixed;top:60px;left:0;width:100vw;height:calc(100vh - 60px);flex-direction:column;align-items:stretch; + justify-content:flex-start;gap:0;padding:16px;margin-left:0;background:var(--surface-bg-solid);border-right:1px solid var(--border); + box-shadow:6px 0 24px rgba(0,0,0,.35);overflow-y:auto;transform:translateX(-100%);transition:transform .3s ease;z-index:101} + .mobile-drawer.mobile-open{transform:translateX(0)} + .mobile-drawer .topbar-nav{flex-direction:column;align-items:stretch;gap:6px;width:100%} + .mobile-drawer .topbar-nav .nav-item{width:100%;justify-content:flex-start} + .mobile-drawer .topbar-controls{flex-direction:column;align-items:stretch;gap:8px;width:100%;margin-top:auto;padding-top:16px; + border-top:1px solid rgba(var(--text-rgb),.12)} + .mobile-drawer .topbar-controls a{width:100%;justify-content:center} +} + +/* ============ hero ============ */ +header.hero{min-height:100vh;display:flex;flex-direction:column;justify-content:center;align-items:center; + text-align:center;padding:140px clamp(18px,5vw,48px) 90px;position:relative} +.badge{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.72rem; + letter-spacing:.14em;text-transform:uppercase;color:var(--accent);padding:7px 15px;border-radius:999px; + border:1px solid rgba(var(--accent-rgb),.35);background:var(--accent-soft);margin-bottom:30px} +.badge .dot{width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 10px var(--accent);animation:pulse 2.4s ease-in-out infinite} +@keyframes pulse{0%,100%{opacity:.4}50%{opacity:1}} +.hero-logo{width:64px;height:64px;margin-bottom:22px;filter:drop-shadow(0 6px 24px rgba(var(--accent-rgb),.45))} +h1{font-size:clamp(2.6rem,7vw,5.2rem);line-height:1.03;letter-spacing:-.03em;font-weight:800;max-width:15ch} +.sub{margin:26px auto 0;max-width:50ch;font-size:clamp(1.02rem,2vw,1.2rem);color:var(--text-secondary);font-weight:400} + +/* install portal */ +.portal{margin:46px auto 0;width:min(660px,100%);position:relative} +.portal::before{content:"";position:absolute;inset:-26px;border-radius:28px;z-index:-1; + background:radial-gradient(60% 80% at 50% 50%, rgba(var(--accent-rgb),.5), transparent 70%);filter:blur(22px);animation:breathe 6s ease-in-out infinite} +@keyframes breathe{0%,100%{opacity:.45;transform:scale(.98)}50%{opacity:.8;transform:scale(1.03)}} +.term{border:1px solid var(--card-border);border-radius:16px;overflow:hidden; + background:linear-gradient(155deg, rgba(255,255,255,.10) 0%, rgba(0,212,255,.06) 100%); + backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);box-shadow:var(--card-shadow-hover)} +.term-bar{display:flex;align-items:center;gap:7px;padding:12px 16px;border-bottom:1px solid var(--border-subtle);background:var(--console-bg)} +.term-bar i{width:11px;height:11px;border-radius:50%;display:block} +.term-bar i:nth-child(1){background:#ff6b5e}.term-bar i:nth-child(2){background:#ffc107}.term-bar i:nth-child(3){background:var(--accent)} +.term-bar em{margin-left:auto;font-family:var(--font-mono);font-size:.72rem;color:var(--text-faint);font-style:normal} +.term-body{display:flex;align-items:center;gap:14px;padding:22px 20px} +.term-body code{font-family:var(--font-mono);font-size:clamp(.82rem,2.3vw,1.02rem);color:var(--text-primary); + white-space:nowrap;overflow-x:auto;flex:1;text-align:left;scrollbar-width:none} +.term-body code::-webkit-scrollbar{display:none} +.term-body code .p{color:var(--accent)} +.term-body code .u{color:#e6f3ff} +.copy{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;font-family:var(--font-sans);font-weight:700; + font-size:.84rem;color:var(--text-on-accent);background:var(--accent);border:none;border-radius:9px;padding:9px 15px;cursor:pointer; + transition:transform .15s,background .25s,box-shadow .25s} +.copy:hover{transform:translateY(-1px);background:#22dbff;box-shadow:0 8px 22px -8px rgba(var(--accent-rgb),.7)} +.copy.done{background:#28a745;color:#fff} +.portal-foot{display:flex;align-items:center;justify-content:center;gap:16px;margin-top:16px;flex-wrap:wrap;font-size:.86rem;color:var(--text-faint)} +.portal-foot a{color:var(--text-secondary);text-decoration:none;border-bottom:1px dashed rgba(255,255,255,.3);transition:color .2s,border-color .2s} +.portal-foot a:hover{color:var(--accent);border-color:var(--accent)} +.hint{font-family:var(--font-mono);font-size:.78rem} +.scroll-cue{position:absolute;bottom:28px;left:50%;transform:translateX(-50%);color:var(--text-faint); + font-family:var(--font-mono);font-size:.66rem;letter-spacing:.2em;text-transform:uppercase; + display:flex;flex-direction:column;align-items:center;gap:8px;animation:bob 2.6s ease-in-out infinite} +.scroll-cue::after{content:"";width:1px;height:34px;background:linear-gradient(var(--text-faint),transparent)} +@keyframes bob{0%,100%{transform:translateX(-50%) translateY(0)}50%{transform:translateX(-50%) translateY(8px)}} + +/* ============ features ============ */ +.feat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:54px} +.card{border-radius:16px;padding:28px 26px;position:relative;overflow:hidden;transition:transform .4s var(--ease),border-color .4s,box-shadow .4s} +.card:hover{transform:translateY(-6px);border-color:rgba(var(--accent-rgb),.45);box-shadow:var(--card-shadow-hover)} +.card .ico{width:44px;height:44px;border-radius:12px;display:grid;place-items:center;margin-bottom:18px; + background:var(--accent-soft);border:1px solid rgba(var(--accent-rgb),.30)} +.card .ico svg{width:22px;height:22px;stroke:var(--accent);fill:none;stroke-width:1.6} +.card h3{font-size:1.24rem;margin-bottom:8px;font-weight:700;letter-spacing:-.01em} +.card p{color:var(--text-secondary);font-size:.96rem} + +/* ============ apps (data-driven) ============ */ +.apps-section{text-align:center} +.app-filters{display:flex;flex-wrap:wrap;justify-content:center;gap:10px;margin-top:40px} +.chip{font-family:var(--font-mono);font-size:.76rem;letter-spacing:.04em;padding:8px 15px;border-radius:999px; + border:1px solid var(--border);background:rgba(255,255,255,.05);color:var(--text-secondary);cursor:pointer;transition:all .2s} +.chip:hover{color:var(--text-primary);border-color:rgba(var(--accent-rgb),.45)} +.chip.active{background:var(--accent);color:var(--text-on-accent);border-color:var(--accent);font-weight:600} +.chip .n{opacity:.55;margin-left:6px} +.app-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(248px,1fr));gap:16px;margin-top:34px;text-align:left} +.app-card{border-radius:14px;padding:20px;display:flex;flex-direction:column;gap:11px;transition:transform .3s var(--ease),border-color .3s,box-shadow .3s} +.app-card.hidden{display:none} +.app-card:hover{transform:translateY(-4px);border-color:rgba(var(--accent-rgb),.4);box-shadow:var(--card-shadow-hover)} +.app-card-head{display:flex;align-items:center;gap:12px} +.app-ico{width:42px;height:42px;border-radius:10px;background:rgba(255,255,255,.06);padding:6px;object-fit:contain;border:1px solid var(--border-subtle);flex:0 0 auto} +.app-card h3{font-size:1.06rem;font-weight:700;line-height:1.2} +.app-cat{font-family:var(--font-mono);font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;color:var(--accent)} +.app-card p{font-size:.9rem;color:var(--text-secondary);margin:0} +.app-count{margin-top:26px;color:var(--text-faint);font-size:.85rem;font-family:var(--font-mono)} + +/* ============ connect / courier ============ */ +.connect{display:grid;grid-template-columns:1.05fr .95fr;gap:60px;align-items:center} +.pill{display:inline-flex;align-items:center;gap:8px;font-family:var(--font-mono);font-size:.72rem; + letter-spacing:.1em;text-transform:uppercase;color:var(--text-secondary);padding:7px 14px;border-radius:999px; + border:1px solid var(--border);background:rgba(255,255,255,.04);margin-top:24px} +.connect ul{list-style:none;margin-top:26px;display:flex;flex-direction:column;gap:15px} +.connect li{display:flex;gap:13px;color:var(--text-secondary);font-size:1rem} +.connect li svg{flex:0 0 auto;width:21px;height:21px;stroke:var(--accent);fill:none;stroke-width:1.6;margin-top:3px} +.connect li b{color:var(--text-primary);font-weight:700} +.vault{position:relative;aspect-ratio:1;display:grid;place-items:center} +.vault svg{width:min(360px,82%);height:auto;overflow:visible} +.orbit{transform-origin:center;animation:spin 26s linear infinite} +@keyframes spin{to{transform:rotate(360deg)}} + +/* ============ promise ============ */ +.promise{text-align:center} +.pledges{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin-top:52px} +.pledge{border-radius:14px;padding:28px 18px} +.pledge .big{font-size:2.4rem;font-weight:800;margin-bottom:8px;line-height:1} +.pledge p{font-size:.92rem;color:var(--text-secondary)} +.promise .link{display:inline-block;margin-top:40px;color:var(--accent);text-decoration:none;font-weight:700; + border-bottom:1px solid rgba(var(--accent-rgb),.45);padding-bottom:2px;transition:color .2s,border-color .2s} +.promise .link:hover{color:#fff;border-color:#fff} + +/* ============ final ============ */ +.final{text-align:center;padding:clamp(90px,14vh,160px) 0} +.final h2{max-width:18ch;margin-inline:auto} +.final .portal{margin-top:42px} + +/* ============ footer ============ */ +footer{border-top:1px solid var(--border-subtle);padding:54px 0 70px;margin-top:40px;background:rgba(10,16,32,.55);backdrop-filter:blur(8px)} +.foot-grid{display:flex;justify-content:space-between;gap:40px;flex-wrap:wrap;align-items:flex-start} +.foot-grid .libreportal-logo{margin-bottom:14px} +.foot-col h4{font-size:.74rem;letter-spacing:.16em;text-transform:uppercase;color:var(--text-faint);margin-bottom:14px;font-family:var(--font-mono)} +.foot-col a{display:block;color:var(--text-secondary);text-decoration:none;font-size:.95rem;margin-bottom:9px;transition:color .2s} +.foot-col a:hover{color:var(--accent)} +.colophon{margin-top:46px;padding-top:26px;border-top:1px solid var(--border-subtle); + display:flex;justify-content:space-between;gap:18px;flex-wrap:wrap;color:var(--text-faint);font-size:.86rem} +.colophon a{color:var(--text-secondary);text-decoration:none} +.colophon a:hover{color:var(--accent)} + +/* ============ reveal ============ */ +.reveal{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease),transform .9s var(--ease)} +.reveal.in{opacity:1;transform:none} +.stagger>*{opacity:0;transform:translateY(20px);transition:opacity .7s var(--ease),transform .7s var(--ease)} +.stagger.in>*{opacity:1;transform:none} +.stagger.in>*:nth-child(2){transition-delay:.07s}.stagger.in>*:nth-child(3){transition-delay:.14s} +.stagger.in>*:nth-child(4){transition-delay:.21s}.stagger.in>*:nth-child(5){transition-delay:.28s}.stagger.in>*:nth-child(6){transition-delay:.35s} +.h-anim{opacity:0;transform:translateY(24px);animation:rise .95s var(--ease) forwards} +.d1{animation-delay:.05s}.d2{animation-delay:.16s}.d3{animation-delay:.28s}.d4{animation-delay:.4s}.d5{animation-delay:.52s} +@keyframes rise{to{opacity:1;transform:none}} + +/* ============ responsive ============ */ +@media(max-width:860px){ + .feat-grid{grid-template-columns:1fr 1fr} + .connect{grid-template-columns:1fr;gap:36px} + .vault{order:-1;max-width:320px;margin-inline:auto} + .pledges{grid-template-columns:1fr 1fr} +} +@media(max-width:540px){ + .feat-grid{grid-template-columns:1fr} + .term-body{flex-direction:column;align-items:stretch} + .copy{justify-content:center} +} +@media(prefers-reduced-motion:reduce){ + *{animation:none!important;transition:none!important} + .reveal,.stagger>*,.h-anim{opacity:1;transform:none} +} diff --git a/site/dist/index.html b/site/dist/index.html new file mode 100644 index 0000000..ff5a8cf --- /dev/null +++ b/site/dist/index.html @@ -0,0 +1,586 @@ + + + + + +LibrePortal — your own private corner of the universe + + + + + + +
+
+ +
+ +
+ +
+
+ + +
+
+ + + +
+ v0.1.0 · early days, no telemetry ever + +

Your own private corner
of the universe

+

Self-host the apps you actually rely on — on your own server. + One command brings up a whole platform, and your data never leaves your orbit.

+ +
+
+
~ one command, your whole server
+
+ bash <(curl -fsSL https://get.libreportal.org) init + +
+
+
+ curl·to·shell, on a privacy tool? read it first → + · + or clone the repo +
+
+ +
explore
+
+ + +
+ What comes online +

A whole platform, handled for you

+

No yak-shaving. LibrePortal wires up the boring, fiddly infrastructure so you can run the good stuff.

+ +
+
+
+

One-click apps

+

Nextcloud, Vaultwarden, Jellyfin, Gitea and dozens more — picked from a menu, deployed clean.

+
+
+
+

Traefik + auto-SSL

+

A reverse proxy with automatic Let's Encrypt certificates. HTTPS everywhere, configured for you.

+
+
+
+

Rootless Docker

+

Containers run without root and with sane security defaults — CrowdSec on guard out of the box.

+
+
+
+

A real dashboard

+

Install, configure, back up and monitor everything from a clean web UI. No SSH archaeology.

+
+
+
+

Optional VPN routing

+

Send any app's traffic through gluetun. Keep the things that should be private, private.

+
+
+
+

No telemetry

+

Nothing phones home. No accounts required to self-host. The software is yours, entirely.

+
+
+
+ + +
+ The constellation +

Dozens of apps, one sky

+

Pulled straight from the repo — 31 apps you can light up from the dashboard, and switch off just as easily.

+ +
+ + + + + + + + + + + + +
+ +
+
+
+ +
+

AdGuard

+ networking +
+
+

DNS based Ad Blocking

+
+ +
+
+ +
+

Authelia

+ security +
+
+

Authentication & SSO

+
+ +
+
+ +
+

Bookstack

+ knowledge +
+
+

Wiki/Knowledge Base

+
+ +
+
+ +
+

CrowdSec

+ security +
+
+

Intrusion Prevention

+
+ +
+
+ +
+

Dashy

+ productivity +
+
+

Dashboard Tool

+
+ +
+
+ +
+

Focalboard

+ productivity +
+
+

Project Management

+
+ +
+
+ +
+

Gitea

+ development +
+
+

Git Repository Management

+
+ +
+
+ +
+

Gluetun

+ networking +
+
+

VPN Container Router

+
+ +
+
+ +
+

Grafana

+ monitoring +
+
+

Metrics Visualizer

+
+ +
+
+ +
+

Headscale

+ networking +
+
+

WireGuard VPN Controller

+
+ +
+
+ +
+

Invidious

+ media +
+
+

YouTube Frontend

+
+ +
+
+ +
+

IPinfo

+ networking +
+
+

IP Information

+
+ +
+
+ +
+

Jellyfin

+ media +
+
+

Media Server

+
+ +
+
+ +
+

Jitsi Meet

+ communication +
+
+

Video Conferencing

+
+ +
+
+ +
+

LibrePortal

+ system +
+
+

WebUI Dashboard

+
+ +
+
+ +
+

Linkding

+ knowledge +
+
+

Bookmark Manager

+
+ +
+
+ +
+

Mastodon

+ communication +
+
+

Social Network

+
+ +
+
+ +
+

MoneyApp

+ productivity +
+
+

Household Money Management

+
+ +
+
+ +
+

Nextcloud

+ storage +
+
+

Self-hosted Cloud Storage

+
+ +
+
+ +
+

Ollama

+ development +
+
+

Local AI Model Hosting

+
+ +
+
+ +
+

OnlyOffice

+ storage +
+
+

Collaborative Office Suite

+
+ +
+
+ +
+

OwnCloud

+ storage +
+
+

Cloud Storage

+
+ +
+
+ +
+

PiHole

+ networking +
+
+

DNS-based Ad Blocking

+
+ +
+
+ +
+

Prometheus

+ monitoring +
+
+

Monitoring and Alerting

+
+ +
+
+ +
+

SearxNG

+ security +
+
+

Search Engine

+
+ +
+
+ +
+

Speedtest

+ networking +
+
+

Network Performance Monitoring

+
+ +
+
+ +
+

Traefik

+ networking +
+
+

Reverse Proxy

+
+ +
+
+ +
+

Trilium

+ knowledge +
+
+

Notes & Knowledge Management

+
+ +
+
+ +
+

Unbound

+ networking +
+
+

DNS Resolver

+
+ +
+
+ +
+

Vaultwarden

+ security +
+
+

Password Manager

+
+ +
+
+ +
+

Wireguard Easy

+ networking +
+
+

VPN Server

+
+ +
+

31 apps

+
+ + +
+
+
+ LibrePortal Connect · optional +

We're the courier.
You hold the key.

+

Reaching your server from your phone and keeping off-site backups are the fiddly bits. + Connect handles them — but works like a courier carrying a sealed box.

+
    +
  • Reach it anywhere. No port-forwarding, no exposing your box to the internet.
  • +
  • Encrypted off-site backups. We only ever hold a locked box — you keep the only key.
  • +
  • We never run your apps. Your data and keys never leave your machine.
  • +
+ every part is free to self-host, too — you pay only for convenience +
+
+ +
+
+
+ + +
+ The promise +

Free software, and it stays that way

+

In plain language, so you can hold us to it.

+
+
100%

Every feature, free to self-host. Forever. No crippled edition.

+
0

Trackers. No telemetry, no phoning home, no accounts to run it.

+

Feature paywalls. You never pay to unlock — only for convenience.

+

What's open stays open. No rug-pulls, ever. AGPLv3.

+
+ Read the full Promise → +
+ + +
+ Ready when you are +

Light up your corner
of the universe.

+
+
+
~
+
+ bash <(curl -fsSL https://get.libreportal.org) init + +
+
+
+
+ + + + + + + + diff --git a/site/src/_data/apps.json b/site/src/_data/apps.json new file mode 100644 index 0000000..0fee04e --- /dev/null +++ b/site/src/_data/apps.json @@ -0,0 +1,378 @@ +[ + { + "slug": "adguard", + "title": "AdGuard", + "category": "networking", + "categories": [ + "networking" + ], + "description": "DNS based Ad Blocking", + "longDescription": "AdGuard Home is a network-wide software for advertisements and tracking blocking that operates as a DNS server and returns the IP address of a local, blackhole DNS server for domains that should be blocked", + "url": "https://github.com/AdguardTeam/AdGuardHome", + "icon": "assets/apps/adguard.svg" + }, + { + "slug": "authelia", + "title": "Authelia", + "category": "security", + "categories": [ + "security" + ], + "description": "Authentication & SSO", + "longDescription": "Authelia is an open-source authentication and authorization server providing 2-factor authentication and single sign-on for your applications", + "url": "https://github.com/authelia/authelia", + "icon": "assets/apps/authelia.svg" + }, + { + "slug": "bookstack", + "title": "Bookstack", + "category": "knowledge", + "categories": [ + "knowledge" + ], + "description": "Wiki/Knowledge Base", + "longDescription": "BookStack is a simple, self-hosted wiki and documentation platform that provides a pleasant and simple way to organize and store information", + "url": "https://github.com/BookStackApp/BookStack", + "icon": "assets/apps/bookstack.svg" + }, + { + "slug": "crowdsec", + "title": "CrowdSec", + "category": "security", + "categories": [ + "security", + "recommended" + ], + "description": "Intrusion Prevention", + "longDescription": "CrowdSec is an open-source intrusion prevention system. It detects attacks from log patterns — brute-force, scans, web exploits — and blocks offending IPs at the firewall. Includes community-shared threat intelligence.", + "url": "https://www.crowdsec.net", + "icon": "assets/apps/crowdsec.svg" + }, + { + "slug": "dashy", + "title": "Dashy", + "category": "productivity", + "categories": [ + "productivity" + ], + "description": "Dashboard Tool", + "longDescription": "Dashy is a self-hostable personal dashboard for monitoring your self-hosted services and applications with a beautiful, intuitive interface", + "url": "https://github.com/Lissy93/dashy", + "icon": "assets/apps/dashy.svg" + }, + { + "slug": "focalboard", + "title": "Focalboard", + "category": "productivity", + "categories": [ + "productivity" + ], + "description": "Project Management", + "longDescription": "Focalboard is an open source, self-hosted alternative to Trello, Notion, and Asana that helps organize projects and tasks", + "url": "https://github.com/mattermost/focalboard", + "icon": "assets/apps/focalboard.svg" + }, + { + "slug": "gitea", + "title": "Gitea", + "category": "development", + "categories": [ + "development" + ], + "description": "Git Repository Management", + "longDescription": "Gitea is a lightweight, self-hosted Git service written in Go that provides a painless self-hosted Git service with a minimal setup", + "url": "https://github.com/go-gitea/gitea", + "icon": "assets/apps/gitea.svg" + }, + { + "slug": "gluetun", + "title": "Gluetun", + "category": "networking", + "categories": [ + "networking", + "recommended" + ], + "description": "VPN Container Router", + "longDescription": "Run all of your containers through a VPN provider. Supports 30+ providers over WireGuard and OpenVPN with a built-in kill-switch, DNS-over-TLS, port forwarding, and an HTTP control server.", + "url": "https://github.com/qdm12/gluetun", + "icon": "assets/apps/gluetun.svg" + }, + { + "slug": "grafana", + "title": "Grafana", + "category": "monitoring", + "categories": [ + "monitoring" + ], + "description": "Metrics Visualizer", + "longDescription": "The open source analytics and monitoring solution for every database with beautiful dashboards and alerting capabilities", + "url": "https://github.com/grafana/grafana", + "icon": "assets/apps/grafana.svg" + }, + { + "slug": "headscale", + "title": "Headscale", + "category": "networking", + "categories": [ + "networking" + ], + "description": "WireGuard VPN Controller", + "longDescription": "Headscale is an open source, self-hosted implementation of the Tailscale control server that works with the Tailscale client", + "url": "https://github.com/juanfont/headscale", + "icon": "assets/apps/headscale.svg" + }, + { + "slug": "invidious", + "title": "Invidious", + "category": "media", + "categories": [ + "media" + ], + "description": "YouTube Frontend", + "longDescription": "Invidious is an alternative front-end to YouTube that focuses on privacy and providing a distraction-free viewing experience", + "url": "https://github.com/iv-org/invidious", + "icon": "assets/apps/invidious.svg" + }, + { + "slug": "ipinfo", + "title": "IPinfo", + "category": "networking", + "categories": [ + "networking" + ], + "description": "IP Information", + "longDescription": "IPinfo is a simple IP address lookup service that provides detailed information about IP addresses including geolocation and ISP data", + "url": "https://github.com/ipinfo/cli", + "icon": "assets/apps/ipinfo.svg" + }, + { + "slug": "jellyfin", + "title": "Jellyfin", + "category": "media", + "categories": [ + "media" + ], + "description": "Media Server", + "longDescription": "Jellyfin is a free software media system that puts you in control of managing and streaming your media without any locked subscriptions", + "url": "https://github.com/jellyfin/jellyfin", + "icon": "assets/apps/jellyfin.svg" + }, + { + "slug": "jitsimeet", + "title": "Jitsi Meet", + "category": "communication", + "categories": [ + "communication" + ], + "description": "Video Conferencing", + "longDescription": "Jitsi Meet is an open-source video conferencing solution that provides secure, easy, and high-quality video meetings for everyone", + "url": "https://github.com/jitsi/jitsi-meet", + "icon": "assets/apps/jitsimeet.svg" + }, + { + "slug": "libreportal", + "title": "LibrePortal", + "category": "system", + "categories": [ + "system" + ], + "description": "WebUI Dashboard", + "longDescription": "LibrePortal is a comprehensive Docker management platform that simplifies container deployment and management with an intuitive web interface", + "url": "", + "icon": "assets/apps/libreportal.svg" + }, + { + "slug": "linkding", + "title": "Linkding", + "category": "knowledge", + "categories": [ + "knowledge" + ], + "description": "Bookmark Manager", + "longDescription": "Linkding is a simple, self-hosted bookmark manager designed to be fast, lightweight, and easy to use with a clean interface", + "url": "https://github.com/sissbruecker/linkding", + "icon": "assets/apps/linkding.svg" + }, + { + "slug": "mastodon", + "title": "Mastodon", + "category": "communication", + "categories": [ + "communication" + ], + "description": "Social Network", + "longDescription": "Your self-hosted, globally interconnected microblogging community that gives you control over your social media experience", + "url": "https://github.com/mastodon/mastodon", + "icon": "assets/apps/mastodon.svg" + }, + { + "slug": "moneyapp", + "title": "MoneyApp", + "category": "productivity", + "categories": [ + "productivity" + ], + "description": "Household Money Management", + "longDescription": "Personal budget tracker with recurring rules, projected ledger, savings goals, compound-interest calculator and 12-month what-if forecast.", + "url": "", + "icon": "assets/apps/default.svg" + }, + { + "slug": "nextcloud", + "title": "Nextcloud", + "category": "storage", + "categories": [ + "storage" + ], + "description": "Self-hosted Cloud Storage", + "longDescription": "Nextcloud is a suite of client-server software for creating and using file hosting services that puts you in control of your data", + "url": "https://github.com/nextcloud/server", + "icon": "assets/apps/nextcloud.svg" + }, + { + "slug": "ollama", + "title": "Ollama", + "category": "development", + "categories": [ + "development" + ], + "description": "Local AI Model Hosting", + "longDescription": "Ollama is a lightweight, extensible framework for building and running large language models locally with ease", + "url": "https://github.com/ollama/ollama", + "icon": "assets/apps/ollama.svg" + }, + { + "slug": "onlyoffice", + "title": "OnlyOffice", + "category": "storage", + "categories": [ + "storage" + ], + "description": "Collaborative Office Suite", + "longDescription": "OnlyOffice is a comprehensive office suite that provides document editing, spreadsheet, and presentation capabilities", + "url": "https://github.com/ONLYOFFICE/DocumentServer", + "icon": "assets/apps/onlyoffice.svg" + }, + { + "slug": "owncloud", + "title": "OwnCloud", + "category": "storage", + "categories": [ + "storage" + ], + "description": "Cloud Storage", + "longDescription": "ownCloud is a self-hosted file sync and share server that provides secure access to your files from any device", + "url": "https://github.com/owncloud/core", + "icon": "assets/apps/owncloud.svg" + }, + { + "slug": "pihole", + "title": "PiHole", + "category": "networking", + "categories": [ + "networking" + ], + "description": "DNS-based Ad Blocking", + "longDescription": "Pi-hole is a DNS sinkhole that protects your devices from unwanted content without installing any client-side software", + "url": "https://github.com/pi-hole/pi-hole", + "icon": "assets/apps/pihole.svg" + }, + { + "slug": "prometheus", + "title": "Prometheus", + "category": "monitoring", + "categories": [ + "monitoring" + ], + "description": "Monitoring and Alerting", + "longDescription": "The Prometheus monitoring system and time series database that provides powerful querying and alerting capabilities", + "url": "https://github.com/prometheus/prometheus", + "icon": "assets/apps/prometheus.svg" + }, + { + "slug": "searxng", + "title": "SearxNG", + "category": "security", + "categories": [ + "security" + ], + "description": "Search Engine", + "longDescription": "SearXNG is a privacy-respecting metasearch engine that aggregates results from multiple search engines while protecting your privacy", + "url": "https://github.com/searxng/searxng", + "icon": "assets/apps/searxng.svg" + }, + { + "slug": "speedtest", + "title": "Speedtest", + "category": "networking", + "categories": [ + "networking" + ], + "description": "Network Performance Monitoring", + "longDescription": "Lightweight speedtest implemented in Javascript that provides accurate network speed measurements", + "url": "https://github.com/librespeed/speedtest", + "icon": "assets/apps/speedtest.svg" + }, + { + "slug": "traefik", + "title": "Traefik", + "category": "networking", + "categories": [ + "networking", + "recommended" + ], + "description": "Reverse Proxy", + "longDescription": "Traefik is a modern HTTP reverse proxy and load balancer that makes deploying microservices easy and efficient", + "url": "https://github.com/traefik/traefik", + "icon": "assets/apps/traefik.svg" + }, + { + "slug": "trilium", + "title": "Trilium", + "category": "knowledge", + "categories": [ + "knowledge" + ], + "description": "Notes & Knowledge Management", + "longDescription": "Trilium Notes is a hierarchical note-taking application with focus on building a personal knowledge base and productivity", + "url": "https://github.com/zadam/trilium", + "icon": "assets/apps/trilium.svg" + }, + { + "slug": "unbound", + "title": "Unbound", + "category": "networking", + "categories": [ + "networking" + ], + "description": "DNS Resolver", + "longDescription": "Unbound is a validating, recursive, and caching DNS resolver that provides secure and fast DNS resolution", + "url": "https://github.com/NLnetLabs/unbound", + "icon": "assets/apps/unbound.svg" + }, + { + "slug": "vaultwarden", + "title": "Vaultwarden", + "category": "security", + "categories": [ + "security" + ], + "description": "Password Manager", + "longDescription": "Vaultwarden is an alternative implementation of the Bitwarden server API written in Rust and compatible with Bitwarden clients", + "url": "https://github.com/dani-garcia/vaultwarden", + "icon": "assets/apps/vaultwarden.svg" + }, + { + "slug": "wireguard", + "title": "Wireguard Easy", + "category": "networking", + "categories": [ + "networking", + "recommended" + ], + "description": "VPN Server", + "longDescription": "WireGuard is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography", + "url": "https://github.com/WireGuard/wireguard-tools", + "icon": "assets/apps/wireguard.svg" + } +] diff --git a/site/src/_data/categories.json b/site/src/_data/categories.json new file mode 100644 index 0000000..96f1434 --- /dev/null +++ b/site/src/_data/categories.json @@ -0,0 +1,57 @@ +[ + { + "id": "networking", + "name": "Networking", + "count": 9 + }, + { + "id": "recommended", + "name": "Recommended", + "count": 4 + }, + { + "id": "security", + "name": "Security", + "count": 4 + }, + { + "id": "knowledge", + "name": "Knowledge", + "count": 3 + }, + { + "id": "productivity", + "name": "Productivity", + "count": 3 + }, + { + "id": "storage", + "name": "Storage", + "count": 3 + }, + { + "id": "communication", + "name": "Communication", + "count": 2 + }, + { + "id": "development", + "name": "Development", + "count": 2 + }, + { + "id": "media", + "name": "Media", + "count": 2 + }, + { + "id": "monitoring", + "name": "Monitoring", + "count": 2 + }, + { + "id": "system", + "name": "System", + "count": 1 + } +]