图片预览文案按封面/截图语境区分
- IconPreview 增加可选 labels,缺省仍是小红书「图标」文案 - FormCard 的封面与截图预览各自传入封面/截图语义的 alt、title 与 aria
This commit is contained in:
+16
-1
@@ -252,6 +252,12 @@ export function FormCard({
|
||||
<IconPreview
|
||||
projectPath={projectPath}
|
||||
relativePath={form.coverPath}
|
||||
labels={{
|
||||
alt: '封面预览',
|
||||
failedTitle: '读不到这张图,用「选择封面」导入一张就能预览',
|
||||
failedAria: '封面读不到',
|
||||
emptyAria: '还没有选封面',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="grid size-24 shrink-0 place-items-center overflow-hidden rounded-xl border border-dashed border-(--platform-surface-border) bg-(--platform-input-fill) text-center text-xs text-(--platform-text-soft)">
|
||||
@@ -315,7 +321,16 @@ export function FormCard({
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{form.screenshotPaths.map((path, index) => (
|
||||
<div key={`${path}-${index}`} className="grid gap-1">
|
||||
<IconPreview projectPath={projectPath} relativePath={path} />
|
||||
<IconPreview
|
||||
projectPath={projectPath}
|
||||
relativePath={path}
|
||||
labels={{
|
||||
alt: `第 ${index + 1} 张截图预览`,
|
||||
failedTitle: '读不到这张图,重新选择截图就能预览',
|
||||
failedAria: `第 ${index + 1} 张截图读不到`,
|
||||
emptyAria: `第 ${index + 1} 张截图`,
|
||||
}}
|
||||
/>
|
||||
<PaneButton
|
||||
variant="ghost"
|
||||
ariaLabel={`移除第 ${index + 1} 张截图`}
|
||||
|
||||
+26
-4
@@ -11,7 +11,18 @@ import {
|
||||
type ImagePreviewResponse = { dataUrl: string };
|
||||
|
||||
/**
|
||||
* 图标缩略图:把项目里那张图读成 dataUrl 直接显示。
|
||||
* 无障碍与占位文案;缺省是小红书「图标」语境。封面/截图等复用方按自己的语义覆盖,
|
||||
* 避免读图失败时对用户说成「选择图标」。
|
||||
*/
|
||||
type IconPreviewLabels = {
|
||||
alt?: string;
|
||||
failedTitle?: string;
|
||||
failedAria?: string;
|
||||
emptyAria?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* 图片缩略图:把项目里那张图读成 dataUrl 直接显示。
|
||||
*
|
||||
* 走 UI Editor 同一套 `read_local_project_image_preview`——越界、符号链接、敏感路径的门禁在宿主
|
||||
* 那边,而且宿主只允许预览「已登记资源」。用户手填一条没登记过的路径时这里读不到,退回占位符并
|
||||
@@ -20,9 +31,11 @@ type ImagePreviewResponse = { dataUrl: string };
|
||||
export function IconPreview({
|
||||
projectPath,
|
||||
relativePath,
|
||||
labels,
|
||||
}: {
|
||||
projectPath: string | null;
|
||||
relativePath: string;
|
||||
labels?: IconPreviewLabels;
|
||||
}) {
|
||||
const [dataUrl, setDataUrl] = useState<string | null>(null);
|
||||
const [failed, setFailed] = useState(false);
|
||||
@@ -71,15 +84,24 @@ export function IconPreview({
|
||||
<span
|
||||
className="grid size-24 shrink-0 place-items-center overflow-hidden rounded-xl border border-(--platform-surface-border) bg-(--platform-input-fill)"
|
||||
title={
|
||||
failed ? '读不到这张图,用「选择图标」导入一张就能预览' : undefined
|
||||
failed
|
||||
? (labels?.failedTitle ??
|
||||
'读不到这张图,用「选择图标」导入一张就能预览')
|
||||
: undefined
|
||||
}
|
||||
role={dataUrl ? undefined : 'img'}
|
||||
aria-label={dataUrl ? undefined : failed ? '图标读不到' : '还没有选图标'}
|
||||
aria-label={
|
||||
dataUrl
|
||||
? undefined
|
||||
: failed
|
||||
? (labels?.failedAria ?? '图标读不到')
|
||||
: (labels?.emptyAria ?? '还没有选图标')
|
||||
}
|
||||
>
|
||||
{dataUrl ? (
|
||||
<img
|
||||
src={dataUrl}
|
||||
alt="图标预览"
|
||||
alt={labels?.alt ?? '图标预览'}
|
||||
className="size-full object-contain"
|
||||
/>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user