资源卡文档分区:Markdown/纯文本显示前几行,代码文件改画代码图标

- index.tsx:卡面据 projectResourceCardPreviewVariant 分流,代码卡分支只渲染 lucide 代码图标 + 扩展名标签,不再显示文件内容
- index.tsx:文档卡改用 projectResourceDocumentPreviewText 取前 3 行,并带上 data-document-preview-variant 便于排障与验收
- index.tsx:引入 FileCode2 图标
- ResourcePreviewMedia.tsx:弹窗宿主里代码文件同样改画代码图标,避免看起来像"读不出来的图片"
- styles.css:文档卡预览保留换行并限制 3 行(white-space: pre-line + -webkit-line-clamp: 3)
- styles.css:新增 .game-resource-card-code-visual / .game-resource-card-code-label,复用现有卡片色板与居中排布口径
This commit is contained in:
2026-09-15 19:58:25 +08:00
parent 2c80aab621
commit 608c3e8790
3 changed files with 89 additions and 10 deletions
+31 -2
View File
@@ -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 {
@@ -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 <FileCode2 className="h-5 w-5" aria-hidden="true" />;
}
return resourcePreviewPlaceholderIcon(
kind === 'video'
? 'video'
@@ -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({
</span>
);
}
if ((kind === 'document' || kind === 'code') && documentSummary) {
/**
* **** +
*
* `previewVariant === 'code'`
* `useProjectResourceCardPreviews`
*/
if (previewVariant === 'code') {
return (
<span className="game-resource-card-document-summary">
{documentSummary}
<span className="game-resource-card-code-visual">
<FileCode2 size={30} aria-hidden="true" />
{codeTypeLabel ? (
<span className="game-resource-card-code-label">
{codeTypeLabel}
</span>
) : null}
</span>
);
}
if (previewVariant !== null && documentPreview) {
return (
<span
className="game-resource-card-document-summary"
data-document-preview-variant={previewVariant}
>
{documentPreview}
</span>
);
}