Spaces:
Sleeping
Sleeping
Commit ·
c2abd76
1
Parent(s): 94b7cac
优化
Browse files- static/css/styles.css +1 -1
- static/js/html2canvas.min.js +0 -0
- static/js/main.js +60 -3
- templates/index.html +3 -4
static/css/styles.css
CHANGED
|
@@ -31,7 +31,7 @@ input[type="range"]{width:100%}
|
|
| 31 |
.preview{overflow:auto}
|
| 32 |
.stage-wrap{background:#0b1224;border:1px solid var(--border);border-radius:16px;padding:12px}
|
| 33 |
.stage-toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;color:#94a3b8}
|
| 34 |
-
.stage{position:relative;margin:0 auto;background:#111827;border-radius:14px;box-shadow:0 8px 30px rgba(0,0,0,.35);overflow:hidden;width:960px;height:504px;display:flex;align-items:center;justify-content:center}
|
| 35 |
.logo-wrap{position:absolute;top:24px;left:24px;width:80px;height:80px;border-radius:12px;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center;overflow:hidden}
|
| 36 |
.logo-wrap img{max-width:70px;max-height:70px}
|
| 37 |
.content{padding:40px;text-align:center;max-width:85%}
|
|
|
|
| 31 |
.preview{overflow:auto}
|
| 32 |
.stage-wrap{background:#0b1224;border:1px solid var(--border);border-radius:16px;padding:12px}
|
| 33 |
.stage-toolbar{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;color:#94a3b8}
|
| 34 |
+
.stage{position:relative;margin:0 auto;background:#111827;border-radius:14px;box-shadow:0 8px 30px rgba(0,0,0,.35);overflow:hidden;width:960px;height:504px;display:flex;align-items:center;justify-content:center;background-size:cover;background-position:center;background-repeat:no-repeat}
|
| 35 |
.logo-wrap{position:absolute;top:24px;left:24px;width:80px;height:80px;border-radius:12px;background:rgba(255,255,255,.06);display:flex;align-items:center;justify-content:center;overflow:hidden}
|
| 36 |
.logo-wrap img{max-width:70px;max-height:70px}
|
| 37 |
.content{padding:40px;text-align:center;max-width:85%}
|
static/js/html2canvas.min.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
static/js/main.js
CHANGED
|
@@ -16,7 +16,8 @@ const state = {
|
|
| 16 |
gradient: "",
|
| 17 |
shadow: true,
|
| 18 |
padding: 64,
|
| 19 |
-
logo: null
|
|
|
|
| 20 |
};
|
| 21 |
|
| 22 |
function applySize() {
|
|
@@ -36,7 +37,9 @@ function applyTheme() {
|
|
| 36 |
const content = el("content");
|
| 37 |
|
| 38 |
// 背景
|
| 39 |
-
if (state.
|
|
|
|
|
|
|
| 40 |
stage.style.background = `linear-gradient(${state.gradient})`;
|
| 41 |
} else {
|
| 42 |
stage.style.background = state.bgColor;
|
|
@@ -150,6 +153,17 @@ function bindInputs() {
|
|
| 150 |
fr.readAsDataURL(file);
|
| 151 |
});
|
| 152 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 153 |
document.querySelectorAll(".preset").forEach((btn) => {
|
| 154 |
btn.addEventListener("click", () => {
|
| 155 |
const p = btn.dataset.preset;
|
|
@@ -198,6 +212,33 @@ function applyPreset(name) {
|
|
| 198 |
applyTheme();
|
| 199 |
}
|
| 200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
function resetAll() {
|
| 202 |
Object.assign(state, {
|
| 203 |
w: 1200, h: 630,
|
|
@@ -211,11 +252,13 @@ function resetAll() {
|
|
| 211 |
gradient: "",
|
| 212 |
shadow: true,
|
| 213 |
padding: 64,
|
| 214 |
-
logo: null
|
|
|
|
| 215 |
});
|
| 216 |
const wrap = el("logo");
|
| 217 |
wrap.style.display = "none";
|
| 218 |
el("logoImg").src = "";
|
|
|
|
| 219 |
el("titleInput").value = state.title;
|
| 220 |
el("subtitleInput").value = state.subtitle;
|
| 221 |
el("sizePreset").value = "1200x630";
|
|
@@ -259,5 +302,19 @@ function init() {
|
|
| 259 |
applyTheme();
|
| 260 |
}
|
| 261 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 262 |
window.addEventListener("DOMContentLoaded", init);
|
| 263 |
|
|
|
|
| 16 |
gradient: "",
|
| 17 |
shadow: true,
|
| 18 |
padding: 64,
|
| 19 |
+
logo: null,
|
| 20 |
+
bgImg: null
|
| 21 |
};
|
| 22 |
|
| 23 |
function applySize() {
|
|
|
|
| 37 |
const content = el("content");
|
| 38 |
|
| 39 |
// 背景
|
| 40 |
+
if (state.bgImg) {
|
| 41 |
+
stage.style.background = `url(${state.bgImg}) center/cover no-repeat`;
|
| 42 |
+
} else if (state.gradient) {
|
| 43 |
stage.style.background = `linear-gradient(${state.gradient})`;
|
| 44 |
} else {
|
| 45 |
stage.style.background = state.bgColor;
|
|
|
|
| 153 |
fr.readAsDataURL(file);
|
| 154 |
});
|
| 155 |
|
| 156 |
+
el("bgImgInput").addEventListener("change", (e) => {
|
| 157 |
+
const file = e.target.files && e.target.files[0];
|
| 158 |
+
if (!file) return;
|
| 159 |
+
const fr = new FileReader();
|
| 160 |
+
fr.onload = () => {
|
| 161 |
+
state.bgImg = fr.result;
|
| 162 |
+
applyTheme();
|
| 163 |
+
};
|
| 164 |
+
fr.readAsDataURL(file);
|
| 165 |
+
});
|
| 166 |
+
|
| 167 |
document.querySelectorAll(".preset").forEach((btn) => {
|
| 168 |
btn.addEventListener("click", () => {
|
| 169 |
const p = btn.dataset.preset;
|
|
|
|
| 212 |
applyTheme();
|
| 213 |
}
|
| 214 |
|
| 215 |
+
function randomTheme() {
|
| 216 |
+
const r = () => Math.floor(Math.random() * 256);
|
| 217 |
+
const rc = () => `#${r().toString(16).padStart(2,'0')}${r().toString(16).padStart(2,'0')}${r().toString(16).padStart(2,'0')}`;
|
| 218 |
+
|
| 219 |
+
state.bgColor = rc();
|
| 220 |
+
state.fgColor = rc();
|
| 221 |
+
state.gradient = Math.random() > 0.5 ? "" : `to right, ${state.bgColor}, ${rc()}`;
|
| 222 |
+
state.titleSize = 32 + Math.floor(Math.random() * 64);
|
| 223 |
+
state.subtitleSize = 18 + Math.floor(Math.random() * 30);
|
| 224 |
+
state.textAlign = ["left", "center", "right"][Math.floor(Math.random() * 3)];
|
| 225 |
+
state.shadow = Math.random() > 0.5;
|
| 226 |
+
state.padding = 24 + Math.floor(Math.random() * 96);
|
| 227 |
+
state.bgImg = null; // 随机时清除背景图
|
| 228 |
+
|
| 229 |
+
el("bgColor").value = state.bgColor;
|
| 230 |
+
el("fgColor").value = state.fgColor;
|
| 231 |
+
el("titleSize").value = state.titleSize;
|
| 232 |
+
el("subtitleSize").value = state.subtitleSize;
|
| 233 |
+
el("textAlign").value = state.textAlign;
|
| 234 |
+
el("gradient").value = state.gradient || ""; // 简单的处理
|
| 235 |
+
el("shadow").checked = state.shadow;
|
| 236 |
+
el("padding").value = state.padding;
|
| 237 |
+
el("bgImgInput").value = "";
|
| 238 |
+
|
| 239 |
+
applyTheme();
|
| 240 |
+
}
|
| 241 |
+
|
| 242 |
function resetAll() {
|
| 243 |
Object.assign(state, {
|
| 244 |
w: 1200, h: 630,
|
|
|
|
| 252 |
gradient: "",
|
| 253 |
shadow: true,
|
| 254 |
padding: 64,
|
| 255 |
+
logo: null,
|
| 256 |
+
bgImg: null
|
| 257 |
});
|
| 258 |
const wrap = el("logo");
|
| 259 |
wrap.style.display = "none";
|
| 260 |
el("logoImg").src = "";
|
| 261 |
+
el("bgImgInput").value = "";
|
| 262 |
el("titleInput").value = state.title;
|
| 263 |
el("subtitleInput").value = state.subtitle;
|
| 264 |
el("sizePreset").value = "1200x630";
|
|
|
|
| 302 |
applyTheme();
|
| 303 |
}
|
| 304 |
|
| 305 |
+
window.addEventListener("DOMContentLoaded", init);
|
| 306 |
+
|
| 307 |
+
a.href = data;
|
| 308 |
+
a.click();
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
function init() {
|
| 312 |
+
el("title").textContent = state.title;
|
| 313 |
+
el("subtitle").textContent = state.subtitle;
|
| 314 |
+
bindInputs();
|
| 315 |
+
applySize();
|
| 316 |
+
applyTheme();
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
window.addEventListener("DOMContentLoaded", init);
|
| 320 |
|
templates/index.html
CHANGED
|
@@ -5,8 +5,6 @@
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
<title>OG 社交预览图工坊 | OG Image Studio</title>
|
| 7 |
<link rel="stylesheet" href="/static/css/styles.css" />
|
| 8 |
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 9 |
-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 10 |
<script>
|
| 11 |
window.__APP_CONFIG__ = {
|
| 12 |
defaultTitle: "你的标题在这里",
|
|
@@ -25,7 +23,7 @@
|
|
| 25 |
<p>一键生成 1200×630/675 的社交分享封面,适配公众号/微博/小红书/推特</p>
|
| 26 |
</div>
|
| 27 |
</div>
|
| 28 |
-
<a class="link" href="https://huggingface.co/spaces/duqing2026" target="_blank" rel="noreferrer">Hugging Face Spaces</a>
|
| 29 |
</header>
|
| 30 |
|
| 31 |
<main class="container">
|
|
@@ -132,6 +130,7 @@
|
|
| 132 |
|
| 133 |
<div class="actions">
|
| 134 |
<button id="resetBtn" class="ghost">重置</button>
|
|
|
|
| 135 |
<button id="downloadBtn" class="primary">导出 PNG</button>
|
| 136 |
</div>
|
| 137 |
</section>
|
|
@@ -161,7 +160,7 @@
|
|
| 161 |
<a href="/healthz" target="_blank" rel="noreferrer">健康检查</a>
|
| 162 |
</footer>
|
| 163 |
|
| 164 |
-
<script src="
|
| 165 |
<script src="/static/js/main.js"></script>
|
| 166 |
</body>
|
| 167 |
</html>
|
|
|
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
| 6 |
<title>OG 社交预览图工坊 | OG Image Studio</title>
|
| 7 |
<link rel="stylesheet" href="/static/css/styles.css" />
|
|
|
|
|
|
|
| 8 |
<script>
|
| 9 |
window.__APP_CONFIG__ = {
|
| 10 |
defaultTitle: "你的标题在这里",
|
|
|
|
| 23 |
<p>一键生成 1200×630/675 的社交分享封面,适配公众号/微博/小红书/推特</p>
|
| 24 |
</div>
|
| 25 |
</div>
|
| 26 |
+
<!-- <a class="link" href="https://huggingface.co/spaces/duqing2026" target="_blank" rel="noreferrer">Hugging Face Spaces</a> -->
|
| 27 |
</header>
|
| 28 |
|
| 29 |
<main class="container">
|
|
|
|
| 130 |
|
| 131 |
<div class="actions">
|
| 132 |
<button id="resetBtn" class="ghost">重置</button>
|
| 133 |
+
<button id="randomBtn" class="ghost">🎲 随机</button>
|
| 134 |
<button id="downloadBtn" class="primary">导出 PNG</button>
|
| 135 |
</div>
|
| 136 |
</section>
|
|
|
|
| 160 |
<a href="/healthz" target="_blank" rel="noreferrer">健康检查</a>
|
| 161 |
</footer>
|
| 162 |
|
| 163 |
+
<script src="/static/js/html2canvas.min.js"></script>
|
| 164 |
<script src="/static/js/main.js"></script>
|
| 165 |
</body>
|
| 166 |
</html>
|