feat: 添加5套主题切换:深邃暗/纯净白/赛博朋克/莫兰迪/护眼绿
This commit is contained in:
19
index.html
19
index.html
@@ -20,12 +20,31 @@
|
|||||||
</svg>
|
</svg>
|
||||||
<span>图片生成器</span>
|
<span>图片生成器</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="header-right">
|
||||||
|
<div class="theme-switcher" id="themeSwitcher">
|
||||||
|
<button class="theme-btn active" data-theme="dark" title="深邃暗">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
|
||||||
|
</button>
|
||||||
|
<button class="theme-btn" data-theme="light" title="纯净白">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
|
||||||
|
</button>
|
||||||
|
<button class="theme-btn" data-theme="cyber" title="赛博朋克">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13,2 3,14 12,14 11,22 21,10 12,10 13,2"/></svg>
|
||||||
|
</button>
|
||||||
|
<button class="theme-btn" data-theme="morandi" title="莫兰迪">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="12" r="10"/></svg>
|
||||||
|
</button>
|
||||||
|
<button class="theme-btn" data-theme="green" title="护眼绿">
|
||||||
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 14.5v-9l6 4.5-6 4.5z"/></svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
<button class="icon-btn" id="openSettings" title="设置">
|
<button class="icon-btn" id="openSettings" title="设置">
|
||||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
<circle cx="12" cy="12" r="3"/>
|
<circle cx="12" cy="12" r="3"/>
|
||||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<!-- API Key Alert -->
|
<!-- API Key Alert -->
|
||||||
|
|||||||
120
style.css
120
style.css
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
:root {
|
/* ── Theme: 深邃暗(默认)─ */
|
||||||
|
:root,
|
||||||
|
[data-theme="dark"] {
|
||||||
--bg: #0f0f13;
|
--bg: #0f0f13;
|
||||||
--surface: #18181f;
|
--surface: #18181f;
|
||||||
--surface2: #1f1f28;
|
--surface2: #1f1f28;
|
||||||
@@ -18,6 +20,74 @@
|
|||||||
--ease: cubic-bezier(0.16, 1, 0.3, 1);
|
--ease: cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Theme: 纯净白 ─ */
|
||||||
|
[data-theme="light"] {
|
||||||
|
--bg: #f5f5f7;
|
||||||
|
--surface: #ffffff;
|
||||||
|
--surface2: #f0f0f4;
|
||||||
|
--border: rgba(0,0,0,0.08);
|
||||||
|
--accent: #6c5ce7;
|
||||||
|
--accent2: #5a4bd4;
|
||||||
|
--text: #1a1a2e;
|
||||||
|
--text2: #555570;
|
||||||
|
--text3: #9999aa;
|
||||||
|
--danger: #e74c3c;
|
||||||
|
--radius: 12px;
|
||||||
|
--radius2: 8px;
|
||||||
|
--ease: cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Theme: 赛博朋克 ─ */
|
||||||
|
[data-theme="cyber"] {
|
||||||
|
--bg: #0a0a14;
|
||||||
|
--surface: #10102a;
|
||||||
|
--surface2: #181840;
|
||||||
|
--border: rgba(0,255,255,0.12);
|
||||||
|
--accent: #00f0ff;
|
||||||
|
--accent2: #ff00aa;
|
||||||
|
--text: #e0f8ff;
|
||||||
|
--text2: #7aaccc;
|
||||||
|
--text3: #3a5a7a;
|
||||||
|
--danger: #ff2d55;
|
||||||
|
--radius: 12px;
|
||||||
|
--radius2: 8px;
|
||||||
|
--ease: cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Theme: 莫兰迪 ─ */
|
||||||
|
[data-theme="morandi"] {
|
||||||
|
--bg: #e8e4df;
|
||||||
|
--surface: #f2ede8;
|
||||||
|
--surface2: #ddd8d0;
|
||||||
|
--border: rgba(0,0,0,0.08);
|
||||||
|
--accent: #9b8fa0;
|
||||||
|
--accent2: #7a6f80;
|
||||||
|
--text: #4a4540;
|
||||||
|
--text2: #7a7068;
|
||||||
|
--text3: #a09890;
|
||||||
|
--danger: #c09080;
|
||||||
|
--radius: 12px;
|
||||||
|
--radius2: 8px;
|
||||||
|
--ease: cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Theme: 护眼绿 ─ */
|
||||||
|
[data-theme="green"] {
|
||||||
|
--bg: #1a2416;
|
||||||
|
--surface: #222e1e;
|
||||||
|
--surface2: #2a3a24;
|
||||||
|
--border: rgba(120,200,80,0.12);
|
||||||
|
--accent: #78c850;
|
||||||
|
--accent2: #9fd878;
|
||||||
|
--text: #d4e8c0;
|
||||||
|
--text2: #90b888;
|
||||||
|
--text3: #5a7848;
|
||||||
|
--danger: #e87070;
|
||||||
|
--radius: 12px;
|
||||||
|
--radius2: 8px;
|
||||||
|
--ease: cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
}
|
||||||
|
|
||||||
html, body {
|
html, body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
@@ -26,8 +96,11 @@ html, body {
|
|||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
|
transition: background 0.3s, color 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#app { transition: background 0.3s; }
|
||||||
|
|
||||||
button { cursor: pointer; font-family: inherit; }
|
button { cursor: pointer; font-family: inherit; }
|
||||||
a { color: var(--accent2); text-decoration: none; }
|
a { color: var(--accent2); text-decoration: none; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { text-decoration: underline; }
|
||||||
@@ -50,6 +123,51 @@ header {
|
|||||||
padding: 22px 0 24px;
|
padding: 22px 0 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Theme Switcher ─────────────────────────────────────────── */
|
||||||
|
|
||||||
|
.theme-switcher {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 2px;
|
||||||
|
background: var(--surface);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
border-radius: 24px;
|
||||||
|
padding: 3px 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-btn {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text3);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, color 0.15s, transform 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-btn:hover {
|
||||||
|
color: var(--text);
|
||||||
|
background: var(--surface2);
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-btn.active {
|
||||||
|
background: var(--accent);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-btn.active svg { stroke: #fff; fill: #fff; }
|
||||||
|
|
||||||
.logo {
|
.logo {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
18
ui.js
18
ui.js
@@ -282,6 +282,24 @@ saveSettingsBtn.addEventListener('click', async () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ── Theme switcher ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
function applyTheme(theme) {
|
||||||
|
document.documentElement.dataset.theme = theme;
|
||||||
|
localStorage.setItem('imgGen-theme', theme);
|
||||||
|
document.querySelectorAll('.theme-btn').forEach(btn =>
|
||||||
|
btn.classList.toggle('active', btn.dataset.theme === theme)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.theme-btn').forEach(btn => {
|
||||||
|
btn.addEventListener('click', () => applyTheme(btn.dataset.theme));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Restore saved theme
|
||||||
|
const savedTheme = localStorage.getItem('imgGen-theme');
|
||||||
|
if (savedTheme) applyTheme(savedTheme);
|
||||||
|
|
||||||
// ── Start ──────────────────────────────────────────────────────
|
// ── Start ──────────────────────────────────────────────────────
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|||||||
Reference in New Issue
Block a user