diff --git a/core/frontend/src/ai-tools-page.css b/core/frontend/src/ai-tools-page.css new file mode 100644 index 0000000..8ece845 --- /dev/null +++ b/core/frontend/src/ai-tools-page.css @@ -0,0 +1,538 @@ +/* AI 工具页 · 像素还原 scoped 样式 + 基线:public/exact/asset-factory.html(图片生成入口 + 任务中心) + public/exact/{model-photo,platform-cover,image-optimize}.html(工作室壳) + 只用 design-restraint.css 的 token;共享组件类(.btn/.pill/.input/.field/ + .placeholder/.with-corners/.toolbar/table.t/.tabs/.chip/.view-toggle…)直接复用, + 不在此重写。以下仅页面专属结构。 + 挂载根:.asset-factory(AssetFactoryPage)/ .image-workbench(ImageWorkbenchPage)。 */ + +/* ============================================================ + A · 图片生成入口(.asset-factory) + ============================================================ */ + +/* ─── 三 Hero 卡片网格(模特上身图 / 平台套图 / 图片创作 · 等比)─── */ +.asset-factory .factory-hero { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 16px; + margin-bottom: 56px; +} +@media (max-width: 1400px) { + .asset-factory .factory-hero { grid-template-columns: 1fr 1fr; } +} +@media (max-width: 1000px) { + .asset-factory .factory-hero { grid-template-columns: 1fr; } +} + +.asset-factory .factory-card { + position: relative; + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + padding: 28px 30px; + overflow: hidden; +} + +.asset-factory .factory-body { + display: flex; + flex-direction: column; + gap: 18px; + height: 100%; +} +.asset-factory .factory-text { display: flex; flex-direction: column; min-width: 0; } + +.asset-factory .factory-tag { + align-self: flex-start; + font-family: var(--font-mono); + font-size: 10.5px; + color: var(--black-alpha-48); + letter-spacing: .06em; + padding: 2px 8px; + border: 1px solid var(--border-faint); + background: var(--background-lighter); + border-radius: var(--r-sm); + margin-bottom: 14px; +} +.asset-factory .factory-title { + font-size: 22px; + font-weight: 600; + letter-spacing: -.018em; + line-height: 1.25; + color: var(--accent-black); +} +.asset-factory .factory-desc { + margin-top: 8px; + font-size: 13.5px; + color: var(--black-alpha-64); + line-height: 1.55; +} + +/* CTA 行:主按钮 + 价格 mono */ +.asset-factory .factory-cta { + margin-top: auto; + padding-top: 24px; + display: flex; + align-items: center; + gap: 14px; +} +.asset-factory .factory-cta .cost { + font-family: var(--font-mono); + font-size: 10.5px; + color: var(--black-alpha-48); + letter-spacing: .04em; +} + +/* ─── 任务中心 · section header(基线 .section-h 带 mono sub)─── */ +.asset-factory .section-h { margin-top: 24px; } +.asset-factory .section-h .sub-mono { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--black-alpha-48); + letter-spacing: .02em; +} + +.asset-factory .result-meta { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--black-alpha-48); + letter-spacing: .02em; + margin: 2px 0 12px; +} + +/* ─── 列表视图 · 表格容器(基线 #task-list-view)─── */ +.asset-factory .task-list-view { + background: var(--surface); + border: 1px solid var(--border-muted); + border-radius: var(--r-md); + overflow: hidden; +} +.asset-factory .task-list-view table.t { + border: 0; + border-radius: 0; + background: transparent; +} +.asset-factory .task-list-view table.t thead th { + background: var(--background-lighter); + border-bottom-color: var(--border-muted); +} +.asset-factory .task-list-view table.t tbody td { border-bottom: 0; } + +.asset-factory .task-name-cell { display: flex; align-items: center; gap: 12px; } +.asset-factory .task-thumb { width: 40px; height: 40px; flex-shrink: 0; border-radius: var(--r-sm); } +.asset-factory .task-name { font-weight: 600; color: var(--accent-black); font-size: 13.5px; } +.asset-factory .task-sub { + font-size: 11.5px; + color: var(--black-alpha-48); + margin-top: 3px; + font-family: var(--font-mono); + letter-spacing: .02em; +} +.asset-factory .task-list-prog { display: flex; align-items: center; gap: 8px; min-width: 120px; } +.asset-factory .task-list-prog .bar { + flex: 1; height: 4px; + background: var(--black-alpha-7); + border-radius: 2px; overflow: hidden; +} +.asset-factory .task-list-prog .bar span { + display: block; height: 100%; + background: var(--heat); border-radius: 2px; + animation: af-hp-pulse 1.4s ease-in-out infinite; +} +.asset-factory .task-list-prog .pct { + font-family: var(--font-mono); font-size: 10.5px; + color: var(--heat); letter-spacing: .02em; white-space: nowrap; +} +@keyframes af-hp-pulse { + 0%, 100% { opacity: 1; transform: scaleY(1); } + 50% { opacity: .55; transform: scaleY(.7); } +} + +.asset-factory .task-empty { + padding: 60px 20px; + text-align: center; + color: var(--black-alpha-48); + font-size: 13px; + line-height: 1.6; +} +.asset-factory .task-empty .mono { + font-family: var(--font-mono); font-size: 11px; + letter-spacing: .04em; margin-bottom: 6px; +} + +/* ============================================================ + B · 图片工作室壳(.image-workbench) + 基线:model-photo / platform-cover(商品空间 + 表单 + 预览) + 与 image-optimize(对话流)布局相近 — 统一为 mode 感知工作室。 + 在 .content 内铺满可用高度(shell 由 App.tsx 渲染,这里只占正文)。 + ============================================================ */ +.image-workbench { + /* 抵消 .content 的 48/28/72 padding,让工作室壳贴边铺满(同旧 .tool-shell 思路) */ + margin: -48px -28px -72px; + min-height: calc(100vh - 64px); + display: flex; + flex-direction: column; + background: var(--background-base); +} + +/* ─── 顶栏 · toolbar 风格(返回 + 标题 + 右侧操作)─── */ +.image-workbench .iw-topbar { + flex-shrink: 0; + display: flex; align-items: center; gap: 14px; + padding: 12px 28px; + border-bottom: 1px solid var(--border-faint); + background: var(--surface); +} +.image-workbench .iw-topbar .back-pill { + display: inline-flex; align-items: center; gap: 6px; + height: 34px; padding: 0 13px 0 11px; + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-pill); + color: var(--accent-black); + font-size: 13px; font-weight: 500; + font-family: inherit; + cursor: pointer; + transition: background var(--t-base), border-color var(--t-base), color var(--t-base); +} +.image-workbench .iw-topbar .back-pill:hover { + background: var(--black-alpha-4); + border-color: var(--black-alpha-24); +} +.image-workbench .iw-topbar .back-pill svg { width: 14px; height: 14px; } +.image-workbench .iw-topbar .iw-title { display: flex; flex-direction: column; gap: 4px; min-width: 0; } +.image-workbench .iw-topbar .iw-title h1 { + font-size: 18px; font-weight: 600; + letter-spacing: -.01em; line-height: 1.2; + color: var(--accent-black); +} +.image-workbench .iw-topbar .iw-title .sub { + font-size: 12.5px; color: var(--black-alpha-56); + display: flex; align-items: center; gap: 8px; flex-wrap: wrap; +} +.image-workbench .iw-topbar .iw-title .sub .mono { + font-family: var(--font-mono); font-size: 10.5px; + color: var(--black-alpha-48); letter-spacing: .04em; +} + +/* ─── 三栏主体:商品空间(rail) + 参数表单 + 结果预览 ─── */ +.image-workbench .iw-layout { + flex: 1; min-height: 0; + display: grid; + grid-template-columns: 260px 320px minmax(0, 1fr); +} +@media (max-width: 1280px) { + .image-workbench .iw-layout { grid-template-columns: 240px 300px minmax(0, 1fr); } +} +@media (max-width: 1100px) { + .image-workbench .iw-layout { grid-template-columns: 1fr; } +} + +/* ── 最左 · 商品空间(单选) ── */ +.image-workbench .iw-prod-space { + background: var(--surface); + border-right: 1px solid var(--border-faint); + display: flex; flex-direction: column; + min-height: 0; overflow: hidden; +} +.image-workbench .iw-ps-h { + flex-shrink: 0; + display: flex; align-items: center; gap: 8px; + padding: 14px 14px 10px; +} +.image-workbench .iw-ps-h .mono { + font-family: var(--font-mono); font-size: 10.5px; + color: var(--black-alpha-48); letter-spacing: .06em; + text-transform: uppercase; +} +.image-workbench .iw-ps-search { + position: relative; height: 32px; + margin: 0 14px 10px; +} +.image-workbench .iw-ps-search svg { + position: absolute; left: 10px; top: 50%; transform: translateY(-50%); + width: 13px; height: 13px; + color: var(--black-alpha-48); z-index: 2; pointer-events: none; +} +.image-workbench .iw-ps-search input { + width: 100%; height: 100%; + padding: 0 10px 0 30px; + background: var(--background-lighter); + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + font-size: 12.5px; color: var(--accent-black); + font-family: inherit; outline: none; + transition: border-color var(--t-base), background var(--t-base); +} +.image-workbench .iw-ps-search input:focus { border-color: var(--heat-40); background: var(--surface); } +.image-workbench .iw-ps-search input::placeholder { color: var(--black-alpha-48); } +.image-workbench .iw-ps-list { + flex: 1; min-height: 0; + overflow-y: auto; + padding: 4px 10px 10px; + display: flex; flex-direction: column; gap: 4px; +} +.image-workbench .iw-prod-item { + display: flex; align-items: center; gap: 10px; + padding: 8px; + border: 1px solid transparent; + border-radius: var(--r-sm); + cursor: pointer; + text-align: left; + background: transparent; + font-family: inherit; + transition: background var(--t-base), border-color var(--t-base); +} +.image-workbench .iw-prod-item:hover { background: var(--black-alpha-4); } +.image-workbench .iw-prod-item.active { background: var(--heat-12); border-color: var(--heat-20); } +.image-workbench .iw-prod-item .thumb { + flex-shrink: 0; + width: 36px; height: 36px; + border-radius: var(--r-sm); +} +.image-workbench .iw-prod-item .body { flex: 1; min-width: 0; } +.image-workbench .iw-prod-item .nm { + font-size: 12.5px; color: var(--accent-black); font-weight: 500; + line-height: 1.3; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} +.image-workbench .iw-prod-item.active .nm { color: var(--heat); font-weight: 600; } +.image-workbench .iw-prod-item .sub { + margin-top: 2px; + font-family: var(--font-mono); font-size: 10px; + color: var(--black-alpha-48); letter-spacing: .02em; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; +} +.image-workbench .iw-ps-empty { + padding: 24px 14px; + text-align: center; + font-family: var(--font-mono); font-size: 10.5px; + color: var(--black-alpha-48); letter-spacing: .04em; + line-height: 1.7; +} + +/* ── 中 · 参数表单 ── */ +.image-workbench .iw-form { + border-right: 1px solid var(--border-faint); + background: var(--surface); + overflow-y: auto; + padding: 18px 20px; + display: flex; flex-direction: column; +} +.image-workbench .iw-step { margin-bottom: 22px; } +.image-workbench .iw-step:last-of-type { margin-bottom: 0; } +.image-workbench .iw-step-h { + display: flex; align-items: center; gap: 8px; + margin-bottom: 12px; +} +.image-workbench .iw-step-h .num { + width: 22px; height: 22px; + border-radius: 50%; + background: var(--heat-12); color: var(--heat); + font-family: var(--font-mono); font-size: 11px; font-weight: 700; + display: grid; place-items: center; + flex-shrink: 0; +} +.image-workbench .iw-step-h .title { font-size: 14px; font-weight: 600; color: var(--accent-black); } +.image-workbench .iw-sub-h { + font-size: 12px; color: var(--black-alpha-48); + margin-bottom: 6px; + font-family: var(--font-mono); letter-spacing: .02em; +} +.image-workbench .iw-sub { margin-bottom: 12px; } +.image-workbench .iw-sub:last-child { margin-bottom: 0; } + +/* 单选 pill row(比例 / 张数 / 风格) */ +.image-workbench .pill-row { display: flex; gap: 6px; flex-wrap: wrap; } +.image-workbench .pill-row .opt { + flex: 1; min-width: 56px; + height: 32px; + background: var(--background-lighter); + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + color: var(--black-alpha-72); + font-size: 12.5px; + cursor: pointer; + font-family: inherit; + transition: background var(--t-base), color var(--t-base), border-color var(--t-base); +} +.image-workbench .pill-row .opt:hover { color: var(--accent-black); } +.image-workbench .pill-row .opt.active { + background: var(--heat-12); + color: var(--heat); + border-color: var(--heat-40); + font-weight: 600; +} + +/* 模特 / 平台多选卡格 */ +.image-workbench .iw-pick-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 8px; +} +.image-workbench .iw-pick-grid.platforms { grid-template-columns: repeat(3, 1fr); } +.image-workbench .iw-pick-card { + position: relative; + background: var(--background-lighter); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + padding: 8px; + cursor: pointer; + display: flex; flex-direction: column; gap: 6px; + text-align: left; + font-family: inherit; + transition: background var(--t-base), border-color var(--t-base); +} +.image-workbench .iw-pick-card:hover { background: var(--surface); } +.image-workbench .iw-pick-card.selected { border-color: var(--heat); background: var(--heat-12); } +.image-workbench .iw-pick-card .m-thumb { aspect-ratio: 3/4; border-radius: var(--r-sm); } +.image-workbench .iw-pick-card.platforms-card { padding: 10px 6px; text-align: center; align-items: center; } +.image-workbench .iw-pick-card .m-name { font-size: 12.5px; font-weight: 500; color: var(--accent-black); } +.image-workbench .iw-pick-card.selected .m-name { color: var(--heat); } +.image-workbench .iw-pick-card .m-meta { + font-family: var(--font-mono); font-size: 10.5px; + color: var(--black-alpha-48); letter-spacing: .02em; +} +.image-workbench .iw-pick-card .m-check { + position: absolute; top: 10px; right: 10px; + width: 20px; height: 20px; + background: var(--surface); + border: 1.5px solid var(--black-alpha-24); + border-radius: 50%; + display: grid; place-items: center; + color: var(--accent-white); z-index: 2; +} +.image-workbench .iw-pick-card .m-check svg { width: 11px; height: 11px; opacity: 0; } +.image-workbench .iw-pick-card.selected .m-check { background: var(--heat); border-color: var(--heat); } +.image-workbench .iw-pick-card.selected .m-check svg { opacity: 1; } + +/* 左栏底部 · 立即生成(主 CTA · 通栏) */ +.image-workbench .iw-cta { margin-top: auto; padding-top: 14px; } +.image-workbench .iw-cta .btn { + width: 100%; + justify-content: center; + height: 44px; + font-size: 14px; +} +.image-workbench .iw-cta-hint { + margin-top: 8px; + font-family: var(--font-mono); font-size: 11px; + color: var(--black-alpha-48); letter-spacing: .02em; + text-align: center; line-height: 1.5; +} + +/* ── 右 · 结果预览 ── */ +.image-workbench .iw-preview { + background: var(--background-base); + overflow-y: auto; + padding: 18px 22px; + display: flex; flex-direction: column; + min-height: 0; +} + +/* prompt-style summary 卡片(引号 icon + 灰底 + 右上 meta) */ +.image-workbench .iw-pv-h { + position: relative; + background: var(--background-lighter); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + padding: 14px 18px 14px 44px; + margin-bottom: 14px; +} +.image-workbench .iw-pv-h .quote-icon { + position: absolute; top: 13px; left: 16px; + width: 18px; height: 18px; + color: var(--black-alpha-24); +} +.image-workbench .iw-pv-h .pv-meta { + float: right; + font-family: var(--font-mono); font-size: 11px; + color: var(--black-alpha-48); letter-spacing: .04em; + line-height: 1.5; +} +.image-workbench .iw-pv-h .pv-meta b { color: var(--accent-black); font-weight: 600; } +.image-workbench .iw-pv-h .pv-line { + font-size: 13px; color: var(--accent-black); + line-height: 1.6; +} + +/* 结果区:复用 §4.18 .gen-card 规范结构(scoped 实现 · 仅 token) */ +.image-workbench .gen-card { + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + padding: 16px; + display: flex; flex-direction: column; gap: 14px; +} +.image-workbench .gen-meta { + display: flex; align-items: center; gap: 8px; + padding: 0 4px; + font-family: var(--font-mono); font-size: 11.5px; + color: var(--black-alpha-48); letter-spacing: .04em; +} +.image-workbench .gen-meta .m-sep { color: var(--black-alpha-24); } +.image-workbench .gen-images { + display: grid; + grid-template-columns: repeat(var(--cols, 4), 1fr); + gap: 10px; +} +@media (max-width: 1400px) { + .image-workbench .gen-images { grid-template-columns: repeat(2, 1fr); } +} +.image-workbench .gen-image { + position: relative; + aspect-ratio: var(--ratio, 1 / 1); + border-radius: var(--r-md); + overflow: hidden; + cursor: pointer; +} +.image-workbench .gen-image .placeholder { position: absolute; inset: 0; } +/* 右上浮层按钮组(§4.18 .gen-image-actions) */ +.image-workbench .gen-image-actions { + position: absolute; top: 8px; right: 8px; + display: flex; gap: 2px; + padding: 2px; + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + box-shadow: 0 2px 8px rgba(0, 0, 0, .08); + opacity: 0; z-index: 2; + transition: opacity var(--t-base); +} +.image-workbench .gen-image:hover .gen-image-actions { opacity: 1; } +.image-workbench .gen-img-btn { + width: 28px; height: 28px; + border: 0; border-radius: 6px; + background: transparent; + color: var(--black-alpha-56); + cursor: pointer; + display: grid; place-items: center; + transition: background var(--t-base), color var(--t-base); +} +.image-workbench .gen-img-btn:hover { background: var(--black-alpha-4); color: var(--accent-black); } +.image-workbench .gen-img-btn svg { width: 14px; height: 14px; } +/* 底部操作按钮行(§4.18 .gen-card-actions · 二级 + ghost · 不放主橙) */ +.image-workbench .gen-card-actions { + display: flex; gap: 8px; + padding-top: 4px; +} + +/* 预览区空态 */ +.image-workbench .iw-pv-empty { + flex: 1; + display: flex; flex-direction: column; + align-items: center; justify-content: center; + text-align: center; + padding: 40px 24px; + gap: 6px; +} +.image-workbench .iw-pv-empty .mono { + font-family: var(--font-mono); font-size: 10.5px; + color: var(--black-alpha-48); letter-spacing: .06em; + margin-bottom: 4px; +} +.image-workbench .iw-pv-empty .title { font-size: 14px; font-weight: 600; color: var(--accent-black); } +.image-workbench .iw-pv-empty .hint { + font-size: 12.5px; color: var(--black-alpha-48); + line-height: 1.6; max-width: 320px; +} +.image-workbench .iw-pv-empty .hint b { color: var(--heat); font-weight: 600; } diff --git a/core/frontend/src/main.tsx b/core/frontend/src/main.tsx index 2e865c7..8acd0f1 100644 --- a/core/frontend/src/main.tsx +++ b/core/frontend/src/main.tsx @@ -10,5 +10,7 @@ import "./pipeline-page.css"; import "./projects-page.css"; import "./products-page.css"; import "./library-page.css"; +import "./messages-page.css"; +import "./settings-page.css"; createRoot(document.getElementById("root")!).render(); diff --git a/core/frontend/src/messages-page.css b/core/frontend/src/messages-page.css new file mode 100644 index 0000000..ce176b2 --- /dev/null +++ b/core/frontend/src/messages-page.css @@ -0,0 +1,355 @@ +/* messages-page.css · 对齐 public/exact/messages.html · 仅 token,scoped 在 .msg-* */ +.msg-page { + display: flex; + flex-direction: column; + gap: 16px; +} +.msg-page .page-head { + margin-bottom: 0; +} +.msg-head-actions { + display: inline-flex; + align-items: center; + gap: 10px; +} +.msg-workbench { + display: grid; + grid-template-columns: minmax(320px, 380px) minmax(0, 1fr); + min-height: 640px; + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + overflow: hidden; +} +.msg-panel { + min-width: 0; + background: transparent; + border: 0; + border-radius: 0; + overflow: hidden; +} +.msg-inbox, +.msg-detail { + display: flex; + flex-direction: column; + min-height: 0; +} +.msg-inbox { border-right: 1px solid var(--border-faint); } +.msg-panel-h { + min-height: 58px; + display: flex; + align-items: center; + gap: 10px; + padding: 14px 16px; + border-bottom: 1px solid var(--border-faint); +} +.msg-panel-h .ti { + font-size: 13px; + font-weight: 600; + color: var(--accent-black); +} +.msg-panel-h .mono { + margin-left: auto; + font-family: var(--font-mono); + font-size: 10.5px; + color: var(--black-alpha-48); + letter-spacing: .04em; +} +.msg-filters { + display: flex; + flex-wrap: wrap; + gap: 6px; + padding: 12px 14px; + border-bottom: 1px solid var(--border-faint); +} +.msg-filter { + height: 30px; + display: inline-flex; + align-items: center; + gap: 6px; + padding: 0 10px; + border: 1px solid var(--border-faint); + border-radius: var(--r-pill); + background: var(--surface); + color: var(--black-alpha-56); + font-family: inherit; + font-size: 12px; + cursor: pointer; +} +.msg-filter:hover { + border-color: var(--black-alpha-24); + color: var(--accent-black); + background: var(--black-alpha-4); +} +.msg-filter.active { + border-color: var(--heat-20); + background: var(--heat-12); + color: var(--heat); + font-weight: 600; +} +.msg-filter .ct { + font-family: var(--font-mono); + font-size: 10px; + letter-spacing: .02em; +} +.msg-search { + position: relative; + padding: 0 14px 12px; + border-bottom: 1px solid var(--border-faint); +} +.msg-search svg { + position: absolute; + left: 26px; + top: 10px; + width: 13px; + height: 13px; + color: var(--black-alpha-48); + pointer-events: none; +} +.msg-search input { + width: 100%; + height: 34px; + padding: 0 12px 0 32px; + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + background: var(--background-lighter); + color: var(--accent-black); + font-family: inherit; + font-size: 13px; + outline: none; +} +.msg-search input:focus { + background: var(--surface); + border-color: var(--heat-40); + box-shadow: inset 0 0 0 1px var(--heat-40); +} +.msg-list { + flex: 1; + min-height: 0; + overflow-y: auto; +} +.msg-item { + position: relative; + width: 100%; + display: grid; + grid-template-columns: 30px minmax(0, 1fr); + gap: 10px; + padding: 14px 16px; + border: 0; + border-bottom: 1px solid var(--border-faint); + background: transparent; + font-family: inherit; + text-align: left; + cursor: pointer; +} +.msg-item:hover { background: var(--black-alpha-4); } +.msg-item.active { background: var(--heat-12); } +.msg-item.active::before { + content: ""; + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 3px; + background: var(--heat); +} +.msg-item.read .msg-item-title { color: var(--black-alpha-56); font-weight: 500; } +.msg-type-ic { + width: 30px; + height: 30px; + display: grid; + place-items: center; + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + background: var(--background-lighter); + color: var(--black-alpha-72); +} +.msg-type-ic svg { width: 14px; height: 14px; } +.msg-type-ic.task { background: var(--heat-12); border-color: var(--heat-20); color: var(--heat); } +.msg-type-ic.team { background: var(--black-alpha-4); color: var(--accent-black); } +.msg-type-ic.billing { background: var(--honey-bg); border-color: var(--honey-bd); color: var(--accent-honey); } +.msg-type-ic.system { background: var(--black-alpha-7); color: var(--black-alpha-72); } +.msg-item-main { min-width: 0; } +.msg-item-row { + display: flex; + align-items: center; + gap: 8px; +} +.msg-dot { + width: 7px; + height: 7px; + border-radius: var(--r-pill); + background: var(--heat); + flex-shrink: 0; +} +.msg-item.read .msg-dot { display: none; } +.msg-item-title { + flex: 1; + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + color: var(--accent-black); + font-size: 13px; + font-weight: 600; +} +.msg-time { + flex-shrink: 0; + color: var(--black-alpha-48); + font-family: var(--font-mono); + font-size: 10.5px; + letter-spacing: .02em; +} +.msg-brief { + margin-top: 4px; + color: var(--black-alpha-56); + font-size: 12px; + line-height: 1.55; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} +.msg-item-foot { + display: flex; + align-items: center; + gap: 6px; + margin-top: 8px; +} +.msg-priority { + display: inline-flex; + align-items: center; + height: 20px; + padding: 0 7px; + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + background: var(--background-lighter); + color: var(--black-alpha-56); + font-family: var(--font-mono); + font-size: 10px; + letter-spacing: .02em; +} +.msg-priority.ok { background: var(--forest-bg); border-color: var(--forest-bd); color: var(--accent-forest); } +.msg-priority.warn { background: var(--honey-bg); border-color: var(--honey-bd); color: var(--accent-honey); } +.msg-priority.err { background: var(--crimson-bg); border-color: var(--crimson-bd); color: var(--accent-crimson); } +.msg-priority.info { background: var(--heat-12); border-color: var(--heat-20); color: var(--heat); } +.msg-empty { + min-height: 320px; + display: grid; + place-items: center; + gap: 8px; + padding: 24px; + color: var(--black-alpha-48); + font-size: 13px; + text-align: center; +} +.msg-empty svg { width: 24px; height: 24px; color: var(--black-alpha-48); } +.msg-detail-empty { + flex: 1; + min-height: 520px; + display: grid; + place-items: center; + gap: 8px; + color: var(--black-alpha-48); + text-align: center; +} +.msg-detail-empty .ic { + width: 46px; + height: 46px; + display: grid; + place-items: center; + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + background: var(--background-lighter); +} +.msg-detail-empty svg { width: 21px; height: 21px; } +.msg-detail-body { + flex: 1; + min-height: 0; + overflow-y: auto; + padding: 22px 24px 24px; +} +.msg-detail-top { + display: flex; + align-items: flex-start; + gap: 12px; + padding-bottom: 18px; + border-bottom: 1px solid var(--border-faint); +} +.msg-detail-title { + min-width: 0; + flex: 1; +} +.msg-detail-title h2 { + margin: 0; + font-size: 20px; + line-height: 1.35; + font-weight: 600; + letter-spacing: -.012em; + color: var(--accent-black); +} +.msg-detail-title .meta { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 8px; + color: var(--black-alpha-48); + font-family: var(--font-mono); + font-size: 10.5px; + letter-spacing: .04em; +} +.msg-body-text { + margin: 18px 0 0; + color: var(--accent-black); + font-size: 14px; + line-height: 1.75; +} +.msg-props { + display: grid; + grid-template-columns: 110px 1fr; + gap: 10px 16px; + margin-top: 18px; + padding: 14px 16px; + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + background: var(--background-lighter); +} +.msg-props .k { + color: var(--black-alpha-48); + font-family: var(--font-mono); + font-size: 10.5px; + letter-spacing: .04em; +} +.msg-props .v { + min-width: 0; + color: var(--accent-black); + font-size: 13px; +} +.msg-props .v a { color: var(--heat); } +.msg-detail-f { + display: flex; + align-items: center; + gap: 8px; + padding: 14px 16px; + border-top: 1px solid var(--border-faint); + background: var(--background-lighter); +} +.msg-detail-f .spacer { flex: 1; } +.msg-foot-note { + display: flex; + align-items: center; + gap: 8px; + color: var(--black-alpha-48); + font-family: var(--font-mono); + font-size: 10.5px; + letter-spacing: .04em; +} +.msg-foot-note a { color: var(--heat); cursor: pointer; } +@media (max-width: 1280px) { + .msg-workbench { grid-template-columns: minmax(300px, 340px) minmax(0, 1fr); } +} +@media (max-width: 860px) { + .msg-workbench { grid-template-columns: 1fr; } + .msg-inbox { border-right: 0; border-bottom: 1px solid var(--border-faint); } + .msg-list { max-height: 360px; } +} diff --git a/core/frontend/src/product-create-page.css b/core/frontend/src/product-create-page.css new file mode 100644 index 0000000..3b01145 --- /dev/null +++ b/core/frontend/src/product-create-page.css @@ -0,0 +1,267 @@ +/* ============================================================ + product-create-upload · 新建商品(上传原图 + 基本信息) + 像素基线: public/exact/_archive/.../product-create-v2.html + 只用 design-restraint.css 的 token · 共享类 (.page-head/.field/ + .input/.select/.textarea/.btn/.bullet-list) 直接复用,本文件只放 + 该页专属布局(双栏卡片 / 原图槽位 / 提示框 / 吸底操作栏)。 + 全部规则 scope 在 .product-create-page 下,避免污染他页。 + ============================================================ */ + +/* ─── 主表单双栏 ─── */ +.product-create-page .form-grid { + display: grid; + grid-template-columns: 1.05fr 1fr; + gap: 24px; + margin-bottom: 24px; +} + +.product-create-page .form-card { + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + padding: 24px; +} +.product-create-page .form-card-wide { margin-bottom: 24px; } + +.product-create-page .form-card .card-h { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 16px; +} +.product-create-page .form-card .card-h h3 { + font-size: 14px; + font-weight: 600; + color: var(--accent-black); +} +.product-create-page .form-card .req-tag { + font-family: var(--font-mono); + font-size: 10px; + padding: 2px 7px; + background: var(--crimson-bg); + color: var(--accent-crimson); + border: 1px solid var(--crimson-bd); + border-radius: var(--r-sm); + letter-spacing: .04em; +} +.product-create-page .form-card .opt-tag { + font-family: var(--font-mono); + font-size: 10px; + padding: 2px 7px; + background: var(--background-lighter); + color: var(--black-alpha-56); + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + letter-spacing: .04em; +} +.product-create-page .form-card .card-sub { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--black-alpha-48); + margin: -10px 0 14px; + letter-spacing: .02em; +} + +/* 字段:本页卡片内最后一个 field 去掉底距 */ +.product-create-page .field-last { margin-bottom: 0; } +.product-create-page .form-card .field-hint { margin: 4px 0 8px; } + +/* ─── 原图槽位 ─── */ +.product-create-page .photo-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 8px; + margin-top: 8px; +} +.product-create-page .photo-slot { + aspect-ratio: 1; + border: 1px dashed var(--border-faint); + border-radius: var(--r-md); + background: var(--background-lighter); + display: grid; + place-items: center; + gap: 4px; + color: var(--black-alpha-32); + font-family: var(--font-mono); + font-size: 10px; + letter-spacing: .04em; + overflow: hidden; + position: relative; + transition: border-color var(--t-base), color var(--t-base), background var(--t-base); +} +.product-create-page .photo-slot-add { cursor: pointer; } +.product-create-page .photo-slot-add:hover { + border-color: var(--heat); + color: var(--heat); + background: var(--heat-8); +} +.product-create-page .photo-slot .plus { + width: 22px; + height: 22px; + border: 1px solid currentColor; + border-radius: var(--r-sm); + display: grid; + place-items: center; +} +.product-create-page .photo-slot .plus svg { width: 12px; height: 12px; } +.product-create-page .photo-slot .slot-label { + position: absolute; + top: 5px; + left: 5px; + font-size: 9.5px; + font-weight: 600; + padding: 2px 6px; + background: var(--surface); + color: var(--black-alpha-48); + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + letter-spacing: .04em; +} + +/* ─── 上传提示(虚线 tip) ─── */ +.product-create-page .upload-tip { + display: flex; + align-items: center; + gap: 8px; + margin-top: 14px; + padding: 10px 12px; + background: var(--heat-8); + border: 1px dashed var(--heat-40); + border-radius: var(--r-md); + font-size: 12px; + color: var(--accent-black); + line-height: 1.5; +} +.product-create-page .upload-tip svg { + width: 14px; + height: 14px; + color: var(--heat); + flex-shrink: 0; +} +.product-create-page .upload-tip strong { color: var(--heat); font-weight: 600; } + +/* ─── AI 提示 banner(虚线 tip · 中性) ─── */ +.product-create-page .ai-tip { + margin: -6px 0 16px; + padding: 10px 12px; + background: var(--background-lighter); + border: 1px dashed var(--border-faint); + border-radius: var(--r-md); + display: flex; + align-items: flex-start; + gap: 8px; + font-size: 12px; + color: var(--black-alpha-64); + line-height: 1.55; +} +.product-create-page .ai-tip svg { + width: 13px; + height: 13px; + color: var(--heat); + flex-shrink: 0; + margin-top: 2px; +} +.product-create-page .ai-tip strong { color: var(--accent-black); font-weight: 600; } + +/* ─── 卖点列表 · 复用 §4.17.5 .bullet-list 语义 ─── + 共享定义 scope 在 .np-body 下,这里把同一套 token 规则 + 挂到本页根,视觉与 restraint.css 完全一致。 */ +.product-create-page .bullet-list { list-style: none; padding: 0; } +.product-create-page .bullet-list li { + display: flex; + gap: 10px; + align-items: center; + padding: 10px 12px; + background: var(--background-lighter); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + margin-bottom: 6px; + font-size: 13px; + color: var(--accent-black); + transition: border-color var(--t-base), background var(--t-base); +} +.product-create-page .bullet-list li.bl-item:hover { border-color: var(--black-alpha-24); } +.product-create-page .bullet-list li.bl-add { background: var(--surface); border-style: dashed; } +.product-create-page .bullet-list li.bl-add:focus-within { border-color: var(--heat-40); } +.product-create-page .bullet-list .num { + width: 20px; + height: 20px; + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-sm); + font-family: var(--font-mono); + font-size: 11px; + font-weight: 600; + color: var(--black-alpha-56); + display: grid; + place-items: center; + flex-shrink: 0; +} +.product-create-page .bullet-list li.bl-add .num { + background: transparent; + color: var(--heat); + border-color: var(--heat-40); +} +.product-create-page .bullet-list .bl-text { flex: 1; min-width: 0; } +.product-create-page .bullet-list .bl-input { + flex: 1; + min-width: 0; + height: 24px; + border: 0; + padding: 0 4px; + background: transparent; + font-size: 13px; + color: var(--accent-black); + font-family: inherit; + outline: none; +} +.product-create-page .bullet-list .bl-input::placeholder { color: var(--black-alpha-48); } +.product-create-page .bullet-list .bl-x { + width: 24px; + height: 24px; + display: grid; + place-items: center; + color: var(--black-alpha-32); + border: 0; + border-radius: var(--r-sm); + background: transparent; + cursor: pointer; + flex-shrink: 0; + opacity: 0; + transition: opacity var(--t-base), background var(--t-base), color var(--t-base); +} +.product-create-page .bullet-list li.bl-item:hover .bl-x { opacity: 1; } +.product-create-page .bullet-list .bl-x:hover { background: var(--crimson-bg); color: var(--accent-crimson); } +.product-create-page .bullet-list .bl-x svg { width: 11px; height: 11px; } + +/* ─── 底部操作行(吸底) ─── */ +.product-create-page .form-foot { + position: sticky; + bottom: 0; + background: var(--surface); + border: 1px solid var(--border-faint); + border-radius: var(--r-md); + padding: 14px 22px; + display: flex; + align-items: center; + gap: 14px; + margin-top: 8px; +} +.product-create-page .form-foot .req-info { + font-family: var(--font-mono); + font-size: 11.5px; + color: var(--black-alpha-48); + letter-spacing: .02em; +} +.product-create-page .form-foot .req-info .ok { color: var(--accent-forest); } +.product-create-page .form-foot .req-info .miss { color: var(--accent-crimson); } +.product-create-page .form-foot .foot-actions { + margin-left: auto; + display: flex; + gap: 10px; +} + +/* ─── 响应式 · 窄屏单列 ─── */ +@media (max-width: 1100px) { + .product-create-page .form-grid { grid-template-columns: 1fr; } +} diff --git a/core/frontend/src/project-wizard-page.css b/core/frontend/src/project-wizard-page.css new file mode 100644 index 0000000..d2263ba --- /dev/null +++ b/core/frontend/src/project-wizard-page.css @@ -0,0 +1,312 @@ +/* 新建视频项目 · 向导页 · 从 public/exact/projects-new.html 内联