Initial commit: 50 shell-script generators with web UI
- 8 categories / 50 generators covering middleware, databases, runtimes, systemd services, system tools, network, monitoring, security - VNC supports XFCE / GNOME / KDE Plasma / MATE / LXQt desktops - Node.js versions 18-26 (incl. current LTS 24 Krypton and current 26) - Live preview, copy / download / multi-script bundle in web UI - Distro-aware (Ubuntu/Debian/CentOS/RHEL/Rocky/Alma/Fedora) - All 50 generators pass bash -n syntax check - Zero pip dependencies (Flask stdlib only)
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Shell-Gen · 首页{% endblock %}
|
||||
{% block body %}
|
||||
<main class="container">
|
||||
<section class="hero">
|
||||
<h1>选择需要部署的服务</h1>
|
||||
<p class="lead">填写参数,实时生成可立即执行的 bash 脚本。所有脚本会先做 distro 检测
|
||||
(Ubuntu/Debian/CentOS/RHEL/Rocky/Alma) 再安装,不会破坏现有服务。</p>
|
||||
<div class="stats">
|
||||
<div class="stat"><div class="num">{{ total }}</div><div class="lbl">生成器</div></div>
|
||||
{% for cat in all_cats %}
|
||||
{% set n = all_cats|length %}
|
||||
{% endfor %}
|
||||
<div class="stat"><div class="num">{{ categories|length }}</div><div class="lbl">分类</div></div>
|
||||
<div class="stat"><div class="num">100%</div><div class="lbl">开源</div></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% for cat in categories %}
|
||||
<section class="cat-section" id="cat-{{ cat }}">
|
||||
<h2><span class="cat-icon">{{ category_icons.get(cat, '📦') }}</span> {{ category_labels.get(cat, cat) }}</h2>
|
||||
<div class="grid">
|
||||
{% for gid, gen in (request.application_generator_items if false else []) %}{% endfor %}
|
||||
{# Render via Python loop using all generators grouped by cat #}
|
||||
{% for gid, gen in [] %}{% endfor %}
|
||||
</div>
|
||||
<div class="grid" data-cat="{{ cat }}">
|
||||
{# Render in JS to keep templating simple #}
|
||||
</div>
|
||||
</section>
|
||||
{% endfor %}
|
||||
|
||||
<section class="cat-section">
|
||||
<h2>📚 全部生成器</h2>
|
||||
<div class="grid" id="all-grid"></div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<script>
|
||||
fetch("/api/categories").then(r => r.json()).then(d => {
|
||||
// populate per-category sections
|
||||
for (const cat of d.categories) {
|
||||
const target = document.querySelector(`#cat-${cat.id} .grid[data-cat]`);
|
||||
if (target) target.innerHTML = cat.items.map(renderCard).join('');
|
||||
}
|
||||
// populate "全部生成器"
|
||||
const all = d.categories.flatMap(c => c.items);
|
||||
document.getElementById("all-grid").innerHTML = all.map(renderCard).join('');
|
||||
});
|
||||
|
||||
function renderCard(g) {
|
||||
const tags = (g.tags || []).slice(0, 4).map(t => `<span class="tag">${escapeHtml(t)}</span>`).join('');
|
||||
const os = (g.os || []).slice(0, 3).map(t => `<span class="os">${escapeHtml(t)}</span>`).join('');
|
||||
return `
|
||||
<a class="card" href="/gen/${g.id}">
|
||||
<div class="card-icon">${g.icon || '📦'}</div>
|
||||
<div class="card-title">${escapeHtml(g.title)}</div>
|
||||
<div class="card-desc">${escapeHtml(g.description)}</div>
|
||||
<div class="card-meta">
|
||||
<div class="tags">${tags}</div>
|
||||
<div class="oss">${os}</div>
|
||||
</div>
|
||||
</a>`;
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s).replace(/[&<>"']/g, c => ({
|
||||
'&':'&','<':'<','>':'>','"':'"',"'":'''
|
||||
}[c]));
|
||||
}
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user