合并 origin/master:保留 3D 契约与 provider checkpoint,旧玩法表随主线退役

- server-rs/crates/shared-contracts/src/lib.rs:采用主线的模块裁剪(删掉 cfg(any()) 遗留模块、补上 agc_analytics 与 game_distribution),同时保留本分支的 editor_canvas、model3d 模块与 EDITOR_GENERATION_OPERATION_KINDS 导出
- server-rs/crates/spacetime-module/src/migration.rs:主线删除的 410 行旧玩法表 normalize 段保持删除,保留本分支的 provider_kind / provider_task_id 兼容段与对应用例
- docs/【开发运维】本地开发验证与生产运维-2026-05-15.md:校验清单同时保留 Tripo 3D 生成任务与 editor_background_music_generation / model3d_text_to_model / model3d_image_to_model
- .gitignore:补回本分支新增的 3D 模型文件忽略规则(*.glb / *.gltf 等 12 行),压测数据段随主线一并删除
- 共享记忆:本分支的 3D 决策与踩坑条目保留在主线重排后的 decision-log.md 与 pitfalls.md 中
This commit is contained in:
2026-09-23 19:39:30 +08:00
997 changed files with 56264 additions and 80302 deletions
@@ -1,6 +1,7 @@
import { Search, Tag } from 'lucide-react';
import type { Ref } from 'react';
import { getPlatformCategoryChipClassName } from './platformCategoryChipModel';
import { PlatformSegmentedTabs } from './PlatformSegmentedTabs';
export type PlatformResourceFilterOption<TId extends string = string> = {
@@ -53,15 +54,6 @@ export type PlatformResourceFilterBarProps<TId extends string = string> =
onToggleTag: (tag: string) => void;
});
function tagChipClassName(active: boolean) {
return [
'platform-category-chip gap-1.5 px-2.5 text-xs font-bold',
active ? 'platform-category-chip--active' : null,
]
.filter(Boolean)
.join(' ');
}
/**
* 资源搜索 + 功能分类 + 标签的筛选条。
*
@@ -115,6 +107,9 @@ export function PlatformResourceFilterBar<TId extends string = string>({
frame="bare"
surface="transparent"
size="sm"
// 选中项与下面的标签 chip 用同一套实心口径:筛选条里「哪个条件在生效」
// 只允许一种视觉语言。
tone="accent"
className="platform-theme platform-theme--light min-w-0 flex-none"
/>
{tagOptions.length > 0 ? (
@@ -130,7 +125,7 @@ export function PlatformResourceFilterBar<TId extends string = string>({
key={option.tag}
type="button"
aria-pressed={active}
className={tagChipClassName(active)}
className={getPlatformCategoryChipClassName(active)}
// 类型上 `tagItems` 必然带 `onToggleTag`;这一层兜底是给不带类型检查的
// 调用方(JS / 动态构造的 props):没有处理函数就不该渲染成可点按钮。
disabled={!onToggleTag}
@@ -138,7 +133,12 @@ export function PlatformResourceFilterBar<TId extends string = string>({
>
<Tag className="h-3 w-3" aria-hidden="true" />
<span>{option.tag}</span>
<span aria-hidden="true">{option.assetCount}</span>
<span
className="platform-category-chip__count"
aria-hidden="true"
>
{option.assetCount}
</span>
</button>
);
})}
@@ -19,6 +19,7 @@ export type PlatformSegmentedTabsTone =
| 'neutral'
| 'warm'
| 'rose'
| 'accent'
| 'underline';
export type PlatformSegmentedTabsFrame = 'panel' | 'bare';
export type PlatformSegmentedTabsSemantics = 'segment' | 'tabs';
@@ -127,6 +128,12 @@ const PLATFORM_SEGMENTED_TABS_TONE_CLASS: Record<
'border border-[#ff7890] bg-[linear-gradient(180deg,#ff7890_0%,#ff4f6a_100%)] text-white shadow-[0_8px_18px_rgba(244,63,94,0.16)]',
idle: 'border border-[var(--platform-subpanel-border)] bg-white/76 text-[var(--platform-text-strong)] hover:border-[var(--platform-surface-hover-border)] hover:bg-white',
},
// 与筛选 chip 的选中态共用同一组语义色:实心填充 + 反白文字。
// 未选中的悬停只加淡暖底 + 加深文字,不换成品牌色 —— 品牌色是「已选中」专用的。
accent: {
active: 'platform-segmented-tabs__item--solid',
idle: 'text-[var(--platform-text-base)] hover:bg-[var(--platform-warm-bg)] hover:text-[var(--platform-text-strong)]',
},
underline: {
active: 'text-[var(--platform-text-strong)]',
idle: 'text-[var(--platform-text-muted)] hover:text-[var(--platform-text-base)]',
+1
View File
@@ -17,6 +17,7 @@ export type {
export { PlatformBackActionButton } from './PlatformBackActionButton';
export type { PlatformBadgeProps, PlatformBadgeTone } from './PlatformBadge';
export { PlatformBadge } from './PlatformBadge';
export { getPlatformCategoryChipClassName } from './platformCategoryChipModel';
export type {
PlatformEmptyStateProps,
PlatformEmptyStateSize,
@@ -0,0 +1,15 @@
import { describe, expect, it } from 'vitest';
import { getPlatformCategoryChipClassName } from './platformCategoryChipModel';
describe('getPlatformCategoryChipClassName', () => {
it('returns the shared chip chrome and only marks the active state when selected', () => {
const idle = getPlatformCategoryChipClassName(false);
expect(idle).toContain('platform-category-chip');
expect(idle).not.toContain('platform-category-chip--active');
const active = getPlatformCategoryChipClassName(true);
expect(active).toContain('platform-category-chip');
expect(active).toContain('platform-category-chip--active');
});
});
@@ -0,0 +1,15 @@
/**
* 分类 / 标签 chip 的类名口径。
*
* `platform-category-chip` 的公共表现(高度、圆角、hover、focus ring)挂在共享样式表里,
* 这里只负责「选中态」这一处分支,让资源画布、参考图弹窗、模板库这些宿主共用同一份定义,
* 不再各抄一遍类名字符串。
*/
export function getPlatformCategoryChipClassName(active: boolean): string {
return [
'platform-category-chip gap-1.5 px-2.5 text-xs font-bold',
active ? 'platform-category-chip--active' : null,
]
.filter(Boolean)
.join(' ');
}
+58 -6
View File
@@ -540,7 +540,7 @@
justify-content: center;
border: 1px solid var(--platform-subpanel-border);
border-radius: 0.78rem;
background: rgba(255, 255, 255, 0.04);
background: var(--platform-chip-idle-fill, rgba(255, 253, 250, 0.72));
color: var(--platform-text-base);
padding: 0 0.92rem;
font-size: 0.88rem;
@@ -548,10 +548,59 @@
white-space: nowrap;
}
/* 状态阶梯(三个状态必须一眼分得开):
静止 = 浅底 + 中性描边;悬停 = 中性加描边 + 极淡暖底 + 常规文字(**不能**用品牌色,
否则一颗未选中的 chip 悬停起来就像已选中,等于把「选中」这个强状态用掉了);
按下 = 再压一层;选中 = 实心品牌填充 + 反白文字,是唯一的强状态。 */
.platform-category-chip:not(.platform-category-chip--active):hover {
border-color: var(--platform-surface-hover-border, rgba(204, 117, 76, 0.42));
background: var(--platform-warm-bg, rgba(234, 204, 179, 0.32));
color: var(--platform-text-strong);
}
.platform-category-chip:not(.platform-category-chip--active):active {
border-color: var(--platform-warm-border, rgba(204, 117, 76, 0.28));
background: var(--platform-warm-bg, rgba(234, 204, 179, 0.32));
}
.platform-category-chip--active {
border-color: var(--platform-cool-border);
background: var(--platform-cool-bg);
color: var(--platform-cool-text);
border-color: var(--platform-chip-active-border, #7d3719);
background: var(
--platform-chip-active-fill,
linear-gradient(135deg, #b3542f, #8f3f22)
);
color: var(--platform-chip-active-text, #fffaf5);
box-shadow: var(
--platform-chip-active-shadow,
0 6px 14px rgba(150, 71, 39, 0.24)
);
}
/* chip 里的计数(标签命中数量):次要信息,比标签文字轻一档;
选中态跟着标签文字一起变白,不参与不透明度衰减,避免落在 AA 以下。 */
.platform-category-chip__count {
font-size: 0.72rem;
font-weight: 600;
color: var(--platform-text-soft);
}
.platform-category-chip--active .platform-category-chip__count {
color: inherit;
}
/* 分段页签的「实心选中」项:与筛选 chip 共用同一组语义色,
避免两处各写一套「选中长什么样」。 */
.platform-segmented-tabs__item--solid {
border-color: var(--platform-chip-active-border, #7d3719);
background: var(
--platform-chip-active-fill,
linear-gradient(135deg, #b3542f, #8f3f22)
);
color: var(--platform-chip-active-text, #fffaf5);
box-shadow: var(
--platform-chip-active-shadow,
0 6px 14px rgba(150, 71, 39, 0.24)
);
}
.platform-category-sort-button {
@@ -586,8 +635,11 @@
.platform-category-filter-button:focus-visible,
.platform-category-chip:focus-visible,
.platform-category-sort-button:focus-visible {
outline: none;
box-shadow: 0 0 0 3px var(--platform-input-focus-ring);
/* 焦点环用 outline 而不是 box-shadow:选中态自己带 box-shadow(实心 chip 的投影),
用 box-shadow 画环会被状态投影覆盖,选中的 chip 就完全没有焦点提示。outline 不参与
box-shadow 的层叠,也不会撑开布局(offset 2px 落在元素外),选中态自己的投影照旧。 */
outline: 2px solid var(--platform-input-focus-ring);
outline-offset: 2px;
}
.platform-navigable-list-item {