feat(ui): 全站统一首页墨黑中性风格,固定亮色并移除光暗切换
- 全站紫/青/粉写死色值与 CSS 变量改为墨黑中性色板 - 移除 aurora 光斑/星点装饰,登录弹窗改纯白卡片 - theme.js 固定亮色并清除历史 dark 选择,删除前台/后台/画布切换按钮 - 模型页空状态文案对齐「保存渠道即自动同步」 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -7,8 +7,8 @@ const contact = computed(() => site.contact || {})
|
||||
const powers = [
|
||||
{ icon: 't2i', title: '文字生图', desc: '一句话出图,画幅与分辨率随模型可选。', tint: 'linear-gradient(135deg,#34d399,#2dd4bf)' },
|
||||
{ icon: 'i2i', title: '参考图生图', desc: '上传参考换风格、改构图、做变体。', tint: 'linear-gradient(135deg,#e879f9,#f472b6)' },
|
||||
{ icon: 't2v', title: '文字生视频', desc: '一段描述生成短片,时长分辨率可选。', tint: 'linear-gradient(135deg,#38bdf8,#22d3ee)' },
|
||||
{ icon: 'i2v', title: '图生视频', desc: '给张参考图,让静态画面动起来。', tint: 'linear-gradient(135deg,#7c5cfc,#a855f7)' },
|
||||
{ icon: 't2v', title: '文字生视频', desc: '一段描述生成短片,时长分辨率可选。', tint: 'linear-gradient(135deg,#38bdf8,#52525b)' },
|
||||
{ icon: 'i2v', title: '图生视频', desc: '给张参考图,让静态画面动起来。', tint: 'linear-gradient(135deg,#18181b,#3f3f46)' },
|
||||
]
|
||||
</script>
|
||||
|
||||
@@ -154,7 +154,7 @@ const powers = [
|
||||
box-shadow: var(--glass-shadow);
|
||||
transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
|
||||
}
|
||||
.power-card:hover { transform: translateY(-3px); border-color: rgb(124 92 252 / 0.45); box-shadow: var(--glass-shadow-lg); }
|
||||
.power-card:hover { transform: translateY(-3px); border-color: rgb(24 24 27 / 0.45); box-shadow: var(--glass-shadow-lg); }
|
||||
.power-ico {
|
||||
width: 2.6rem;
|
||||
height: 2.6rem;
|
||||
@@ -162,7 +162,7 @@ const powers = [
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: #fff;
|
||||
box-shadow: 0 6px 16px rgb(124 92 252 / 0.28);
|
||||
box-shadow: 0 6px 16px rgb(24 24 27 / 0.28);
|
||||
}
|
||||
.power-ico svg { width: 1.3rem; height: 1.3rem; }
|
||||
@media (max-width: 768px) { .ab-cluster { display: none; } }
|
||||
|
||||
@@ -1119,7 +1119,7 @@ const saveLabel = computed(() => ({
|
||||
}
|
||||
.cv-btn:hover:not(:disabled) {
|
||||
background: var(--hover);
|
||||
border-color: rgb(124 92 252 / 0.45);
|
||||
border-color: rgb(24 24 27 / 0.45);
|
||||
box-shadow: 0 4px 14px var(--accent-glow);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
@@ -1136,13 +1136,13 @@ const saveLabel = computed(() => ({
|
||||
box-shadow: 0 4px 14px rgb(229 72 77 / 0.25);
|
||||
}
|
||||
.cv-btn--accent {
|
||||
background: linear-gradient(120deg, rgb(124 92 252 / 0.16), rgb(168 85 247 / 0.14));
|
||||
border-color: rgb(124 92 252 / 0.42);
|
||||
background: linear-gradient(120deg, rgb(24 24 27 / 0.16), rgb(168 85 247 / 0.14));
|
||||
border-color: rgb(24 24 27 / 0.42);
|
||||
color: var(--m-orange);
|
||||
}
|
||||
.cv-btn--accent:hover:not(:disabled) {
|
||||
background: linear-gradient(120deg, rgb(124 92 252 / 0.26), rgb(168 85 247 / 0.22));
|
||||
border-color: rgb(124 92 252 / 0.62);
|
||||
background: linear-gradient(120deg, rgb(24 24 27 / 0.26), rgb(168 85 247 / 0.22));
|
||||
border-color: rgb(24 24 27 / 0.62);
|
||||
box-shadow: 0 4px 16px var(--accent-glow);
|
||||
}
|
||||
.cv-select,
|
||||
@@ -1157,8 +1157,8 @@ const saveLabel = computed(() => ({
|
||||
}
|
||||
.cv-select:focus,
|
||||
.cv-input:focus {
|
||||
border-color: rgb(124 92 252 / 0.6);
|
||||
box-shadow: 0 0 0 3px rgb(124 92 252 / 0.18);
|
||||
border-color: rgb(24 24 27 / 0.6);
|
||||
box-shadow: 0 0 0 3px rgb(24 24 27 / 0.18);
|
||||
}
|
||||
|
||||
.cv-page {
|
||||
@@ -1225,7 +1225,7 @@ const saveLabel = computed(() => ({
|
||||
min-width: 46px;
|
||||
text-align: center;
|
||||
background: var(--hover);
|
||||
border: 1px solid rgb(124 92 252 / 0.35);
|
||||
border: 1px solid rgb(24 24 27 / 0.35);
|
||||
border-radius: 999px;
|
||||
padding: 1px 8px;
|
||||
}
|
||||
@@ -1266,9 +1266,9 @@ const saveLabel = computed(() => ({
|
||||
font-size: 15px;
|
||||
font-weight: 800;
|
||||
color: var(--fg);
|
||||
border: 2px dashed rgb(34 211 238 / 0.6);
|
||||
border: 2px dashed rgb(24 24 27 / 0.6);
|
||||
border-radius: 18px;
|
||||
background: rgb(34 211 238 / 0.1);
|
||||
background: rgb(24 24 27 / 0.1);
|
||||
pointer-events: none;
|
||||
}
|
||||
.cv-loading,
|
||||
@@ -1318,11 +1318,11 @@ const saveLabel = computed(() => ({
|
||||
}
|
||||
.cv-chip:hover {
|
||||
background: var(--hover);
|
||||
border-color: rgb(124 92 252 / 0.4);
|
||||
border-color: rgb(24 24 27 / 0.4);
|
||||
}
|
||||
.cv-chip.is-on {
|
||||
color: #fff;
|
||||
background: linear-gradient(120deg, #7c5cfc, #5f6cf8);
|
||||
background: linear-gradient(120deg, #18181b, #27272a);
|
||||
border-color: transparent;
|
||||
box-shadow: 0 4px 14px var(--accent-glow);
|
||||
}
|
||||
@@ -1332,7 +1332,7 @@ const saveLabel = computed(() => ({
|
||||
border: 1px solid var(--glass-border);
|
||||
border-radius: 22px;
|
||||
background:
|
||||
linear-gradient(160deg, rgb(124 92 252 / 0.06), transparent 40%),
|
||||
linear-gradient(160deg, rgb(24 24 27 / 0.06), transparent 40%),
|
||||
var(--surface);
|
||||
-webkit-backdrop-filter: blur(22px) saturate(1.15);
|
||||
backdrop-filter: blur(22px) saturate(1.15);
|
||||
@@ -1341,8 +1341,8 @@ const saveLabel = computed(() => ({
|
||||
overflow: visible; /* 下拉面板要从输入框上方弹出,不能被裁切 */
|
||||
}
|
||||
.cv-composer:focus-within {
|
||||
border-color: rgb(124 92 252 / 0.55);
|
||||
box-shadow: var(--glass-shadow-lg), 0 0 0 3px rgb(124 92 252 / 0.16), 0 0 42px var(--accent-glow);
|
||||
border-color: rgb(24 24 27 / 0.55);
|
||||
box-shadow: var(--glass-shadow-lg), 0 0 0 3px rgb(24 24 27 / 0.16), 0 0 42px var(--accent-glow);
|
||||
}
|
||||
.cv-composer__refs {
|
||||
display: flex;
|
||||
@@ -1399,8 +1399,8 @@ const saveLabel = computed(() => ({
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: 12px;
|
||||
border: 1.5px dashed rgb(124 92 252 / 0.5);
|
||||
background: rgb(124 92 252 / 0.04);
|
||||
border: 1.5px dashed rgb(24 24 27 / 0.5);
|
||||
background: rgb(24 24 27 / 0.04);
|
||||
color: var(--m-orange);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -1414,7 +1414,7 @@ const saveLabel = computed(() => ({
|
||||
}
|
||||
.cv-refadd:hover {
|
||||
border-color: var(--m-orange);
|
||||
background: rgb(124 92 252 / 0.1);
|
||||
background: rgb(24 24 27 / 0.1);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px var(--accent-glow);
|
||||
}
|
||||
@@ -1468,7 +1468,7 @@ const saveLabel = computed(() => ({
|
||||
padding: 10px;
|
||||
border-radius: 11px;
|
||||
border: 1px solid rgb(255 255 255 / 0.18);
|
||||
background: linear-gradient(120deg, #7c5cfc, #5f6cf8 55%, #22d3ee 140%);
|
||||
background: linear-gradient(120deg, #18181b, #27272a 55%, #52525b 140%);
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
font-weight: 800;
|
||||
@@ -1593,14 +1593,14 @@ const saveLabel = computed(() => ({
|
||||
}
|
||||
.cv-picker__grid img:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: rgb(124 92 252 / 0.55);
|
||||
border-color: rgb(24 24 27 / 0.55);
|
||||
box-shadow: 0 8px 20px var(--accent-glow);
|
||||
}
|
||||
.cv-picker__up {
|
||||
width: 100%;
|
||||
aspect-ratio: 1;
|
||||
border-radius: 10px;
|
||||
border: 2px dashed rgb(124 92 252 / 0.45);
|
||||
border: 2px dashed rgb(24 24 27 / 0.45);
|
||||
background: transparent;
|
||||
color: var(--m-orange);
|
||||
display: flex;
|
||||
@@ -1616,7 +1616,7 @@ const saveLabel = computed(() => ({
|
||||
.cv-picker__up:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--m-orange);
|
||||
background: rgb(124 92 252 / 0.08);
|
||||
background: rgb(24 24 27 / 0.08);
|
||||
box-shadow: 0 8px 20px var(--accent-glow);
|
||||
}
|
||||
.cv-picker__up:disabled {
|
||||
|
||||
@@ -279,7 +279,7 @@ onMounted(load)
|
||||
:class="!picked.has(s.id) && 'opacity-45'">
|
||||
<div class="flex items-center gap-2.5 min-w-0">
|
||||
<span class="w-2 h-2 rounded-full shrink-0"
|
||||
:class="s.kind === 'video' ? 'bg-sky-400' : s.kind === 'text' ? 'bg-amber-400' : 'bg-indigo-400'"></span>
|
||||
:class="s.kind === 'video' ? 'bg-sky-400' : s.kind === 'text' ? 'bg-amber-400' : 'bg-zinc-500'"></span>
|
||||
<code class="font-mono text-[13px] font-semibold text-white/90 truncate">{{ s.id }}</code>
|
||||
<span class="text-[11px] font-semibold text-white/40 shrink-0">{{ KIND_LABEL[s.kind] || s.kind }}</span>
|
||||
<button type="button" class="ml-auto sw" :class="picked.has(s.id) && 'sw-on'"
|
||||
|
||||
@@ -656,7 +656,7 @@ html.dark .hint b { color: rgb(253 164 175); } /* rose — visible warning, no
|
||||
box-shadow: 0 1px 2px rgb(15 23 42 / 0.2);
|
||||
transition: transform 0.18s ease;
|
||||
}
|
||||
.sw:checked { background: #4f46e5; } /* sky-600 — matches btn-primary */
|
||||
.sw:checked { background: #27272a; } /* sky-600 — matches btn-primary */
|
||||
.sw:checked::after { transform: translateX(calc(2.25rem - 1.3rem)); }
|
||||
.sw:focus-visible { box-shadow: 0 0 0 3px rgb(236 91 19 / 0.3); }
|
||||
.sw:disabled { cursor: not-allowed; opacity: 0.55; }
|
||||
@@ -677,8 +677,8 @@ html.dark .num, html.dark .txt, html.dark .field {
|
||||
}
|
||||
.num::placeholder, .txt::placeholder, .field::placeholder { color: var(--fg-faint); }
|
||||
.num:focus, .txt:focus, .field:focus {
|
||||
border-color: rgb(124 92 252 / 0.65);
|
||||
box-shadow: 0 0 0 3px rgb(124 92 252 / 0.18);
|
||||
border-color: rgb(24 24 27 / 0.65);
|
||||
box-shadow: 0 0 0 3px rgb(24 24 27 / 0.18);
|
||||
}
|
||||
.num:disabled, .txt:disabled, .field:disabled { opacity: 0.45; cursor: not-allowed; }
|
||||
.num { width: 6rem; padding: 0.4rem 0.55rem; font-size: 0.8rem; text-align: right; -moz-appearance: textfield; appearance: textfield; }
|
||||
@@ -692,7 +692,7 @@ html.dark .num, html.dark .txt, html.dark .field {
|
||||
.btn-primary {
|
||||
padding: 0.55rem 1.15rem; border-radius: 0.6rem;
|
||||
font-size: 0.8rem; font-weight: 800; color: white;
|
||||
background: linear-gradient(120deg, #7c5cfc, #5f6cf8);
|
||||
background: linear-gradient(120deg, #18181b, #27272a);
|
||||
border: 1px solid rgb(255 255 255 / 0.16);
|
||||
box-shadow: 0 6px 18px var(--accent-glow);
|
||||
transition: filter 0.15s, transform 0.12s, box-shadow 0.15s, opacity 0.15s;
|
||||
|
||||
@@ -739,7 +739,7 @@ html.dark .art { border-color: var(--ink-soft); }
|
||||
height: 40px;
|
||||
border-radius: 12px;
|
||||
background: rgba(24, 24, 27, 0.12);
|
||||
color: #7c3aed;
|
||||
color: #18181b;
|
||||
}
|
||||
.feature h3 {
|
||||
margin-top: 16px;
|
||||
|
||||
@@ -328,7 +328,7 @@ onUnmounted(() => window.removeEventListener('keydown', onKey))
|
||||
<span v-if="f.resolution" class="text-emerald-300/90">{{ f.resolution }}</span>
|
||||
<span v-if="f.ratio" class="text-white/40">{{ f.ratio }}</span>
|
||||
<span v-if="f.kind === 'video' && f.duration" class="text-rose-300/80">{{ f.duration }}</span>
|
||||
<span v-if="f.deai" class="text-[#a78bfa]">去AI</span>
|
||||
<span v-if="f.deai" class="text-[#71717a]">去AI</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[10px] text-white/35 mt-0.5 tabular-nums">{{ fmtSize(f.size) }} · {{ fmtTs(f.mtime) }}</div>
|
||||
|
||||
@@ -88,7 +88,7 @@ function toast(m) {
|
||||
<section class="relative rounded-2xl p-7 md:p-8 overflow-hidden ink-card">
|
||||
<div class="memphis-dots absolute inset-0 opacity-30 pointer-events-none"></div>
|
||||
<div class="relative inline-grid w-11 h-11 rounded-xl text-white place-items-center"
|
||||
style="background: linear-gradient(135deg, #7c5cfc, #22d3ee); box-shadow: 0 8px 20px var(--accent-glow)">
|
||||
style="background: linear-gradient(135deg, #18181b, #52525b); box-shadow: 0 8px 20px var(--accent-glow)">
|
||||
<Icon name="accounts" class="w-5 h-5" />
|
||||
</div>
|
||||
|
||||
@@ -114,7 +114,7 @@ function toast(m) {
|
||||
</button>
|
||||
<button @click="copyInvite"
|
||||
class="rounded-xl border border-white/20 text-white px-5 py-3 text-sm font-extrabold hover:-translate-y-0.5 active:translate-y-0.5 transition-all"
|
||||
style="background: linear-gradient(120deg, #7c5cfc, #22d3ee); box-shadow: 0 8px 20px var(--accent-glow)">
|
||||
style="background: linear-gradient(120deg, #18181b, #52525b); box-shadow: 0 8px 20px var(--accent-glow)">
|
||||
复制链接
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -327,7 +327,7 @@ const sourcePill = (s) => ({
|
||||
</template>
|
||||
<template v-if="e.deai">
|
||||
<span class="text-white/25 mx-1.5">·</span>
|
||||
<span class="text-[#a78bfa]">去AI特征</span>
|
||||
<span class="text-[#71717a]">去AI特征</span>
|
||||
</template>
|
||||
</td>
|
||||
<td class="px-3 py-3.5 text-right text-xs tabular-nums align-middle whitespace-nowrap">
|
||||
|
||||
@@ -123,7 +123,7 @@ onMounted(loadModels)
|
||||
<div v-else-if="!filtered.length" class="flex flex-col items-center gap-3 text-white/40 py-20">
|
||||
<span class="w-14 h-14 rounded-2xl bg-white/[0.04] grid place-items-center"><Icon name="models" class="w-6 h-6" /></span>
|
||||
<span v-if="models.length" class="text-sm">没有匹配的模型</span>
|
||||
<router-link v-else to="/admin/channels" class="text-sm text-sky-300 underline underline-offset-2">还没有模型,先到「渠道管理」勾选上游模型自动导入</router-link>
|
||||
<router-link v-else to="/admin/channels" class="text-sm text-sky-300 underline underline-offset-2">还没有模型,先到「渠道管理」添加渠道,保存后会自动同步上游模型</router-link>
|
||||
</div>
|
||||
|
||||
<table v-else class="w-full text-sm table-fixed">
|
||||
|
||||
@@ -1076,7 +1076,7 @@ onUnmounted(() => {
|
||||
<div class="pg-cap text-[11px] leading-tight font-medium line-clamp-2 transition-colors"
|
||||
:class="item.prompt ? 'pointer-events-auto cursor-pointer' : ''"
|
||||
:title="item.prompt ? '点击复制提示词' : ''" @click.stop="copyPrompt(item)">{{ item.prompt }}</div>
|
||||
<div class="pg-cap-sub text-[9px] mt-0.5 font-mono truncate">{{ item.model }}<span v-if="item.deai"> · <span class="text-[#a78bfa]">去AI</span></span><span v-if="item.elapsed_ms"> · {{ (item.elapsed_ms / 1000).toFixed(1) }}s</span></div>
|
||||
<div class="pg-cap-sub text-[9px] mt-0.5 font-mono truncate">{{ item.model }}<span v-if="item.deai"> · <span class="text-[#71717a]">去AI</span></span><span v-if="item.elapsed_ms"> · {{ (item.elapsed_ms / 1000).toFixed(1) }}s</span></div>
|
||||
</div>
|
||||
</template>
|
||||
<!-- pending / running -->
|
||||
|
||||
@@ -273,7 +273,7 @@ async function recharge() {
|
||||
<section class="lg:col-span-2 card overflow-hidden">
|
||||
<div class="p-7 md:p-8 relative">
|
||||
<div class="absolute -top-16 -right-16 w-48 h-48 rounded-full opacity-30 blur-3xl"
|
||||
style="background: radial-gradient(circle,#8b5cf6,transparent 60%)"></div>
|
||||
style="background: radial-gradient(circle,#27272a,transparent 60%)"></div>
|
||||
<div class="relative grid md:grid-cols-[260px_1fr] gap-8 items-start">
|
||||
<div>
|
||||
<div class="inline-grid w-10 h-10 rounded-xl bg-orange-500/15 ring-1 ring-orange-400/30 grid place-items-center text-orange-300">
|
||||
|
||||
@@ -257,7 +257,7 @@ const params = (e) => {
|
||||
:title="e.error + ' — 点击复制'"
|
||||
@click.stop="copyError(e)">⚠ {{ e.error }}</div>
|
||||
</td>
|
||||
<td class="px-3 py-3 align-middle text-xs text-slate-500 tabular-nums">{{ params(e) || '—' }}<span v-if="e.deai"> · <span class="text-[#a78bfa]">去AI特征</span></span></td>
|
||||
<td class="px-3 py-3 align-middle text-xs text-slate-500 tabular-nums">{{ params(e) || '—' }}<span v-if="e.deai"> · <span class="text-[#71717a]">去AI特征</span></span></td>
|
||||
<td class="px-3 py-3 align-middle text-right text-xs text-slate-700 tabular-nums">{{ e.cost ? points(e.cost) : '—' }}</td>
|
||||
<td class="px-3 py-3 align-middle text-right text-xs text-slate-500 tabular-nums">{{ e.elapsed_ms ? (e.elapsed_ms / 1000).toFixed(1) + 's' : '—' }}</td>
|
||||
</tr>
|
||||
|
||||
@@ -361,7 +361,7 @@ onUnmounted(() => {
|
||||
<span v-if="e.resolution" class="text-emerald-300/90">{{ e.resolution }}</span>
|
||||
<span v-if="e.ratio" class="text-white/40">{{ e.ratio }}</span>
|
||||
<span v-if="e.kind === 'video' && e.duration" class="text-rose-300/80">{{ e.duration }}</span>
|
||||
<span v-if="e.deai" class="text-[#a78bfa]">去AI</span>
|
||||
<span v-if="e.deai" class="text-[#71717a]">去AI</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-[10px] text-white/35 mt-0.5 tabular-nums">{{ fmtTs(e.ts) }}<span v-if="e.elapsed_ms"> · {{ fmtMs(e.elapsed_ms) }}</span></div>
|
||||
|
||||
Reference in New Issue
Block a user