From 7fcda19ba2166286bdc849e9d81f6c44f48acd8c Mon Sep 17 00:00:00 2001 From: kang Date: Wed, 20 May 2026 00:51:41 +0800 Subject: [PATCH] fix: loosen glass dashboard workspace --- .memory/worklog.json | 94 ++++++++++++ src/app/globals.css | 123 ++++++++++------ src/app/page.tsx | 6 +- src/components/HoverImagePreview.tsx | 5 +- src/components/PackPanel.tsx | 69 ++++----- src/components/ResultGrid.tsx | 22 +-- src/components/Sidebar.tsx | 204 ++++++++++++--------------- tsconfig.tsbuildinfo | 2 +- 8 files changed, 323 insertions(+), 202 deletions(-) diff --git a/.memory/worklog.json b/.memory/worklog.json index dc49fd7..54ff843 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1388,6 +1388,100 @@ "message": "fix: enlarge result thumbnails", "hash": "a13bd05", "files_changed": 1 + }, + { + "ts": "2026-05-19T21:05:38+08:00", + "type": "commit", + "message": "chore: record enlarged thumbnail workflow", + "hash": "7b63ade", + "files_changed": 1 + }, + { + "ts": "2026-05-19T13:10:07Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T13:20:07Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T13:30:08Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T13:40:08Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T13:50:08Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T14:00:08Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T15:40:29Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T15:50:29Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T16:00:29Z", + "type": "session-heartbeat", + "message": "Codex 会话活跃 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T16:02:50Z", + "type": "session-end", + "message": "Codex 会话结束 · 持续 0 秒 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-19T16:02:50Z", + "type": "session-end", + "message": "Codex 会话结束 · 持续 0 秒 · 最近命令:codex · 分支 master · 1 项未提交变更 · 最近提交:chore: record enlarged thumbnail workflow", + "files_changed": 1 + }, + { + "ts": "2026-05-20T00:24:31+08:00", + "type": "commit", + "message": "auto-save 2026-05-20 00:24 (~5)", + "hash": "e72ba50", + "files_changed": 5 + }, + { + "ts": "2026-05-20T00:29:58+08:00", + "type": "commit", + "message": "auto-save 2026-05-20 00:29 (~4)", + "hash": "92df778", + "files_changed": 4 + }, + { + "ts": "2026-05-20T00:51:41+08:00", + "type": "commit", + "message": "auto-save 2026-05-20 00:51 (~8)", + "hash": "3547987", + "files_changed": 8 } ] } diff --git a/src/app/globals.css b/src/app/globals.css index 569fb24..414ce98 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -3,7 +3,7 @@ @tailwind utilities; html, body { - background: #071108; + background: #0f0f10; color: #FFFFFF; font-feature-settings: "cv02", "cv03", "cv04", "cv11", "ss01"; -webkit-font-smoothing: antialiased; @@ -12,13 +12,17 @@ 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: #071108; - background-image: linear-gradient(180deg, rgba(22, 42, 16, 0.92), rgba(5, 12, 4, 1)); + background-color: #0f0f10; + background-image: + radial-gradient(circle at 18% 18%, rgba(110, 99, 200, 0.16), transparent 28%), + radial-gradient(circle at 78% 28%, rgba(73, 199, 182, 0.14), transparent 28%), + radial-gradient(circle at 48% 76%, rgba(185, 194, 42, 0.14), transparent 34%), + linear-gradient(180deg, #171717 0%, #0f0f10 48%, #080809 100%); background-attachment: fixed; min-height: 100vh; } -::selection { background: rgba(230, 245, 120, 0.28); color: #fff; } +::selection { background: rgba(185, 194, 42, 0.28); color: #fff; } .login-oasis-loop { position: fixed; @@ -124,13 +128,13 @@ body { .app-oasis .login-oasis-canvas { z-index: 0; - opacity: 0.74; - filter: saturate(0.92) contrast(1.04); + opacity: 0.18; + filter: saturate(0.72) contrast(0.92) grayscale(0.34); } .app-oasis .login-oasis-loop { - opacity: 1; - filter: saturate(1.08) brightness(1.2); + opacity: 0.2; + filter: saturate(0.72) brightness(0.72); } .app-oasis-shade { @@ -139,10 +143,13 @@ body { z-index: 1; pointer-events: none; background: - linear-gradient(90deg, rgba(0, 0, 0, 0.42), rgba(9, 22, 7, 0.14) 42%, rgba(0, 0, 0, 0.42)), - linear-gradient(180deg, rgba(0, 0, 0, 0.28), rgba(0, 0, 0, 0.02) 36%, rgba(0, 0, 0, 0.54)), - linear-gradient(90deg, rgba(255, 255, 255, 0.026) 1px, transparent 1px), - linear-gradient(180deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px); + radial-gradient(circle at 21% 24%, rgba(110, 99, 200, 0.18), transparent 30%), + radial-gradient(circle at 84% 28%, rgba(73, 199, 182, 0.15), transparent 28%), + radial-gradient(circle at 58% 84%, rgba(185, 194, 42, 0.12), transparent 34%), + linear-gradient(90deg, rgba(0, 0, 0, 0.52), rgba(20, 20, 20, 0.26) 44%, rgba(0, 0, 0, 0.46)), + linear-gradient(180deg, rgba(0, 0, 0, 0.20), rgba(0, 0, 0, 0.02) 36%, rgba(0, 0, 0, 0.58)), + linear-gradient(90deg, rgba(255, 255, 255, 0.022) 1px, transparent 1px), + linear-gradient(180deg, rgba(255, 255, 255, 0.018) 1px, transparent 1px); background-size: auto, auto, 64px 64px, 64px 64px; } @@ -154,7 +161,7 @@ body { z-index: 2; height: 34vh; pointer-events: none; - opacity: 0.46; + opacity: 0.08; background: linear-gradient(180deg, transparent, rgba(10, 25, 7, 0.62) 60%, rgba(0, 0, 0, 0.82)), repeating-linear-gradient(103deg, transparent 0 13px, rgba(204, 230, 120, 0.18) 13px 14px, transparent 14px 28px), @@ -168,7 +175,7 @@ body { } .btn-primary { @apply active:scale-[0.98]; - background: linear-gradient(135deg, rgba(230, 245, 120, 0.96), rgba(214, 179, 106, 0.94)); + background: linear-gradient(135deg, rgba(217, 223, 42, 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); } @@ -177,43 +184,43 @@ body { } .btn-ghost { @apply text-white/80 active:scale-[0.98]; - border: 1px solid rgba(140, 180, 120, 0.14); - background: rgba(10, 18, 10, 0.34); + border: 1px solid rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.055); } .btn-outline { @apply text-white/80 active:scale-[0.98]; - border: 1px solid rgba(140, 180, 120, 0.16); - background: rgba(10, 18, 10, 0.28); + border: 1px solid rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.05); } .btn-glass { @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); + border: 1px solid rgba(255, 255, 255, 0.13); + background: rgba(255, 255, 255, 0.07); } /* ===== Cards (glass) ===== */ .card { @apply relative rounded-[8px] backdrop-blur-xl; - border: 1px solid rgba(140, 180, 120, 0.14); + border: 1px solid rgba(255, 255, 255, 0.10); background: - linear-gradient(180deg, rgba(17, 28, 13, 0.62), rgba(5, 10, 5, 0.54)), - rgba(10, 18, 10, 0.42); + linear-gradient(135deg, rgba(255, 255, 255, 0.085), rgba(255, 255, 255, 0.035)), + rgba(42, 42, 42, 0.58); box-shadow: 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); + 0 0 42px -34px rgba(73, 199, 182, 0.64); } .card-2 { @apply rounded-[8px] backdrop-blur-xl; - border: 1px solid rgba(140, 180, 120, 0.12); - background: rgba(8, 16, 8, 0.42); + border: 1px solid rgba(255, 255, 255, 0.10); + background: rgba(255, 255, 255, 0.055); } .card-hover { @apply transition-all; } .card-hover:hover, .card:hover { - border-color: rgba(140, 180, 120, 0.28); + border-color: rgba(255, 255, 255, 0.18); } /* ===== Chips ===== */ @@ -230,8 +237,8 @@ body { } .chip-neutral { color: rgba(255, 255, 255, 0.7); - border-color: rgba(140, 180, 120, 0.14); - background: rgba(10, 18, 10, 0.34); + border-color: rgba(255, 255, 255, 0.11); + background: rgba(255, 255, 255, 0.055); } .chip-violet { border-color: rgba(230, 245, 120, 0.28); @@ -242,8 +249,8 @@ body { /* ===== Segmented ===== */ .seg { @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); + border: 1px solid rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.055); backdrop-filter: blur(16px); } .seg-item { @@ -258,10 +265,12 @@ body { /* ===== Tiles ===== */ .tile { @apply relative aspect-square overflow-hidden rounded-[8px] transition-all cursor-pointer; - background: rgba(10, 18, 10, 0.44); + background: + linear-gradient(135deg, rgba(255,255,255,0.08), rgba(255,255,255,0.025)), + rgba(42, 42, 42, 0.62); 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); + --tw-ring-color: rgba(255, 255, 255, 0.14); + border: 1px solid rgba(255, 255, 255, 0.10); } .tile-selected { position: relative; @@ -294,8 +303,8 @@ input, textarea { } .field { @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); + background: rgba(18, 18, 18, 0.56); + border: 1px solid rgba(255, 255, 255, 0.11); box-shadow: inset 0 1px 0 rgba(255,255,255,0.05); } .field:focus { @@ -306,23 +315,23 @@ input, textarea { /* ===== KBD ===== */ .kbd { @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); + border: 1px solid rgba(255, 255, 255, 0.12); + background: rgba(255, 255, 255, 0.06); 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]; - color: rgba(230, 245, 120, 0.82); - text-shadow: 0 0 22px rgba(230, 245, 120, 0.16); + color: rgba(217, 223, 42, 0.82); + text-shadow: 0 0 22px rgba(217, 223, 42, 0.16); } .glass-sidebar { - border-right: 1px solid rgba(140, 180, 120, 0.14); + border-right: 1px solid rgba(255, 255, 255, 0.10); background: - linear-gradient(180deg, rgba(8, 16, 7, 0.72), rgba(2, 5, 2, 0.62)), - rgba(10, 18, 10, 0.42); + linear-gradient(180deg, rgba(46, 46, 46, 0.78), rgba(22, 22, 22, 0.70)), + rgba(42, 42, 42, 0.54); box-shadow: inset -1px 0 0 rgba(255,255,255,0.04), 16px 0 70px -44px rgba(0,0,0,0.95); @@ -330,7 +339,33 @@ input, textarea { } .app-oasis main { - background: linear-gradient(90deg, rgba(0,0,0,0.18), rgba(10,18,10,0.08)); + background: linear-gradient(90deg, rgba(0,0,0,0.16), rgba(42,42,42,0.08)); +} + +.dashboard-workbench { + border: 1px solid rgba(255, 255, 255, 0.10); + border-radius: 8px; + background: + linear-gradient(135deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.025)), + rgba(32, 32, 32, 0.48); + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.07), + 0 24px 90px -46px rgba(0, 0, 0, 0.92); + backdrop-filter: blur(18px); +} + +.result-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); + gap: 16px; + align-items: start; +} + +@media (min-width: 1440px) { + .result-grid { + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 18px; + } } /* ===== Login (cloned from SKG source) ===== */ diff --git a/src/app/page.tsx b/src/app/page.tsx index 0c10e9e..d27f247 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -291,8 +291,8 @@ export default function Home() { onPick={id => setCurrent(sessions.find(s => s.id === id) ?? null)} onNew={() => setCurrent(null)} /> -
-
+
+
@@ -353,7 +353,7 @@ export default function Home() { /> )} {current && ( -
+
Step · 02 · Quick Screen diff --git a/src/components/HoverImagePreview.tsx b/src/components/HoverImagePreview.tsx index d222e62..a70f7fc 100644 --- a/src/components/HoverImagePreview.tsx +++ b/src/components/HoverImagePreview.tsx @@ -21,7 +21,8 @@ function nextPreviewState(event: PointerEvent, aspectRatio?: string const gap = 18; const margin = 12; const ratio = parseRatio(aspectRatio); - const width = Math.min(620, Math.max(280, window.innerWidth * 0.42)); + const maxWidth = ratio < 0.8 ? 380 : ratio > 1.35 ? 620 : 500; + const width = Math.min(maxWidth, Math.max(260, window.innerWidth * 0.38)); const height = Math.min(window.innerHeight * 0.82, width / ratio); let left = event.clientX + gap; let top = event.clientY + gap; @@ -69,7 +70,7 @@ export function HoverImagePreview({ /> {preview && (
diff --git a/src/components/PackPanel.tsx b/src/components/PackPanel.tsx index ce4b6c1..b46d3b2 100644 --- a/src/components/PackPanel.tsx +++ b/src/components/PackPanel.tsx @@ -60,9 +60,12 @@ function AssetRow({ template, asset, accent, onRegenerate }: { } } return ( -
+
{/* thumbnail */} -
+
{ready ? ( {/* info */} -
+
{template.title} {template.required && !ready && ( @@ -109,45 +112,43 @@ function AssetRow({ template, asset, accent, onRegenerate }: { anchor: {asset.anchorAssetId ?? asset.anchorImageUrl}
)} - {ready && onRegenerate && ( -
- 重新生成 - -
- )} - {showRedo && ready && ( -
- 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-[#e6f578]/40" - /> - -
- )}
{/* meta */} -
+
{ASPECT_PX[template.aspectRatio]}
{ready ? `L${asset!.derivationLevel}` : '待生成'} + {ready && onRegenerate && ( + + )}
+ + {showRedo && ready && ( +
+ setRefinement(event.target.value)} + placeholder="重做要求" + className="min-w-0 flex-1 rounded-[8px] bg-black/30 ring-1 ring-white/[0.08] px-2.5 py-2 text-[11px] text-white/80 outline-none focus:ring-[#e6f578]/40" + /> + +
+ )}
); } @@ -366,7 +367,9 @@ function VideoSection({ videoLoading, primaryImage, onGenerateVideo }: { return (
- + {template.duration}s
diff --git a/src/components/ResultGrid.tsx b/src/components/ResultGrid.tsx index 832240e..bd4cff7 100644 --- a/src/components/ResultGrid.tsx +++ b/src/components/ResultGrid.tsx @@ -17,9 +17,9 @@ function cssRatioToNumber(ratio: string | undefined) { function thumbnailWidth(ratio: string | undefined) { const value = cssRatioToNumber(ratio); - if (value > 1.35) return 'min(100%, 660px)'; - if (value < 0.8) return 'min(100%, 276px)'; - return 'min(100%, 468px)'; + if (value > 1.35) return 'min(100%, 560px)'; + if (value < 0.8) return 'min(100%, 260px)'; + return 'min(100%, 390px)'; } export default function ResultGrid({ images, onAction }: ResultGridProps) { @@ -42,12 +42,11 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) { return () => window.removeEventListener('keydown', handler); }, [images, onAction]); - const cols = images.length === 1 ? 'grid-cols-[minmax(220px,520px)]' : images.length <= 4 ? 'grid-cols-2' : images.length <= 9 ? 'grid-cols-3' : 'grid-cols-4'; const selectedCount = images.filter(i => i.status === 'selected').length; return (
-
+
1 @@ -66,11 +65,11 @@ export default function ResultGrid({ images, onAction }: ResultGridProps) {
-
+
{images.map((img, i) => (
+ className="flex h-8 w-10 items-center justify-center rounded-[8px] bg-white/[0.10] text-white/85 transition-colors hover:bg-rose-500/60 hover:text-white backdrop-blur" + title={img.status === 'rejected' ? '取消打叉' : '打叉'} + > + + + +
))} diff --git a/src/components/Sidebar.tsx b/src/components/Sidebar.tsx index 683369f..d1facf6 100644 --- a/src/components/Sidebar.tsx +++ b/src/components/Sidebar.tsx @@ -1,6 +1,5 @@ 'use client'; -import { useEffect, useRef, useState } from 'react'; import type { GenSession } from '@/lib/types'; function modeLabel(mode?: GenSession['inputMode']) { @@ -25,9 +24,9 @@ function ActiveSessionDetail({ session }: { session: GenSession }) { const packCount = session.packs?.length ?? 0; return ( -
+
-
下级信息
+
Current session
{modeLabel(session.inputMode)} @@ -57,7 +56,7 @@ function ActiveSessionDetail({ session }: { session: GenSession }) {
Reference
{refs.slice(0, 4).map((ref, index) => ( -
+
{ref.label}
))} @@ -88,28 +87,8 @@ export default function Sidebar({ onPick: (id: string) => void; onNew: () => void; }) { - const rootRef = useRef(null); - const rowRefs = useRef>({}); - const [detailTop, setDetailTop] = useState(140); - const activeSession = sessions.find(session => session.id === currentId) ?? null; - function syncDetailTop() { - if (!currentId) return; - const row = rowRefs.current[currentId]; - const root = rootRef.current; - if (!row || !root) return; - const rowRect = row.getBoundingClientRect(); - const rootRect = root.getBoundingClientRect(); - const rawTop = rowRect.top - rootRect.top; - const maxTop = Math.max(96, rootRect.height - 360); - setDetailTop(Math.min(Math.max(96, rawTop), maxTop)); - } - - useEffect(() => { - syncDetailTop(); - }, [currentId, sessions.length, open]); - if (!open) { return (