style: apply oasis glass theme to workspace
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
@tailwind utilities;
|
||||
|
||||
html, body {
|
||||
background: #0A0A0F;
|
||||
background: #030603;
|
||||
color: #FFFFFF;
|
||||
font-feature-settings: "cv02", "cv03", "cv04", "cv11", "ss01";
|
||||
-webkit-font-smoothing: antialiased;
|
||||
@@ -12,88 +12,155 @@ html, body {
|
||||
|
||||
body {
|
||||
font-family: ui-sans-serif, system-ui, -apple-system, "SF Pro Text", "PingFang SC", "Noto Sans SC", "Helvetica Neue", sans-serif;
|
||||
background-color: #0A0A0F;
|
||||
background-image:
|
||||
radial-gradient(circle at 18% -10%, rgba(139, 92, 246, 0.22), transparent 55%),
|
||||
radial-gradient(circle at 88% 8%, rgba(59, 130, 246, 0.18), transparent 50%),
|
||||
radial-gradient(circle at 50% 110%, rgba(217, 70, 239, 0.12), transparent 60%);
|
||||
background-color: #030603;
|
||||
background-image: linear-gradient(180deg, rgba(13, 24, 12, 0.9), rgba(2, 4, 2, 1));
|
||||
background-attachment: fixed;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
::selection { background: rgba(139, 92, 246, 0.35); color: #fff; }
|
||||
::selection { background: rgba(230, 245, 120, 0.28); color: #fff; }
|
||||
|
||||
.app-oasis .login-oasis-canvas {
|
||||
z-index: 0;
|
||||
opacity: 0.74;
|
||||
filter: saturate(0.92) contrast(1.04);
|
||||
}
|
||||
|
||||
.app-oasis-shade {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
background:
|
||||
linear-gradient(90deg, rgba(0, 0, 0, 0.76), rgba(3, 9, 3, 0.46) 42%, rgba(0, 0, 0, 0.72)),
|
||||
linear-gradient(180deg, rgba(0, 0, 0, 0.68), rgba(0, 0, 0, 0.12) 36%, rgba(0, 0, 0, 0.82)),
|
||||
linear-gradient(90deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px);
|
||||
background-size: auto, auto, 64px 64px, 64px 64px;
|
||||
}
|
||||
|
||||
.app-grass-floor {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
height: 34vh;
|
||||
pointer-events: none;
|
||||
opacity: 0.38;
|
||||
background:
|
||||
linear-gradient(180deg, transparent, rgba(5, 12, 4, 0.78) 60%, rgba(0, 0, 0, 0.94)),
|
||||
repeating-linear-gradient(103deg, transparent 0 13px, rgba(188, 218, 112, 0.13) 13px 14px, transparent 14px 28px),
|
||||
repeating-linear-gradient(78deg, transparent 0 18px, rgba(84, 122, 67, 0.18) 18px 20px, transparent 20px 34px);
|
||||
mask-image: linear-gradient(180deg, transparent, rgba(0, 0, 0, 0.8) 38%, #000 100%);
|
||||
}
|
||||
|
||||
/* ===== Buttons ===== */
|
||||
.btn {
|
||||
@apply inline-flex items-center justify-center gap-1.5 px-4 py-2 rounded-xl text-sm font-medium transition-all;
|
||||
@apply inline-flex items-center justify-center gap-1.5 px-4 py-2 rounded-[8px] text-sm font-medium transition-all;
|
||||
}
|
||||
.btn-primary {
|
||||
@apply text-white bg-gradient-to-r from-violet-500 via-indigo-500 to-blue-500 hover:brightness-110 active:scale-[0.98];
|
||||
@apply active:scale-[0.98];
|
||||
background: linear-gradient(135deg, rgba(230, 245, 120, 0.96), rgba(214, 179, 106, 0.94));
|
||||
color: #081006;
|
||||
box-shadow: 0 6px 24px -8px rgba(99, 102, 241, 0.6), inset 0 1px 0 rgba(255,255,255,0.18);
|
||||
}
|
||||
.btn-primary:hover {
|
||||
filter: brightness(1.06);
|
||||
}
|
||||
.btn-ghost {
|
||||
@apply text-white/80 bg-white/[0.05] hover:bg-white/[0.09] border border-white/[0.08] active:scale-[0.98];
|
||||
@apply text-white/80 active:scale-[0.98];
|
||||
border: 1px solid rgba(140, 180, 120, 0.14);
|
||||
background: rgba(10, 18, 10, 0.34);
|
||||
}
|
||||
.btn-outline {
|
||||
@apply text-white/80 bg-white/[0.03] hover:bg-white/[0.07] border border-white/[0.1] hover:border-white/[0.18] active:scale-[0.98];
|
||||
@apply text-white/80 active:scale-[0.98];
|
||||
border: 1px solid rgba(140, 180, 120, 0.16);
|
||||
background: rgba(10, 18, 10, 0.28);
|
||||
}
|
||||
.btn-glass {
|
||||
@apply text-white bg-white/[0.06] hover:bg-white/[0.10] border border-white/[0.12] backdrop-blur-xl active:scale-[0.98];
|
||||
@apply text-white backdrop-blur-xl active:scale-[0.98];
|
||||
border: 1px solid rgba(140, 180, 120, 0.18);
|
||||
background: rgba(10, 18, 10, 0.42);
|
||||
}
|
||||
|
||||
/* ===== Cards (glass) ===== */
|
||||
.card {
|
||||
@apply relative rounded-3xl bg-white/[0.035] border border-white/[0.08] backdrop-blur-xl;
|
||||
@apply relative rounded-[8px] backdrop-blur-xl;
|
||||
border: 1px solid rgba(140, 180, 120, 0.14);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(17, 28, 13, 0.62), rgba(5, 10, 5, 0.54)),
|
||||
rgba(10, 18, 10, 0.42);
|
||||
box-shadow:
|
||||
0 1px 0 0 rgba(255,255,255,0.06) inset,
|
||||
0 18px 60px -24px rgba(0,0,0,0.6);
|
||||
0 1px 0 0 rgba(255,255,255,0.08) inset,
|
||||
0 22px 70px -30px rgba(0,0,0,0.82),
|
||||
0 0 42px -34px rgba(230, 245, 120, 0.64);
|
||||
}
|
||||
.card-2 {
|
||||
@apply rounded-2xl bg-white/[0.03] border border-white/[0.07] backdrop-blur-xl;
|
||||
@apply rounded-[8px] backdrop-blur-xl;
|
||||
border: 1px solid rgba(140, 180, 120, 0.12);
|
||||
background: rgba(8, 16, 8, 0.42);
|
||||
}
|
||||
.card-hover {
|
||||
@apply transition-all hover:border-white/[0.14];
|
||||
@apply transition-all;
|
||||
}
|
||||
.card-hover:hover,
|
||||
.card:hover {
|
||||
border-color: rgba(140, 180, 120, 0.28);
|
||||
}
|
||||
|
||||
/* ===== Chips ===== */
|
||||
.chip {
|
||||
@apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-[11px] font-medium border;
|
||||
@apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-[8px] text-[11px] font-medium border;
|
||||
}
|
||||
.chip-mock {
|
||||
@apply bg-amber-500/10 text-amber-300 border-amber-400/30;
|
||||
}
|
||||
.chip-live {
|
||||
@apply bg-emerald-500/10 text-emerald-300 border-emerald-400/30;
|
||||
@apply border-emerald-400/30;
|
||||
background: rgba(142, 190, 104, 0.13);
|
||||
color: #dff5a8;
|
||||
}
|
||||
.chip-neutral {
|
||||
@apply bg-white/[0.05] text-white/70 border-white/[0.12];
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
border-color: rgba(140, 180, 120, 0.14);
|
||||
background: rgba(10, 18, 10, 0.34);
|
||||
}
|
||||
.chip-violet {
|
||||
@apply bg-violet-500/15 text-violet-200 border-violet-400/30;
|
||||
border-color: rgba(230, 245, 120, 0.28);
|
||||
background: rgba(230, 245, 120, 0.12);
|
||||
color: #e6f578;
|
||||
}
|
||||
|
||||
/* ===== Segmented ===== */
|
||||
.seg {
|
||||
@apply inline-flex p-1 bg-white/[0.04] border border-white/[0.07] rounded-xl gap-1;
|
||||
@apply inline-flex p-1 rounded-[8px] gap-1;
|
||||
border: 1px solid rgba(140, 180, 120, 0.13);
|
||||
background: rgba(10, 18, 10, 0.36);
|
||||
backdrop-filter: blur(16px);
|
||||
}
|
||||
.seg-item {
|
||||
@apply px-3 py-1.5 rounded-lg text-xs font-medium text-white/55 transition-all cursor-pointer;
|
||||
@apply px-3 py-1.5 rounded-[7px] text-xs font-medium text-white/55 transition-all cursor-pointer;
|
||||
}
|
||||
.seg-item-active {
|
||||
@apply text-white;
|
||||
background: linear-gradient(135deg, rgba(139,92,246,0.35), rgba(59,130,246,0.25));
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.18), 0 4px 16px -8px rgba(99,102,241,0.6);
|
||||
color: #081006;
|
||||
background: linear-gradient(135deg, rgba(230,245,120,0.92), rgba(214,179,106,0.86));
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.35), 0 4px 16px -8px rgba(230,245,120,0.6);
|
||||
}
|
||||
|
||||
/* ===== Tiles ===== */
|
||||
.tile {
|
||||
@apply relative aspect-square overflow-hidden rounded-2xl bg-white/[0.04] ring-1 ring-white/[0.08] transition-all cursor-pointer;
|
||||
@apply relative aspect-square overflow-hidden rounded-[8px] transition-all cursor-pointer;
|
||||
background: rgba(10, 18, 10, 0.44);
|
||||
box-shadow: 0 1px 0 rgba(255,255,255,0.08) inset, 0 18px 50px -28px rgba(0,0,0,0.8);
|
||||
--tw-ring-color: rgba(140, 180, 120, 0.14);
|
||||
border: 1px solid rgba(140, 180, 120, 0.1);
|
||||
}
|
||||
.tile-selected {
|
||||
position: relative;
|
||||
background: linear-gradient(#0A0A0F, #0A0A0F) padding-box, linear-gradient(135deg, #8B5CF6, #3B82F6) border-box;
|
||||
background: linear-gradient(#071006, #071006) padding-box, linear-gradient(135deg, #e6f578, #d6b36a) border-box;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 0 0 1px rgba(139,92,246,0.25), 0 8px 32px -8px rgba(139,92,246,0.55);
|
||||
box-shadow: 0 0 0 1px rgba(230,245,120,0.22), 0 8px 32px -8px rgba(230,245,120,0.46);
|
||||
}
|
||||
.tile-rejected {
|
||||
@apply opacity-30 grayscale;
|
||||
@@ -107,8 +174,8 @@ body {
|
||||
box-shadow: 0 6px 18px -4px rgba(0,0,0,0.6);
|
||||
}
|
||||
.tile-badge-selected {
|
||||
background: linear-gradient(135deg, #8B5CF6, #3B82F6);
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #e6f578, #d6b36a);
|
||||
color: #081006;
|
||||
}
|
||||
.tile-badge-rejected {
|
||||
@apply bg-rose-500 text-white;
|
||||
@@ -119,24 +186,44 @@ input, textarea {
|
||||
font-family: inherit;
|
||||
}
|
||||
.field {
|
||||
@apply w-full rounded-xl px-3.5 py-3 text-sm text-white placeholder:text-white/30 outline-none resize-none transition-colors;
|
||||
background: rgba(255,255,255,0.04);
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
@apply w-full rounded-[8px] px-3.5 py-3 text-sm text-white placeholder:text-white/30 outline-none resize-none transition-colors;
|
||||
background: rgba(10, 18, 10, 0.42);
|
||||
border: 1px solid rgba(140, 180, 120, 0.14);
|
||||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
|
||||
}
|
||||
.field:focus {
|
||||
border-color: rgba(139, 92, 246, 0.55);
|
||||
box-shadow: 0 0 0 4px rgba(139, 92, 246, 0.12);
|
||||
border-color: rgba(230, 245, 120, 0.5);
|
||||
box-shadow: 0 0 0 4px rgba(230, 245, 120, 0.12);
|
||||
}
|
||||
|
||||
/* ===== KBD ===== */
|
||||
.kbd {
|
||||
@apply inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded text-[10px] font-medium text-white/70 ring-1 ring-white/10 bg-white/[0.06];
|
||||
@apply inline-flex items-center justify-center min-w-[20px] h-5 px-1.5 rounded-[6px] text-[10px] font-medium text-white/70;
|
||||
border: 1px solid rgba(140, 180, 120, 0.16);
|
||||
background: rgba(10, 18, 10, 0.46);
|
||||
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
|
||||
}
|
||||
|
||||
/* ===== Section header ===== */
|
||||
.section-eyebrow {
|
||||
@apply inline-block text-[10px] font-semibold uppercase tracking-[0.18em] text-violet-300/80;
|
||||
@apply inline-block text-[10px] font-semibold uppercase tracking-[0.18em];
|
||||
color: rgba(230, 245, 120, 0.82);
|
||||
text-shadow: 0 0 22px rgba(230, 245, 120, 0.16);
|
||||
}
|
||||
|
||||
.glass-sidebar {
|
||||
border-right: 1px solid rgba(140, 180, 120, 0.14);
|
||||
background:
|
||||
linear-gradient(180deg, rgba(8, 16, 7, 0.72), rgba(2, 5, 2, 0.62)),
|
||||
rgba(10, 18, 10, 0.42);
|
||||
box-shadow:
|
||||
inset -1px 0 0 rgba(255,255,255,0.04),
|
||||
16px 0 70px -44px rgba(0,0,0,0.95);
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
|
||||
.app-oasis main {
|
||||
background: linear-gradient(90deg, rgba(0,0,0,0.18), rgba(10,18,10,0.08));
|
||||
}
|
||||
|
||||
/* ===== Login (cloned from SKG source) ===== */
|
||||
|
||||
@@ -5,6 +5,7 @@ import PromptPanel from '@/components/PromptPanel';
|
||||
import ResultGrid from '@/components/ResultGrid';
|
||||
import Sidebar from '@/components/Sidebar';
|
||||
import PackPanel from '@/components/PackPanel';
|
||||
import { OasisCanvas } from '@/components/login/OasisCanvas';
|
||||
import type {
|
||||
GenImage,
|
||||
GenSession,
|
||||
@@ -277,7 +278,11 @@ export default function Home() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex h-screen text-white">
|
||||
<div className="app-oasis relative h-screen overflow-hidden text-white">
|
||||
<OasisCanvas />
|
||||
<div className="app-oasis-shade" />
|
||||
<div className="app-grass-floor" />
|
||||
<div className="relative z-10 flex h-screen text-white">
|
||||
<Sidebar
|
||||
open={sidebarOpen}
|
||||
onToggle={() => setSidebarOpen(v => !v)}
|
||||
@@ -287,20 +292,20 @@ export default function Home() {
|
||||
onNew={() => setCurrent(null)}
|
||||
/>
|
||||
<main className="flex-1 overflow-y-auto">
|
||||
<div className="mx-auto max-w-[1200px] px-10 py-10">
|
||||
<div className="mx-auto max-w-[1240px] px-10 py-8">
|
||||
<header className="flex items-center justify-between mb-8 gap-4">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<div className="w-9 h-9 rounded-xl bg-gradient-to-br from-violet-500 to-blue-500 flex items-center justify-center shrink-0 shadow-glow-violet">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2.5">
|
||||
<div className="w-9 h-9 rounded-[8px] bg-gradient-to-br from-[#e6f578] to-[#d6b36a] flex items-center justify-center shrink-0 shadow-glow-violet">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#081006" strokeWidth="2.5">
|
||||
<path d="M12 2l2.5 6.5L21 11l-6.5 2.5L12 20l-2.5-6.5L3 11l6.5-2.5z" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="min-w-0">
|
||||
<h1 className="text-base font-semibold tracking-tight leading-tight text-white">
|
||||
<h1 className="text-base font-semibold tracking-tight leading-tight text-[#f8f7ef]">
|
||||
AI Toy Patent
|
||||
<span className="ml-2 text-white/40 font-normal text-sm">把一句想法变成专利 / 生产 / 宣发素材包</span>
|
||||
<span className="ml-2 text-white/48 font-normal text-sm">把一句想法变成专利 / 生产 / 宣发素材包</span>
|
||||
</h1>
|
||||
<p className="text-[11px] text-white/35 mt-0.5">批量出意向 · 快筛 · 锁定角色 · 一键四包 · Seedance 视频</p>
|
||||
<p className="text-[11px] text-[#e6f578]/55 mt-0.5">批量出意向 · 快筛 · 锁定角色 · 一键四包 · Seedance 视频</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
@@ -310,7 +315,7 @@ export default function Home() {
|
||||
href={`/api/gallery/${encodeURIComponent(current.id)}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="chip chip-neutral hover:border-violet-300/40 hover:text-white transition-colors"
|
||||
className="chip chip-neutral hover:border-[#e6f578]/40 hover:text-white transition-colors"
|
||||
>
|
||||
图库
|
||||
</a>
|
||||
@@ -318,7 +323,7 @@ export default function Home() {
|
||||
href={`/api/audit/${encodeURIComponent(current.id)}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="chip chip-neutral hover:border-violet-300/40 hover:text-white transition-colors"
|
||||
className="chip chip-neutral hover:border-[#e6f578]/40 hover:text-white transition-colors"
|
||||
>
|
||||
记录
|
||||
</a>
|
||||
@@ -326,7 +331,7 @@ export default function Home() {
|
||||
)}
|
||||
<button
|
||||
onClick={handleLogout}
|
||||
className="chip chip-neutral hover:border-violet-300/40 hover:text-white transition-colors"
|
||||
className="chip chip-neutral hover:border-[#e6f578]/40 hover:text-white transition-colors"
|
||||
>
|
||||
退出
|
||||
</button>
|
||||
@@ -375,5 +380,6 @@ export default function Home() {
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,10 +12,10 @@ const PACK_DESCRIPTIONS: Record<PackKind, string> = {
|
||||
};
|
||||
|
||||
const PACK_ACCENT: Record<PackKind, { bar: string; chip: string; icon: string }> = {
|
||||
patent: { bar: 'from-violet-400 to-indigo-400', chip: 'bg-violet-500/15 text-violet-200 border-violet-400/30', icon: 'P' },
|
||||
accessories: { bar: 'from-sky-400 to-cyan-400', chip: 'bg-sky-500/15 text-sky-200 border-sky-400/30', icon: 'A' },
|
||||
production: { bar: 'from-amber-400 to-orange-400', chip: 'bg-amber-500/15 text-amber-200 border-amber-400/30', icon: 'F' },
|
||||
marketing: { bar: 'from-emerald-400 to-teal-400', chip: 'bg-emerald-500/15 text-emerald-200 border-emerald-400/30', icon: 'M' },
|
||||
patent: { bar: 'from-[#e6f578] to-[#d6b36a]', chip: 'bg-[#e6f578]/15 text-[#e6f578] border-[#e6f578]/30', icon: 'P' },
|
||||
accessories: { bar: 'from-[#8cb478] to-[#547a43]', chip: 'bg-[#8cb478]/15 text-[#cfe7a7] border-[#8cb478]/30', icon: 'A' },
|
||||
production: { bar: 'from-[#d6b36a] to-[#b6813c]', chip: 'bg-[#d6b36a]/15 text-[#f2d38c] border-[#d6b36a]/30', icon: 'F' },
|
||||
marketing: { bar: 'from-[#b6df72] to-[#4f9a56]', chip: 'bg-[#b6df72]/15 text-[#dff5a8] border-[#b6df72]/30', icon: 'M' },
|
||||
};
|
||||
|
||||
const ASPECT_PX: Record<AssetTemplate['aspectRatio'], string> = {
|
||||
@@ -59,13 +59,13 @@ function AssetRow({ template, asset, accent, onRegenerate }: {
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div className="grid grid-cols-[76px_1fr_auto] gap-3 p-3 rounded-2xl bg-white/[0.025] ring-1 ring-white/[0.05] hover:ring-white/[0.1] transition-all">
|
||||
<div className="grid grid-cols-[76px_1fr_auto] gap-3 p-3 rounded-[8px] bg-white/[0.025] ring-1 ring-white/[0.05] hover:ring-white/[0.1] transition-all">
|
||||
{/* thumbnail */}
|
||||
<div className="group/thumb relative w-[72px] h-[72px] rounded-xl overflow-visible bg-white/[0.04] ring-1 ring-white/[0.07] flex items-center justify-center">
|
||||
<div className="group/thumb relative w-[72px] h-[72px] rounded-[8px] overflow-visible bg-white/[0.04] ring-1 ring-white/[0.07] flex items-center justify-center">
|
||||
{ready ? (
|
||||
<>
|
||||
<img src={asset!.url} alt={template.title} className="max-w-full max-h-full object-contain rounded-lg bg-white" />
|
||||
<div className="pointer-events-none fixed left-1/2 top-1/2 z-[80] hidden -translate-x-1/2 -translate-y-1/2 rounded-2xl bg-white p-2 shadow-2xl ring-1 ring-white/20 group-hover/thumb:block" style={{ width: 'min(640px, 86vw)' }}>
|
||||
<div className="pointer-events-none fixed left-1/2 top-1/2 z-[80] hidden -translate-x-1/2 -translate-y-1/2 rounded-[8px] bg-white p-2 shadow-2xl ring-1 ring-white/20 group-hover/thumb:block" style={{ width: 'min(640px, 86vw)' }}>
|
||||
<img src={asset!.url} alt="" className="max-h-[82vh] w-full object-contain" style={{ aspectRatio: aspectCss(asset!.aspectRatio) }} />
|
||||
</div>
|
||||
</>
|
||||
@@ -75,7 +75,7 @@ function AssetRow({ template, asset, accent, onRegenerate }: {
|
||||
</div>
|
||||
)}
|
||||
{template.required && !ready && (
|
||||
<span className="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-violet-400 ring-2 ring-violet-400/30" />
|
||||
<span className="absolute top-1 right-1 w-1.5 h-1.5 rounded-full bg-[#e6f578] ring-2 ring-[#e6f578]/30" />
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -84,14 +84,14 @@ function AssetRow({ template, asset, accent, onRegenerate }: {
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
<span className="text-[13px] font-medium text-white leading-snug">{template.title}</span>
|
||||
{template.required && !ready && (
|
||||
<span className="text-[9px] text-violet-300/80 uppercase tracking-widest">必备</span>
|
||||
<span className="text-[9px] text-[#e6f578]/80 uppercase tracking-widest">必备</span>
|
||||
)}
|
||||
{ready && <span className="chip chip-live text-[10px] py-0">✓</span>}
|
||||
</div>
|
||||
<p className="text-[11px] text-white/45 leading-relaxed line-clamp-1">{template.description}</p>
|
||||
<button
|
||||
onClick={() => setShowPrompt(s => !s)}
|
||||
className="text-[10px] text-white/30 hover:text-violet-300 transition-colors flex items-center gap-1"
|
||||
className="text-[10px] text-white/30 hover:text-[#e6f578] transition-colors flex items-center gap-1"
|
||||
>
|
||||
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d={showPrompt ? 'M6 9l6 6 6-6' : 'M9 6l6 6-6 6'} strokeLinecap="round" />
|
||||
@@ -125,7 +125,7 @@ function AssetRow({ template, asset, accent, onRegenerate }: {
|
||||
value={refinement}
|
||||
onChange={event => setRefinement(event.target.value)}
|
||||
placeholder="重做要求"
|
||||
className="min-w-0 flex-1 rounded-lg bg-black/30 ring-1 ring-white/[0.08] px-2 py-1 text-[11px] text-white/80 outline-none focus:ring-violet-400/40"
|
||||
className="min-w-0 flex-1 rounded-lg bg-black/30 ring-1 ring-white/[0.08] px-2 py-1 text-[11px] text-white/80 outline-none focus:ring-[#e6f578]/40"
|
||||
/>
|
||||
<button
|
||||
onClick={handleRedo}
|
||||
@@ -142,7 +142,7 @@ function AssetRow({ template, asset, accent, onRegenerate }: {
|
||||
<div className="flex flex-col items-end justify-between text-right shrink-0">
|
||||
<span className="text-[10px] font-mono text-white/40">{ASPECT_PX[template.aspectRatio]}</span>
|
||||
<div className="flex flex-col items-end gap-1">
|
||||
<span className={`text-[10px] ${ready ? 'text-emerald-300' : 'text-white/25'}`}>
|
||||
<span className={`text-[10px] ${ready ? 'text-[#dff5a8]' : 'text-white/25'}`}>
|
||||
{ready ? `L${asset!.derivationLevel}` : '待生成'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -249,7 +249,7 @@ function TextTemplateSection() {
|
||||
return (
|
||||
<section className="card overflow-hidden" id="pack-text">
|
||||
<div className="p-4 flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-sky-500 to-cyan-400 flex items-center justify-center text-white text-[11px] font-bold shrink-0">T</div>
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#8cb478] to-[#d6b36a] flex items-center justify-center text-white text-[11px] font-bold shrink-0">T</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-semibold text-white">设计说明文字</span>
|
||||
@@ -261,7 +261,7 @@ function TextTemplateSection() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<span className="chip bg-sky-500/15 text-sky-200 border-sky-400/30 text-[10px]">GPT Text</span>
|
||||
<span className="chip bg-[#8cb478]/15 text-[#cfe7a7] border-[#8cb478]/30 text-[10px]">GPT Text</span>
|
||||
<button
|
||||
onClick={() => setOpen(v => !v)}
|
||||
title={open ? '收起' : '展开'}
|
||||
@@ -279,23 +279,23 @@ function TextTemplateSection() {
|
||||
{TEXT_TEMPLATES.map(template => {
|
||||
const isOpen = showPromptId === template.id;
|
||||
return (
|
||||
<div key={template.id} className="grid grid-cols-[72px_1fr_auto] gap-3 p-3 rounded-2xl bg-white/[0.025] ring-1 ring-white/[0.05] hover:ring-white/[0.1] transition-all">
|
||||
<div className="aspect-square rounded-xl bg-gradient-to-br from-sky-500/15 to-cyan-500/15 ring-1 ring-sky-400/20 flex flex-col items-center justify-center text-sky-300 text-[9px] font-mono gap-0.5">
|
||||
<div key={template.id} className="grid grid-cols-[72px_1fr_auto] gap-3 p-3 rounded-[8px] bg-white/[0.025] ring-1 ring-white/[0.05] hover:ring-white/[0.1] transition-all">
|
||||
<div className="aspect-square rounded-[8px] bg-gradient-to-br from-[#8cb478]/15 to-[#d6b36a]/15 ring-1 ring-[#8cb478]/20 flex flex-col items-center justify-center text-[#cfe7a7] text-[9px] font-mono gap-0.5">
|
||||
<span>text</span>
|
||||
<span className="text-[8px] text-sky-400/60">{template.outputFormat}</span>
|
||||
<span className="text-[8px] text-[#cfe7a7]/60">{template.outputFormat}</span>
|
||||
</div>
|
||||
<div className="min-w-0 space-y-1">
|
||||
<div className="flex items-center gap-1.5 flex-wrap">
|
||||
<span className="text-[13px] font-medium text-white">{template.title}</span>
|
||||
<span className={`chip text-[10px] py-0 ${template.kind === 'patent' ? 'bg-violet-500/15 text-violet-200 border-violet-400/30' : template.kind === 'production' ? 'bg-amber-500/15 text-amber-200 border-amber-400/30' : template.kind === 'accessories' ? 'bg-sky-500/15 text-sky-200 border-sky-400/30' : template.kind === 'marketing' ? 'bg-emerald-500/15 text-emerald-200 border-emerald-400/30' : 'chip-neutral'}`}>
|
||||
<span className={`chip text-[10px] py-0 ${template.kind === 'patent' ? 'bg-[#e6f578]/15 text-[#e6f578] border-[#e6f578]/30' : template.kind === 'production' ? 'bg-[#d6b36a]/15 text-[#f2d38c] border-[#d6b36a]/30' : template.kind === 'accessories' ? 'bg-[#8cb478]/15 text-[#cfe7a7] border-[#8cb478]/30' : template.kind === 'marketing' ? 'bg-[#b6df72]/15 text-[#dff5a8] border-[#b6df72]/30' : 'chip-neutral'}`}>
|
||||
{template.kind}
|
||||
</span>
|
||||
{template.required && <span className="text-[9px] text-violet-300/80 uppercase tracking-widest">必备</span>}
|
||||
{template.required && <span className="text-[9px] text-[#e6f578]/80 uppercase tracking-widest">必备</span>}
|
||||
</div>
|
||||
<p className="text-[11px] text-white/45 line-clamp-1">{template.description}</p>
|
||||
<button
|
||||
onClick={() => setShowPromptId(isOpen ? null : template.id)}
|
||||
className="text-[10px] text-white/30 hover:text-sky-300 transition-colors flex items-center gap-1"
|
||||
className="text-[10px] text-white/30 hover:text-[#cfe7a7] transition-colors flex items-center gap-1"
|
||||
>
|
||||
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d={isOpen ? 'M6 9l6 6 6-6' : 'M9 6l6 6-6 6'} strokeLinecap="round" />
|
||||
@@ -333,7 +333,7 @@ function VideoSection({ videoLoading, primaryImage, onGenerateVideo }: {
|
||||
return (
|
||||
<section className="card overflow-hidden" id="pack-video">
|
||||
<div className="p-4 flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-fuchsia-500 to-violet-500 flex items-center justify-center text-white text-[11px] font-bold shrink-0">V</div>
|
||||
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#e6f578] to-[#8cb478] flex items-center justify-center text-white text-[11px] font-bold shrink-0">V</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-semibold text-white">Seedance 视频</span>
|
||||
@@ -363,8 +363,8 @@ function VideoSection({ videoLoading, primaryImage, onGenerateVideo }: {
|
||||
{VIDEO_TEMPLATES.map(template => {
|
||||
const isOpen = showPromptId === template.id;
|
||||
return (
|
||||
<div key={template.id} className="grid grid-cols-[72px_1fr_auto] gap-3 p-3 rounded-2xl bg-white/[0.025] ring-1 ring-white/[0.05] hover:ring-white/[0.1] transition-all">
|
||||
<div className="aspect-square rounded-xl bg-gradient-to-br from-fuchsia-500/15 to-violet-500/15 ring-1 ring-fuchsia-400/20 flex flex-col items-center justify-center text-fuchsia-300 text-[9px] font-mono gap-1">
|
||||
<div key={template.id} className="grid grid-cols-[72px_1fr_auto] gap-3 p-3 rounded-[8px] bg-white/[0.025] ring-1 ring-white/[0.05] hover:ring-white/[0.1] transition-all">
|
||||
<div className="aspect-square rounded-[8px] bg-gradient-to-br from-[#e6f578]/15 to-[#8cb478]/15 ring-1 ring-[#e6f578]/20 flex flex-col items-center justify-center text-[#e6f578] text-[9px] font-mono gap-1">
|
||||
<span>▶</span>
|
||||
<span className="text-[8px]">{template.duration}s</span>
|
||||
</div>
|
||||
@@ -376,7 +376,7 @@ function VideoSection({ videoLoading, primaryImage, onGenerateVideo }: {
|
||||
<p className="text-[11px] text-white/45 line-clamp-1">{template.description}</p>
|
||||
<button
|
||||
onClick={() => setShowPromptId(isOpen ? null : template.id)}
|
||||
className="text-[10px] text-white/30 hover:text-fuchsia-300 transition-colors flex items-center gap-1"
|
||||
className="text-[10px] text-white/30 hover:text-[#e6f578] transition-colors flex items-center gap-1"
|
||||
>
|
||||
<svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
|
||||
<path d={isOpen ? 'M6 9l6 6 6-6' : 'M9 6l6 6-6 6'} strokeLinecap="round" />
|
||||
@@ -407,12 +407,12 @@ function VideoSection({ videoLoading, primaryImage, onGenerateVideo }: {
|
||||
|
||||
/* ── Section Nav ──────────────────────────────── */
|
||||
const NAV_ITEMS = [
|
||||
{ id: 'pack-patent', label: '专利', accent: 'from-violet-400 to-indigo-400' },
|
||||
{ id: 'pack-accessories', label: '配件', accent: 'from-sky-400 to-cyan-400' },
|
||||
{ id: 'pack-production', label: '生产', accent: 'from-amber-400 to-orange-400' },
|
||||
{ id: 'pack-marketing', label: '宣发', accent: 'from-emerald-400 to-teal-400' },
|
||||
{ id: 'pack-text', label: '文字', accent: 'from-sky-500 to-cyan-400' },
|
||||
{ id: 'pack-video', label: '视频', accent: 'from-fuchsia-500 to-violet-500' },
|
||||
{ id: 'pack-patent', label: '专利', accent: 'from-[#e6f578] to-[#d6b36a]' },
|
||||
{ id: 'pack-accessories', label: '配件', accent: 'from-[#8cb478] to-[#547a43]' },
|
||||
{ id: 'pack-production', label: '生产', accent: 'from-[#d6b36a] to-[#b6813c]' },
|
||||
{ id: 'pack-marketing', label: '宣发', accent: 'from-[#b6df72] to-[#4f9a56]' },
|
||||
{ id: 'pack-text', label: '文字', accent: 'from-[#8cb478] to-[#d6b36a]' },
|
||||
{ id: 'pack-video', label: '视频', accent: 'from-[#e6f578] to-[#8cb478]' },
|
||||
];
|
||||
|
||||
function SectionNav({ active, onChange }: { active: string; onChange: (id: string) => void }) {
|
||||
@@ -427,8 +427,8 @@ function SectionNav({ active, onChange }: { active: string; onChange: (id: strin
|
||||
}}
|
||||
className={`shrink-0 px-3 py-1.5 rounded-lg text-xs font-medium transition-all ${
|
||||
active === item.id
|
||||
? `text-white bg-gradient-to-r ${item.accent} shadow-sm`
|
||||
: 'text-white/45 hover:text-white/70 hover:bg-white/[0.05]'
|
||||
? `text-[#081006] bg-gradient-to-r ${item.accent} shadow-sm`
|
||||
: 'text-white/45 hover:text-white/70 hover:bg-[#e6f578]/[0.06]'
|
||||
}`}
|
||||
>
|
||||
{item.label}
|
||||
@@ -473,7 +473,7 @@ export default function PackPanel({
|
||||
return (
|
||||
<section className="card p-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="w-8 h-8 rounded-xl bg-white/[0.05] border border-white/[0.08] flex items-center justify-center text-white/30 text-sm">⌗</div>
|
||||
<div className="w-8 h-8 rounded-[8px] bg-white/[0.05] border border-white/[0.08] flex items-center justify-center text-white/30 text-sm">⌗</div>
|
||||
<div>
|
||||
<span className="section-eyebrow">Step · 03 · Assets</span>
|
||||
<h2 className="mt-1.5 text-sm font-semibold text-white">选中主方案后展开资产清单</h2>
|
||||
@@ -506,7 +506,7 @@ export default function PackPanel({
|
||||
<div className="font-mono text-white/70">{generatedTotal} <span className="text-white/30">/ {totalImageSlots} 张</span></div>
|
||||
<div className="text-[10px]">图片位</div>
|
||||
</div>
|
||||
<div className="relative w-16 h-16 rounded-2xl overflow-hidden ring-1 ring-white/15 shadow-glow-violet shrink-0">
|
||||
<div className="relative w-16 h-16 rounded-[8px] overflow-hidden ring-1 ring-white/15 shadow-glow-violet shrink-0">
|
||||
<img src={primaryImage.url} alt="selected" className="w-full h-full object-contain bg-white" />
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent" />
|
||||
<div className="absolute bottom-1 inset-x-0 text-center text-[8px] font-semibold text-white/80 uppercase tracking-wider">主方案</div>
|
||||
|
||||
@@ -136,7 +136,7 @@ export default function PromptPanel({ onGenerate, onUploadProject, loading, uplo
|
||||
</label>
|
||||
<div className="flex flex-wrap gap-2.5">
|
||||
{refs.map((r, i) => (
|
||||
<div key={i} className="relative w-20 h-20 rounded-xl overflow-hidden ring-1 ring-white/[0.1] group">
|
||||
<div key={i} className="relative w-20 h-20 rounded-[8px] overflow-hidden ring-1 ring-white/[0.1] group">
|
||||
<img src={r} alt="ref" className="w-full h-full object-cover" />
|
||||
<button
|
||||
onClick={() => setRefs(prev => prev.filter((_, j) => j !== i))}
|
||||
@@ -147,7 +147,7 @@ export default function PromptPanel({ onGenerate, onUploadProject, loading, uplo
|
||||
{refs.length < 4 && (
|
||||
<button
|
||||
onClick={() => fileInput.current?.click()}
|
||||
className="w-20 h-20 rounded-xl border-2 border-dashed border-white/15 hover:border-violet-400/50 hover:bg-white/[0.03] text-white/30 hover:text-violet-300 text-2xl transition-all flex items-center justify-center"
|
||||
className="w-20 h-20 rounded-[8px] border-2 border-dashed border-[#8cb478]/25 hover:border-[#e6f578]/55 hover:bg-[#e6f578]/[0.04] text-white/30 hover:text-[#e6f578] text-2xl transition-all flex items-center justify-center"
|
||||
>+</button>
|
||||
)}
|
||||
<input
|
||||
@@ -171,7 +171,7 @@ export default function PromptPanel({ onGenerate, onUploadProject, loading, uplo
|
||||
</label>
|
||||
<div className="flex flex-wrap gap-2.5">
|
||||
{remixFiles.map((file, i) => (
|
||||
<div key={`${file.name}-${i}`} className="relative w-20 h-20 rounded-xl overflow-hidden ring-1 ring-white/[0.1] group">
|
||||
<div key={`${file.name}-${i}`} className="relative w-20 h-20 rounded-[8px] overflow-hidden ring-1 ring-white/[0.1] group">
|
||||
<img src={URL.createObjectURL(file)} alt={file.name} className="w-full h-full object-cover" />
|
||||
<button
|
||||
onClick={() => setRemixFiles(prev => prev.filter((_, j) => j !== i))}
|
||||
@@ -182,7 +182,7 @@ export default function PromptPanel({ onGenerate, onUploadProject, loading, uplo
|
||||
{remixFiles.length < 4 && (
|
||||
<button
|
||||
onClick={() => remixInput.current?.click()}
|
||||
className="w-20 h-20 rounded-xl border-2 border-dashed border-white/15 hover:border-violet-400/50 hover:bg-white/[0.03] text-white/30 hover:text-violet-300 text-2xl transition-all flex items-center justify-center"
|
||||
className="w-20 h-20 rounded-[8px] border-2 border-dashed border-[#8cb478]/25 hover:border-[#e6f578]/55 hover:bg-[#e6f578]/[0.04] text-white/30 hover:text-[#e6f578] text-2xl transition-all flex items-center justify-center"
|
||||
>+</button>
|
||||
)}
|
||||
<input
|
||||
@@ -220,7 +220,7 @@ export default function PromptPanel({ onGenerate, onUploadProject, loading, uplo
|
||||
</label>
|
||||
<button
|
||||
onClick={() => replicateInput.current?.click()}
|
||||
className="relative w-full aspect-square rounded-2xl border-2 border-dashed border-white/15 hover:border-violet-400/50 bg-white/[0.025] overflow-hidden transition-all flex items-center justify-center text-white/35"
|
||||
className="relative w-full aspect-square rounded-[8px] border-2 border-dashed border-[#8cb478]/25 hover:border-[#e6f578]/55 bg-[#e6f578]/[0.025] overflow-hidden transition-all flex items-center justify-center text-white/35"
|
||||
>
|
||||
{replicateFile ? (
|
||||
<img src={replicatePreview} alt={replicateFile.name} className="w-full h-full object-cover" />
|
||||
@@ -249,7 +249,7 @@ export default function PromptPanel({ onGenerate, onUploadProject, loading, uplo
|
||||
className="field text-[15px] leading-relaxed"
|
||||
/>
|
||||
</div>
|
||||
<div className="rounded-xl bg-amber-500/10 ring-1 ring-amber-400/20 px-3 py-2 text-[11px] leading-relaxed text-amber-100/75">
|
||||
<div className="rounded-[8px] bg-amber-500/10 ring-1 ring-amber-400/20 px-3 py-2 text-[11px] leading-relaxed text-amber-100/75">
|
||||
上传图必须为你拥有或有合法授权使用的素材。请勿上传迪士尼、三丽鸥、泡泡玛特等已注册 IP 图像;用于专利申请前需自行确认不与他人在先权利冲突。
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) {
|
||||
</div>
|
||||
<div className="text-xs text-white/55">
|
||||
已选
|
||||
<span className="ml-1 font-semibold bg-gradient-to-r from-violet-300 to-blue-300 bg-clip-text text-transparent">{selectedCount}</span>
|
||||
<span className="ml-1 font-semibold bg-gradient-to-r from-[#e6f578] to-[#d6b36a] bg-clip-text text-transparent">{selectedCount}</span>
|
||||
<span className="text-white/30"> / {images.length}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -57,7 +57,7 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) {
|
||||
className={`tile group ${img.status === 'selected' ? 'tile-selected' : ''} ${img.status === 'rejected' ? 'tile-rejected' : ''}`}
|
||||
>
|
||||
<img src={img.url} alt={`gen ${i + 1}`} className="w-full h-full object-contain bg-white" />
|
||||
<div className="pointer-events-none fixed left-1/2 top-1/2 z-[80] hidden -translate-x-1/2 -translate-y-1/2 rounded-2xl bg-white p-2 shadow-2xl ring-1 ring-white/20 group-hover:block" style={{ width: 'min(640px, 86vw)' }}>
|
||||
<div className="pointer-events-none fixed left-1/2 top-1/2 z-[80] hidden -translate-x-1/2 -translate-y-1/2 rounded-[8px] bg-white p-2 shadow-2xl ring-1 ring-white/20 group-hover:block" style={{ width: 'min(640px, 86vw)' }}>
|
||||
<img src={img.url} alt="" className="max-h-[82vh] w-full object-contain" />
|
||||
</div>
|
||||
<div className="tile-keynum">{i + 1}</div>
|
||||
@@ -72,7 +72,7 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) {
|
||||
<div className="absolute inset-x-0 bottom-0 p-2 flex gap-2 opacity-0 group-hover:opacity-100 transition-opacity bg-gradient-to-t from-black/80 via-black/40 to-transparent">
|
||||
<button
|
||||
onClick={() => onAction(img.id, img.status === 'selected' ? 'reset' : 'select')}
|
||||
className="flex-1 px-3 py-1.5 rounded-lg bg-gradient-to-r from-violet-500 to-blue-500 text-white text-xs font-semibold hover:brightness-110 transition shadow-glow-violet"
|
||||
className="flex-1 px-3 py-1.5 rounded-[8px] bg-gradient-to-r from-[#e6f578] to-[#d6b36a] text-[#081006] text-xs font-semibold hover:brightness-110 transition shadow-glow-violet"
|
||||
>
|
||||
{img.status === 'selected' ? '✓ 已选' : '选中'}
|
||||
</button>
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function Sidebar({
|
||||
}) {
|
||||
if (!open) {
|
||||
return (
|
||||
<aside className="w-12 shrink-0 border-r border-white/[0.06] bg-black/30 backdrop-blur-xl flex flex-col items-center py-4">
|
||||
<aside className="glass-sidebar w-12 shrink-0 flex flex-col items-center py-4">
|
||||
<button
|
||||
onClick={onToggle}
|
||||
className="w-8 h-8 rounded-lg hover:bg-white/[0.08] flex items-center justify-center text-white/60 transition-colors"
|
||||
@@ -34,10 +34,10 @@ export default function Sidebar({
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="w-72 shrink-0 border-r border-white/[0.06] bg-black/30 backdrop-blur-xl flex flex-col">
|
||||
<aside className="glass-sidebar w-72 shrink-0 flex flex-col">
|
||||
<div className="px-4 pt-5 pb-3 flex items-center gap-3">
|
||||
<div className="w-8 h-8 rounded-xl bg-gradient-to-br from-violet-500 to-blue-500 flex items-center justify-center shadow-glow-violet">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2.5">
|
||||
<div className="w-8 h-8 rounded-[8px] bg-gradient-to-br from-[#e6f578] to-[#d6b36a] flex items-center justify-center shadow-glow-violet">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="#081006" strokeWidth="2.5">
|
||||
<path d="M12 2l2.5 6.5L21 11l-6.5 2.5L12 20l-2.5-6.5L3 11l6.5-2.5z" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
@@ -85,10 +85,10 @@ export default function Sidebar({
|
||||
<button
|
||||
key={s.id}
|
||||
onClick={() => onPick(s.id)}
|
||||
className={`w-full text-left px-3 py-2.5 rounded-xl text-xs transition-all ${
|
||||
className={`w-full text-left px-3 py-2.5 rounded-[8px] text-xs transition-all ${
|
||||
active
|
||||
? 'bg-gradient-to-r from-violet-500/30 via-indigo-500/20 to-blue-500/20 ring-1 ring-violet-400/40 text-white shadow-glow-violet'
|
||||
: 'hover:bg-white/[0.05] text-white/75 ring-1 ring-transparent hover:ring-white/[0.08]'
|
||||
? 'bg-gradient-to-r from-[#e6f578]/24 via-[#8cb478]/18 to-[#d6b36a]/16 ring-1 ring-[#e6f578]/35 text-white shadow-glow-violet'
|
||||
: 'hover:bg-[#e6f578]/[0.06] text-white/75 ring-1 ring-transparent hover:ring-[#8cb478]/20'
|
||||
}`}
|
||||
>
|
||||
<div className={`line-clamp-2 font-medium leading-relaxed ${active ? 'text-white' : 'text-white/85'}`}>
|
||||
@@ -101,7 +101,7 @@ export default function Sidebar({
|
||||
<span className="flex items-center gap-1.5">
|
||||
<span>{s.images.length} 张</span>
|
||||
{selectedCount > 0 && (
|
||||
<span className={active ? 'text-violet-200 font-semibold' : 'text-violet-300 font-semibold'}>
|
||||
<span className={active ? 'text-[#e6f578] font-semibold' : 'text-[#d6b36a] font-semibold'}>
|
||||
✓{selectedCount}
|
||||
</span>
|
||||
)}
|
||||
|
||||
@@ -5,22 +5,22 @@ const config: Config = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
ink: '#0a0a0a',
|
||||
paper: '#fafafa',
|
||||
accent: '#ff6b35',
|
||||
noir: '#0A0A0F',
|
||||
'noir-2': '#11111A',
|
||||
'noir-3': '#171723',
|
||||
ink: '#081006',
|
||||
paper: '#f8f7ef',
|
||||
accent: '#d6b36a',
|
||||
noir: '#030603',
|
||||
'noir-2': '#071006',
|
||||
'noir-3': '#10180c',
|
||||
},
|
||||
backgroundImage: {
|
||||
'accent-violet': 'linear-gradient(135deg, #8B5CF6 0%, #6366F1 50%, #3B82F6 100%)',
|
||||
'accent-fuchsia': 'linear-gradient(135deg, #D946EF 0%, #8B5CF6 100%)',
|
||||
'noir-radial': 'radial-gradient(circle at 20% 0%, rgba(139,92,246,0.18), transparent 60%), radial-gradient(circle at 90% 90%, rgba(59,130,246,0.12), transparent 50%)',
|
||||
'accent-violet': 'linear-gradient(135deg, #e6f578 0%, #d6b36a 100%)',
|
||||
'accent-fuchsia': 'linear-gradient(135deg, #d6b36a 0%, #8cb478 100%)',
|
||||
'noir-radial': 'linear-gradient(180deg, rgba(12,28,10,0.8), rgba(3,6,3,1))',
|
||||
},
|
||||
boxShadow: {
|
||||
'glow-violet': '0 0 40px -8px rgba(139, 92, 246, 0.45)',
|
||||
'glow-blue': '0 0 40px -8px rgba(59, 130, 246, 0.45)',
|
||||
'card-noir': '0 1px 0 0 rgba(255,255,255,0.06) inset, 0 18px 60px -20px rgba(0,0,0,0.6)',
|
||||
'glow-violet': '0 0 40px -8px rgba(230, 245, 120, 0.38)',
|
||||
'glow-blue': '0 0 40px -8px rgba(214, 179, 106, 0.34)',
|
||||
'card-noir': '0 1px 0 0 rgba(255,255,255,0.08) inset, 0 18px 60px -20px rgba(0,0,0,0.72)',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user