diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css
index 5374a3cff..912935119 100644
--- a/apps/ai-game-creator-shell/src/styles.css
+++ b/apps/ai-game-creator-shell/src/styles.css
@@ -7209,9 +7209,38 @@ iframe.preview-frame {
font-size: 11px;
line-height: 1.55;
text-align: left;
- white-space: normal;
+ /* 文档卡预览改为"前几行"(最多 3 行),必须保留换行:折成一行就看不出结构了。 */
+ white-space: pre-line;
+ word-break: break-word;
-webkit-box-orient: vertical;
- -webkit-line-clamp: 5;
+ -webkit-line-clamp: 3;
+}
+
+/*
+ * 代码文件卡:不显示文件内容,只给代码图标 + 扩展名标签。
+ * 与 `.game-resource-card-version-visual` 共用同一套居中排布口径,视觉上仍是同一族卡片。
+ */
+.game-resource-card-code-visual {
+ display: grid;
+ gap: 8px;
+ width: 100%;
+ height: 100%;
+ background: linear-gradient(145deg, #fff8f1, #f2ded2);
+ color: #8b5b45;
+ /* 图标与标签作为一组整体垂直居中,与 `.game-resource-card-version-visual` 同口径。 */
+ align-content: center;
+ place-items: center;
+}
+
+.game-resource-card-code-label {
+ padding: 1px 7px;
+ border: 1px solid rgb(139 91 69 / 28%);
+ border-radius: 999px;
+ background: rgb(255 255 255 / 72%);
+ color: #8b5b45;
+ font-size: 9px;
+ font-weight: 700;
+ letter-spacing: 0.04em;
}
.game-resource-card-version-visual {
diff --git a/apps/ai-game-creator-shell/src/view/project-development/ResourcePreviewMedia.tsx b/apps/ai-game-creator-shell/src/view/project-development/ResourcePreviewMedia.tsx
index 1da6ca17c..637ab9103 100644
--- a/apps/ai-game-creator-shell/src/view/project-development/ResourcePreviewMedia.tsx
+++ b/apps/ai-game-creator-shell/src/view/project-development/ResourcePreviewMedia.tsx
@@ -1,9 +1,10 @@
-import { Image as ImageIcon, Music2, Video } from 'lucide-react';
+import { FileCode2, Image as ImageIcon, Music2, Video } from 'lucide-react';
import { useEffect, useRef } from 'react';
import {
projectResourceCardPreviewKind,
type ProjectResourceCardPreviewState,
+ projectResourceCardPreviewVariant,
} from './resourceCardPreviewModel';
import type { ProjectResource } from './resourceProjectionModel';
@@ -79,6 +80,13 @@ export function ResourcePreviewMedia({
}, [onObservePreview, previewIdentity, resource]);
const kind = resource ? projectResourceCardPreviewKind(resource) : null;
+ /**
+ * 代码文件走与资源卡一致的分流:不画内容(本组件本来也只画缩略图 / 占位),
+ * 占位图标换成代码图标,免得弹窗里代码文件看起来像"读不出来的图片"。
+ */
+ const previewVariant = resource
+ ? projectResourceCardPreviewVariant(resource)
+ : null;
const sourceUrl =
preview.status === 'loaded' ? (preview.preview.sourceUrl ?? null) : null;
const visual = (() => {
@@ -111,6 +119,9 @@ export function ResourcePreviewMedia({
/>
);
}
+ if (previewVariant === 'code') {
+ return ;
+ }
return resourcePreviewPlaceholderIcon(
kind === 'video'
? 'video'
diff --git a/apps/ai-game-creator-shell/src/view/project-development/index.tsx b/apps/ai-game-creator-shell/src/view/project-development/index.tsx
index 6efc1d0f1..2beb79a1a 100644
--- a/apps/ai-game-creator-shell/src/view/project-development/index.tsx
+++ b/apps/ai-game-creator-shell/src/view/project-development/index.tsx
@@ -18,6 +18,7 @@ import { save as saveNativeFileDialog } from '@tauri-apps/plugin-dialog';
import {
AtSign,
Crosshair,
+ FileCode2,
FileText,
FolderTree,
Gamepad2,
@@ -275,7 +276,9 @@ import {
import {
projectResourceCardPreviewKind,
type ProjectResourceCardPreviewState,
- summarizeProjectResourceDocument,
+ projectResourceCardPreviewVariant,
+ projectResourceCodeTypeLabel,
+ projectResourceDocumentPreviewText,
} from './resourceCardPreviewModel';
import { ResourceClassificationPanel } from './ResourceClassificationPanel';
import {
@@ -757,9 +760,24 @@ const ResourceCard = memo(function ResourceCard({
const mediaActive = activeMediaIdentity === previewIdentity;
const sourceUrl =
preview.status === 'loaded' ? preview.preview.sourceUrl : null;
- const documentSummary =
- preview.status === 'loaded' && preview.preview.content !== undefined
- ? summarizeProjectResourceDocument(preview.preview.content)
+ /**
+ * 文档类卡片的卡面分流结论(`markdown` / `code` / `plain-text` / `null`)。
+ *
+ * 判据只看路径扩展名与 subtype,**不依赖是否读到内容** —— 代码卡的卡面本就不该有内容,
+ * 等读完再决定画什么只会把"丑预览"和多余 IO 一起留在链路上。
+ */
+ const previewVariant = projectResourceCardPreviewVariant(resource);
+ /** 代码卡的类型标签(`.tsx` → `TSX`);不是代码卡时为 `null`。 */
+ const codeTypeLabel = projectResourceCodeTypeLabel(resource.path);
+ const documentPreview =
+ preview.status === 'loaded' &&
+ preview.preview.content !== undefined &&
+ previewVariant !== null &&
+ previewVariant !== 'code'
+ ? projectResourceDocumentPreviewText(
+ preview.preview.content,
+ previewVariant === 'markdown',
+ )
: '';
useEffect(() => {
@@ -908,10 +926,31 @@ const ResourceCard = memo(function ResourceCard({
);
}
- if ((kind === 'document' || kind === 'code') && documentSummary) {
+ /**
+ * 代码文件卡:**不显示内容**,只给代码图标 + 类型标签。
+ *
+ * 这里的判据是路径分流(`previewVariant === 'code'`),与是否读到内容无关 ——
+ * 代码卡压根不发起读取(见 `useProjectResourceCardPreviews` 的入队门禁)。
+ */
+ if (previewVariant === 'code') {
return (
-
- {documentSummary}
+
+
+ {codeTypeLabel ? (
+
+ {codeTypeLabel}
+
+ ) : null}
+
+ );
+ }
+ if (previewVariant !== null && documentPreview) {
+ return (
+
+ {documentPreview}
);
}