Guanghu Domestic Migration d1e47f4565
Some checks are pending
自动更新代码和重启 / update-and-restart (push) Waiting to run
CI检查 + 自动部署 / check (push) Waiting to run
CI检查 + 自动部署 / deploy (push) Blocked by required conditions
重启聊天服务 / restart (push) Waiting to run
chore: import sanitized domestic snapshot for REPO-002
Source snapshot: ca48d3ddf926d79aa138306164169baf764bb829
2026-07-17 15:54:41 +08:00

620 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>冰朔开源仓库 · 模块市场</title>
<style>
:root {
--bg: #0d1117;
--panel: rgba(22,27,34,0.95);
--border: rgba(48,54,61,0.8);
--border-h: rgba(88,166,255,0.4);
--text: #c9d1d9;
--dim: #8b949e;
--accent: #58a6ff;
--green: #3fb950;
--gold: #d2991d;
--code-bg: #161b22;
}
*{margin:0;padding:0;box-sizing:border-box}
body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;min-height:100vh;font-size:15px}
/* ── 仓库头 ── */
.repo-bar {
background: var(--code-bg);
border-bottom: 1px solid var(--border);
padding: 16px 24px;
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
}
.repo-bar .icon { font-size: 20px; }
.repo-bar .path { font-size: 14px; color: var(--accent); font-weight: 600; }
.repo-bar .sep { color: var(--dim); margin: 0 4px; }
.repo-bar .branch {
padding: 2px 10px;
border: 1px solid var(--border);
border-radius: 12px;
font-size: 12px;
color: var(--dim);
}
.repo-bar .badge {
padding: 4px 10px;
border-radius: 12px;
font-size: 11px;
border: 1px solid var(--border);
}
.repo-bar .badge.free { border-color: var(--green); color: var(--green); }
.repo-bar .badge.api { border-color: var(--accent); color: var(--accent); }
/* ── 主布局 ── */
.layout {
display: grid;
grid-template-columns: 240px 1fr;
min-height: calc(100vh - 56px);
}
@media(max-width:860px){ .layout{grid-template-columns:1fr} }
/* ── 左侧文件树 ── */
.sidebar {
background: var(--code-bg);
border-right: 1px solid var(--border);
padding: 12px 0;
overflow-y: auto;
max-height: calc(100vh - 56px);
position: sticky;
top: 0;
}
.sidebar .sect {
padding: 8px 16px;
font-size: 11px;
color: var(--dim);
font-weight: 600;
letter-spacing: 1px;
text-transform: uppercase;
}
.file-item {
padding: 6px 16px 6px 28px;
font-size: 13px;
color: var(--dim);
cursor: pointer;
transition: all 0.15s;
display: flex;
align-items: center;
gap: 8px;
}
.file-item:hover { color: var(--text); background: rgba(88,166,255,0.06); }
.file-item.active { color: var(--accent); background: rgba(88,166,255,0.1); }
.file-item .fi { font-size: 14px; width: 18px; text-align: center; flex-shrink: 0; }
/* ── 右侧内容区 ── */
.content {
padding: 24px;
max-width: 1000px;
}
/* Module Card */
.module-card {
background: var(--panel);
border: 1px solid var(--border);
border-radius: 8px;
margin-bottom: 16px;
overflow: hidden;
}
.module-card:hover { border-color: var(--border-h); }
.module-header {
padding: 20px 24px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: background 0.2s;
}
.module-header:hover { background: rgba(88,166,255,0.04); }
.module-header .left { display: flex; align-items: center; gap: 12px; }
.module-header .icon { font-size: 28px; }
.module-header .info h3 { font-size: 16px; font-weight: 600; }
.module-header .info .mod-id {
font-size: 11px;
color: var(--dim);
font-family: monospace;
margin-top: 2px;
}
.module-header .tags { display: flex; gap: 6px; flex-wrap: wrap; }
.module-header .tag {
padding: 3px 10px;
border-radius: 10px;
font-size: 11px;
border: 1px solid var(--border);
color: var(--dim);
}
.module-header .arrow { color: var(--dim); transition: transform 0.2s; font-size: 14px; }
.module-header .arrow.open { transform: rotate(90deg); }
.module-body {
padding: 0 24px 24px;
display: none;
border-top: 1px solid var(--border);
}
.module-body.open { display: block; }
.module-body .desc { font-size: 14px; color: var(--dim); line-height: 1.8; margin: 16px 0; }
.module-body .section-title {
font-size: 12px;
font-weight: 600;
color: var(--dim);
letter-spacing: 1px;
margin: 16px 0 8px;
}
.module-body .code-block {
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 6px;
padding: 14px 18px;
font-family: 'SF Mono','Fira Code','Consolas',monospace;
font-size: 12.5px;
line-height: 1.7;
overflow-x: auto;
white-space: pre-wrap;
color: var(--text);
margin-bottom: 12px;
}
.code-block .cmt { color: #636e7b; }
.code-block .str { color: #a5d6ff; }
.code-block .key { color: #ff7b72; }
.code-block .num { color: #79c0ff; }
.code-block .fn { color: #d2a8ff; }
/* Use Button */
.use-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 20px;
background: linear-gradient(135deg, #238636, #2ea043);
color: #fff;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
margin-top: 8px;
text-decoration: none;
letter-spacing: 1px;
}
.use-btn:hover { background: #2ea043; transform: translateY(-1px); }
/* ── 在线使用模态窗口 ── */
.modal-overlay {
display: none;
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.7);
z-index: 100;
justify-content: center;
align-items: center;
padding: 20px;
}
.modal-overlay.show { display: flex; }
.modal {
background: var(--bg);
border: 1px solid var(--border);
border-radius: 12px;
width: 100%;
max-width: 1000px;
max-height: 90vh;
overflow-y: auto;
display: grid;
grid-template-columns: 1fr 360px;
gap: 0;
}
@media(max-width:860px){ .modal{grid-template-columns:1fr} }
.modal-left {
padding: 28px;
border-right: 1px solid var(--border);
}
.modal-right {
padding: 28px;
background: var(--code-bg);
display: flex;
flex-direction: column;
align-items: center;
}
.modal-close {
position: absolute;
top: 12px;
right: 16px;
background: none;
border: none;
color: var(--dim);
font-size: 24px;
cursor: pointer;
z-index: 101;
}
/* Input inside modal */
.input-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px; }
select, input, textarea {
padding: 10px 14px;
background: var(--code-bg);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text);
font-size: 13px;
outline: none;
width: 100%;
font-family: inherit;
}
select:focus, input:focus, textarea:focus { border-color: var(--accent); }
textarea { min-height: 80px; resize: vertical; line-height: 1.7; }
.preview-area {
min-height: 200px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(13,17,23,0.5);
border-radius: 8px;
border: 1px dashed var(--border);
width: 100%;
margin-bottom: 12px;
}
.preview-img { max-width: 100%; max-height: 400px; border-radius: 4px; display: block; }
.intent-item {
display: flex; gap: 10px; padding: 10px;
background: var(--code-bg); border: 1px solid var(--border);
border-radius: 6px; margin-bottom: 6px; font-size: 12px;
}
.intent-item.user { border-left: 2px solid var(--green); }
.intent-item.system { border-left: 2px solid var(--accent); }
.intent-who { font-size: 10px; letter-spacing: 1px; margin-bottom: 2px; }
.intent-item.user .intent-who { color: var(--green); }
.intent-item.system .intent-who { color: var(--accent); }
.intent-step { font-weight: 600; margin-bottom: 2px; }
.intent-detail { color: var(--dim); line-height: 1.4; }
.design-id-badge {
text-align: center; padding: 12px;
background: rgba(63,185,80,0.06);
border: 1px solid rgba(63,185,80,0.15);
border-radius: 8px; margin-bottom: 10px;
}
.design-id-badge .id { font-size: 16px; font-weight: 700; color: var(--green); font-family: monospace; margin-top: 4px; }
.btn {
display: block; width: 100%; padding: 11px;
background: linear-gradient(135deg, rgba(88,166,255,0.2), rgba(130,100,200,0.15));
border: 1px solid var(--border); border-radius: 6px;
color: var(--accent); text-align: center; text-decoration: none;
font-size: 13px; font-weight: 600; cursor: pointer; margin-top: 6px;
letter-spacing: 1px;
}
.btn:hover { border-color: var(--accent); }
.btn.primary { background: #238636; color: #fff; border-color: #238636; }
.btn.primary:hover { background: #2ea043; }
.copy-toast {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
background: var(--green);
color: #0d1117;
padding: 10px 24px;
border-radius: 20px;
font-size: 13px;
font-weight: 600;
z-index: 200;
display: none;
}
.copy-toast.show { display: block; animation: fadeInOut 2s ease; }
@keyframes fadeInOut {
0% { opacity: 0; transform: translateX(-50%) translateY(10px); }
20% { opacity: 1; transform: translateX(-50%) translateY(0); }
80% { opacity: 1; }
100% { opacity: 0; }
}
</style>
</head>
<body>
<!-- 仓库头 -->
<div class="repo-bar">
<span class="icon">📦</span>
<span class="path">bingshuo / open-modules</span>
<span class="branch">main</span>
<span class="badge free">✅ 开源免费</span>
<span class="badge api">🔌 API Ready</span>
<span style="font-size:12px;color:var(--dim);margin-left:auto">模块热插拔 · 用你自己的AI进来读取</span>
</div>
<!-- 主布局 -->
<div class="layout">
<!-- 左侧文件树 -->
<div class="sidebar">
<div class="sect">仓库文件</div>
<div class="file-item"><span class="fi">📄</span> README.md</div>
<div class="file-item"><span class="fi">📄</span> package.json</div>
<div class="file-item"><span class="fi">📄</span> server.js</div>
<div class="file-item"><span class="fi">📄</span> generate.js</div>
<div class="file-item"><span class="fi">📄</span> renderer.js</div>
<div class="sect">templates/</div>
<div class="file-item"><span class="fi">📄</span> registry.js</div>
<div class="file-item"><span class="fi">📄</span> xiaohongshu.js</div>
<div class="sect">public/</div>
<div class="file-item"><span class="fi">📄</span> index.html</div>
<div class="sect">模块注册表</div>
<div class="file-item active"><span class="fi">📦</span> MODULE-COVER-001</div>
</div>
<!-- 右侧内容 -->
<div class="content">
<h2 style="font-size:20px;margin-bottom:4px;">开放模块</h2>
<p style="font-size:13px;color:var(--dim);margin-bottom:24px;">
每个模块有唯一编号。用你自己的编程 AI 软件连入此仓库Agent 引导后即可直接调用。
仓库不提供模型 API —— 走你 AI 软件自己的模型。
</p>
<!-- 模块卡片 1图片生成 -->
<div class="module-card">
<div class="module-header" onclick="toggleModule(this)">
<div class="left">
<span class="icon">🎨</span>
<div class="info">
<h3>图片模块 · 语言驱动封面生成器</h3>
<div class="mod-id">MODULE-COVER-001</div>
</div>
</div>
<div style="display:flex;align-items:center;gap:12px;">
<div class="tags">
<span class="tag">📕 小红书</span>
<span class="tag">1080×1440</span>
<span class="tag">MIT</span>
</div>
<span class="arrow"></span>
</div>
</div>
<div class="module-body">
<p class="desc">
输入自然语言描述,系统翻译为设计逻辑,生成独一无二的封面图片。
纯 HTML/CSS 排版渲染,<strong>不依赖任何 AI 绘画模型</strong>,无需 GPU无需 API 密钥。
封面底部带有此仓库域名水印。
</p>
<div class="section-title">技术栈 · 全免费</div>
<div class="code-block"><span class="cmt">// 全部开源 · 全部免费 · 不花一分钱</span>
<span class="key">渲染引擎</span>: Puppeteer + Chrome Headless
<span class="key">Web框架</span>: Express.js
<span class="key">排版引擎</span>: 纯 HTML/CSS不调用任何 AI 模型)
<span class="key">意图分析</span>: 自研文本分析引擎
<span class="cmt">// 不需要 GPU · 不需要 API 密钥 · 不需要付费模型</span></div>
<div class="section-title">如何让 AI 调用</div>
<div class="code-block"><span class="cmt">// 1. 用你的编程 AI 软件连入此仓库</span>
<span class="cmt">// 仓库地址guanghulab.com/code/bingshuo/guanghulab</span>
<span class="cmt">// 2. Agent 引导你走完唤醒路径</span>
<span class="cmt">// 3. 告诉 AI调用模块 MODULE-COVER-001</span>
<span class="cmt">// 4. AI 读取模块代码,理解参数,直接执行</span>
<span class="cmt">// 5. 左边生成你的设计逻辑链 + 唯一编号</span>
<span class="cmt">// 6. 右边预览 + 下载</span>
<span class="cmt">// API 端点AI 或手动调用)</span>
<span class="key">GET</span> <span class="str">/api/templates</span> → 获取模板列表
<span class="key">POST</span> <span class="str">/api/generate</span> → 生成封面
<span class="cmt">// 参数</span>
{ "templateId": "<span class="str">xiaohongshu</span>",
"presetId": "<span class="str">tech</span>",
"title": "<span class="str">标题</span>",
"body": "<span class="str">正文</span>",
"layout": "<span class="str">hero</span>" }</div>
<a href="#" class="use-btn" onclick="openTry(event)">🚀 在线使用</a>
</div>
</div>
<!-- 更多模块占位 -->
<div class="module-card" style="opacity:0.5;cursor:not-allowed">
<div class="module-header">
<div class="left">
<span class="icon">📋</span>
<div class="info">
<h3>更多模块即将上线</h3>
<div class="mod-id">MODULE-XXX-00X</div>
</div>
</div>
<span style="font-size:12px;color:var(--dim)">热插拔 · 随时部署</span>
</div>
</div>
</div>
</div>
<!-- 在线使用模态 -->
<div class="modal-overlay" id="modal">
<div class="modal" style="position:relative;">
<button class="modal-close" onclick="closeModal()"></button>
<div class="modal-left">
<h3 style="font-size:16px;margin-bottom:16px;">🎨 图片模块 · 在线使用</h3>
<div class="input-row">
<select id="preset"><option value="tech" selected>🔷 科技蓝</option><option value="warm">🟠 奶油暖调</option><option value="minimal">⬜ 极简黑白</option><option value="rose">🟣 玫瑰粉调</option><option value="green">🟢 文艺绿植</option></select>
<select id="layout"><option value="default">标准排版</option><option value="hero" selected>大标题封面</option><option value="quote">金句居中</option></select>
</div>
<input type="text" id="title" placeholder="标题" style="margin-bottom:10px;">
<textarea id="body" placeholder="正文..."></textarea>
<button class="btn primary" id="genBtn" onclick="gen()">执行设计逻辑</button>
<div style="display:none;padding:10px;background:rgba(255,100,100,0.08);border:1px solid rgba(255,100,100,0.2);border-radius:6px;color:#ff7b72;font-size:12px;margin-top:10px" id="err"></div>
<div class="design-id-badge" id="idBadge" style="display:none;margin-top:16px;">
<span style="font-size:10px;color:var(--dim);">DESIGN ID · 证明这个设计是你的</span>
<div class="id">---</div>
<span style="font-size:10px;color:var(--dim);">编号已保存到本地 · 署名可选</span>
</div>
<div style="margin-top:16px;">
<div style="font-size:12px;color:var(--dim);margin-bottom:10px;letter-spacing:1px;">意图链 · 设计逻辑</div>
<div id="chain"></div>
</div>
</div>
<div class="modal-right">
<div style="font-size:12px;color:var(--dim);margin-bottom:10px;letter-spacing:1px;">封面预览</div>
<div class="preview-area" id="previewArea">
<div style="text-align:center;color:var(--dim);" id="empty">
<div style="font-size:36px;margin-bottom:8px;opacity:0.3;">🎨</div>
<div style="font-size:12px;">点击执行<br>生成封面</div>
</div>
<img class="preview-img" id="previewImg" style="display:none;" alt="封面">
</div>
<a class="btn primary" id="dlBtn" href="#" download style="display:none;">💾 下载 PNG</a>
<button class="btn" id="saveBtn" onclick="saveId()" style="display:none;">📋 保存设计编号到本地</button>
<div style="font-size:11px;color:var(--dim);margin-top:8px;text-align:center;">
封面带 cover.guanghulab.com 水印<br>
署名可选 · 设计属于你
</div>
</div>
</div>
</div>
<!-- Toast -->
<div class="copy-toast" id="toast"></div>
<script>
function toggleModule(el) {
const body = el.nextElementSibling;
const arrow = el.querySelector('.arrow');
body.classList.toggle('open');
arrow.classList.toggle('open');
}
function openTry(e) {
e.preventDefault();
document.getElementById('modal').classList.add('show');
// 预设内容不显示任何编程AI名字
if(!document.getElementById('title').value) {
document.getElementById('title').value = '零基础手搓AI做图小系统';
document.getElementById('body').value = 'AI辅助 + 自己手搓 · 0经验也能开发\n\n- 开源到个人代码仓库\n- 全免费 · 无需GPU\n- 语言驱动排版 · 意图透明\n- 封面也用它自己生成';
}
}
function closeModal() {
document.getElementById('modal').classList.remove('show');
document.getElementById('previewImg').style.display = 'none';
document.getElementById('empty').style.display = 'block';
document.getElementById('dlBtn').style.display = 'none';
document.getElementById('saveBtn').style.display = 'none';
document.getElementById('idBadge').style.display = 'none';
document.getElementById('chain').innerHTML = '';
document.getElementById('err').style.display = 'none';
}
let currentId = '';
const SAVED_KEY = 'cover-studio-ids';
async function gen() {
const title = document.getElementById('title').value.trim();
const body = document.getElementById('body').value.trim();
if(!title && !body) { showErr('请输入标题或正文'); return; }
document.getElementById('err').style.display = 'none';
document.getElementById('empty').style.display = 'none';
document.getElementById('previewImg').style.display = 'none';
document.getElementById('dlBtn').style.display = 'none';
document.getElementById('saveBtn').style.display = 'none';
document.getElementById('idBadge').style.display = 'none';
document.getElementById('chain').innerHTML = '';
document.getElementById('genBtn').disabled = true;
document.getElementById('genBtn').textContent = '编译中...';
currentId = 'DSG-' + Date.now().toString(36).toUpperCase().slice(-8);
try {
const r = await fetch('/api/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
templateId: 'xiaohongshu',
presetId: document.getElementById('preset').value,
title, body,
layout: document.getElementById('layout').value
})
});
if(!r.ok) throw new Error('生成失败');
const d = await r.json();
document.getElementById('previewImg').src = d.url;
document.getElementById('previewImg').style.display = 'block';
document.getElementById('dlBtn').href = d.url;
document.getElementById('dlBtn').style.display = 'block';
document.getElementById('saveBtn').style.display = 'block';
document.getElementById('idBadge').style.display = 'block';
document.getElementById('idBadge').querySelector('.id').textContent = currentId;
// 意图链
if(d.intent_chain) {
document.getElementById('chain').innerHTML = d.intent_chain.map(s =>
'<div class="intent-item '+(s.who==='用户'?'user':'system')+'">'+
'<div style="font-size:14px;flex-shrink:0;">'+s.icon+'</div>'+
'<div>'+
'<div class="intent-who">'+s.who+'</div>'+
'<div class="intent-step">'+s.step+'</div>'+
'<div class="intent-detail">'+s.detail+'</div>'+
'</div></div>'
).join('');
}
// 自动保存到本地
saveToLocal();
} catch(e) {
document.getElementById('empty').style.display = 'block';
showErr(e.message);
} finally {
document.getElementById('genBtn').disabled = false;
document.getElementById('genBtn').textContent = '执行设计逻辑';
}
}
function saveToLocal() {
const saved = JSON.parse(localStorage.getItem(SAVED_KEY) || '[]');
saved.push({
id: currentId,
title: document.getElementById('title').value,
time: new Date().toISOString(),
});
localStorage.setItem(SAVED_KEY, JSON.stringify(saved.slice(-50)));
}
function saveId() {
toast('✅ 设计编号 ' + currentId + ' 已保存到本地');
}
function showErr(m) {
const e = document.getElementById('err');
e.textContent = m;
e.style.display = 'block';
setTimeout(() => e.style.display = 'none', 4000);
}
function toast(m) {
const t = document.getElementById('toast');
t.textContent = m;
t.classList.add('show');
setTimeout(() => t.classList.remove('show'), 2000);
}
document.addEventListener('keydown', e => {
if((e.metaKey || e.ctrlKey) && e.key === 'Enter' && document.getElementById('modal').classList.contains('show')) gen();
});
</script>
</body>
</html>