feat: update Makelore modules and conversations
Some checks failed
Electron E2E / Electron E2E (macos-latest) (push) Has been cancelled
Electron E2E / Electron E2E (ubuntu-latest) (push) Has been cancelled
Electron E2E / Electron E2E (windows-latest) (push) Has been cancelled

This commit is contained in:
inman
2026-07-31 10:08:41 +08:00
parent b8ca3f8eea
commit 80e8386fa6
175 changed files with 8036 additions and 10581 deletions

View File

@@ -121,16 +121,16 @@ export function GameAssetBrowser(props: {
const discardedCount = review ? Object.values(review.decisions).filter((decision) => decision !== 'approved').length : 0;
if (loading) {
return <section data-testid="game-asset-browser" className="flex min-h-28 w-full items-center justify-center rounded-md border-2 border-[#26384D] bg-[#e9fff9] text-[#26384D] shadow-[3px_3px_0_#26384D]"><Loader2 className="h-5 w-5 animate-spin" /></section>;
return <section data-testid="game-asset-browser" className="surface-card flex min-h-28 w-full items-center justify-center rounded-2xl border border-border/70 bg-background text-foreground shadow-none"><Loader2 className="h-5 w-5 animate-spin" /></section>;
}
if (loadFailure === 'stale') {
return (
<section
data-testid="game-asset-browser-stale"
className="flex min-h-24 w-full items-center rounded-md border-2 border-[#26384D] bg-[#FFFFFF] px-4 py-3 text-[#26384D] shadow-[3px_3px_0_#26384D]"
className="flex min-h-24 w-full items-center rounded-md border border-foreground/15 bg-background px-4 py-3 text-foreground shadow-soft"
>
<p className="text-pretty text-sm font-bold"></p>
<p className="text-pretty text-sm font-medium"></p>
</section>
);
}
@@ -139,12 +139,12 @@ export function GameAssetBrowser(props: {
return (
<section
data-testid="game-asset-browser-retryable"
className="flex min-h-24 w-full items-center justify-between gap-3 rounded-md border-2 border-[#26384D] bg-[#FFFFFF] px-4 py-3 text-[#26384D] shadow-[3px_3px_0_#26384D]"
className="flex min-h-24 w-full items-center justify-between gap-3 rounded-md border border-foreground/15 bg-background px-4 py-3 text-foreground shadow-soft"
>
<p className="text-pretty text-sm font-bold"></p>
<p className="text-pretty text-sm font-medium"></p>
<Button
type="button"
className="h-10 shrink-0 border-2 border-[#26384D] bg-[#DCE6EF] font-black text-[#26384D] transition-transform active:scale-[0.96]"
className="h-10 shrink-0 border border-foreground/15 bg-brand-soft font-semibold text-foreground transition-transform active:scale-[0.985]"
onClick={() => void load()}
>
<RefreshCw className="mr-1 h-4 w-4" />
@@ -155,12 +155,12 @@ export function GameAssetBrowser(props: {
if (review?.status === 'resolved' && review.candidateIds.length > 0) {
return (
<section data-testid="game-asset-review-summary" className="w-full rounded-md border-2 border-[#26384D] bg-[#e9fff9] px-3 py-3 text-[#26384D] shadow-[3px_3px_0_#26384D]">
<section data-testid="game-asset-review-summary" className="surface-card w-full rounded-2xl border border-border/70 bg-background px-3 py-3 text-foreground shadow-none">
<div className="flex items-start gap-2">
<Check className="mt-0.5 h-4 w-4 shrink-0 text-emerald-700" />
<div>
<p className="text-sm font-black"></p>
<p className="mt-1 text-xs font-medium leading-5 text-[#68788B]"> {approvedCount} {discardedCount} </p>
<p className="text-sm font-semibold"></p>
<p className="mt-1 text-xs font-medium leading-5 text-muted-foreground"> {approvedCount} {discardedCount} </p>
</div>
</div>
</section>
@@ -168,42 +168,42 @@ export function GameAssetBrowser(props: {
}
return (
<section data-testid="game-asset-browser" className="w-full rounded-md border-2 border-[#26384D] bg-[#e9fff9] px-3 py-3 text-[#26384D] shadow-[3px_3px_0_#26384D]">
<section data-testid="game-asset-browser" className="surface-card w-full rounded-2xl border border-border/70 bg-background px-3 py-3 text-foreground shadow-none">
<div className="flex items-start justify-between gap-3">
<div>
<h3 className="text-sm font-black"></h3>
<p className="text-xs font-bold text-[#68788B]"></p>
<h3 className="text-sm font-semibold"></h3>
<p className="text-xs font-medium text-muted-foreground"></p>
</div>
{review ? <span className="rounded border-2 border-[#26384D] bg-white px-2 py-1 text-[10px] font-black"> {review.pendingAssetIds.length} </span> : null}
{review ? <span className="rounded border border-foreground/15 bg-white px-2 py-1 text-[10px] font-semibold"> {review.pendingAssetIds.length} </span> : null}
</div>
{error ? <p className="mt-3 rounded border-2 border-red-400 bg-red-50 p-2 text-xs font-bold text-red-700">{error}</p> : null}
{error ? <p className="mt-3 rounded border border-red-400 bg-red-50 p-2 text-xs font-medium text-red-700">{error}</p> : null}
{!error && assets.length === 0 ? (
<p className="mt-3 rounded border-2 border-dashed border-[#26384D] bg-white p-3 text-xs font-bold">Agent </p>
<p className="mt-3 rounded border border-dashed border-foreground/15 bg-white p-3 text-xs font-medium">Agent </p>
) : null}
{assets.length > 0 ? (
<div className="mt-3 flex gap-3 overflow-x-auto pb-2" data-testid="game-asset-candidate-list">
{assets.map((asset) => {
const selectedAction = draftDecisions[asset.id];
return (
<article key={asset.id} className={`w-56 shrink-0 overflow-hidden rounded-md border-2 border-[#26384D] bg-white shadow-[3px_3px_0_#26384D] ${selectedAction ? 'ring-4 ring-[#F26A3D]/60' : ''}`}>
<button type="button" className="flex h-28 w-full items-center justify-center overflow-hidden border-b-2 border-[#26384D] bg-[#FFFFFF]" onClick={() => setPreviewAsset(asset)}>
<article key={asset.id} className={`w-56 shrink-0 overflow-hidden rounded-md border border-foreground/15 bg-white shadow-soft ${selectedAction ? 'ring-4 ring-accent/40' : ''}`}>
<button type="button" className="flex h-28 w-full items-center justify-center overflow-hidden border-b border-foreground/15 bg-background" onClick={() => setPreviewAsset(asset)}>
{asset.previewDataUrl ? <img src={asset.previewDataUrl} alt={asset.name} className="h-full w-full object-contain" />
: asset.mediaKind === 'audio' ? <Headphones className="h-10 w-10 text-[#3A5578]" />
: asset.mediaKind === 'bundle' ? <Archive className="h-10 w-10 text-[#F26A3D]" />
: asset.mediaKind === 'audio' ? <Headphones className="h-10 w-10 text-brand" />
: asset.mediaKind === 'bundle' ? <Archive className="h-10 w-10 text-accent" />
: <ImageIcon className="h-10 w-10 text-slate-400" />}
</button>
<div className="space-y-2 p-3">
<div className="flex items-start justify-between gap-2"><strong className="line-clamp-2 text-xs">{asset.name}</strong><Badge className="border border-[#26384D] bg-[#EEF3F7] text-[9px] text-[#26384D]">{selectedAction ? actionLabel(selectedAction) : asset.status}</Badge></div>
<div className="flex items-start justify-between gap-2"><strong className="line-clamp-2 text-xs">{asset.name}</strong><Badge className="border border-foreground/15 bg-surface-subtle text-[9px] text-foreground">{selectedAction ? actionLabel(selectedAction) : asset.status}</Badge></div>
<p className="line-clamp-2 text-[11px] font-medium">{asset.purpose || '未填写用途'}</p>
<p className="truncate text-[10px] text-[#68788B]">{asset.source || '未填写'}</p>
<p className="truncate text-[10px] text-[#68788B]">{asset.license || '未填写'}</p>
<p className="truncate text-[10px] text-muted-foreground">{asset.source || '未填写'}</p>
<p className="truncate text-[10px] text-muted-foreground">{asset.license || '未填写'}</p>
{asset.audioDataUrl ? <audio controls preload="metadata" className="h-8 w-full" src={asset.audioDataUrl} /> : null}
<div className="grid grid-cols-2 gap-2">
<Button type="button" size="sm" disabled={submitting} className={`h-8 border-2 border-[#26384D] text-[11px] font-black text-[#26384D] ${selectedAction === 'approve' ? 'bg-[#DCE6EF]' : 'bg-white'}`} aria-pressed={selectedAction === 'approve'} aria-label={`纳入开发 ${asset.name}`} onClick={() => chooseAction(asset.id, 'approve')}></Button>
<Button type="button" size="sm" variant="outline" disabled={submitting} className={`h-8 border-2 border-[#26384D] text-[11px] font-black ${selectedAction === 'discard' ? 'bg-[#ffd8c2]' : ''}`} aria-pressed={selectedAction === 'discard'} aria-label={`舍弃 ${asset.name}`} onClick={() => chooseAction(asset.id, 'discard')}></Button>
<Button type="button" size="sm" disabled={submitting} className={`h-8 border border-foreground/15 text-[11px] font-semibold text-foreground ${selectedAction === 'approve' ? 'bg-brand-soft' : 'bg-white'}`} aria-pressed={selectedAction === 'approve'} aria-label={`纳入开发 ${asset.name}`} onClick={() => chooseAction(asset.id, 'approve')}></Button>
<Button type="button" size="sm" variant="outline" disabled={submitting} className={`h-8 border border-foreground/15 text-[11px] font-semibold ${selectedAction === 'discard' ? 'bg-accent-soft' : ''}`} aria-pressed={selectedAction === 'discard'} aria-label={`舍弃 ${asset.name}`} onClick={() => chooseAction(asset.id, 'discard')}></Button>
</div>
<Button type="button" size="sm" variant="outline" disabled={submitting} className={`h-8 w-full border-2 border-[#26384D] text-[11px] font-black ${selectedAction === 'replace' ? 'bg-[#EEF3F7]' : ''}`} aria-pressed={selectedAction === 'replace'} aria-label={`重新寻找 ${asset.name}`} onClick={() => chooseAction(asset.id, 'replace')}><Search className="mr-1 h-3 w-3" /></Button>
<Button type="button" size="sm" variant="outline" disabled={submitting} className={`h-8 w-full border border-foreground/15 text-[11px] font-semibold ${selectedAction === 'replace' ? 'bg-surface-subtle' : ''}`} aria-pressed={selectedAction === 'replace'} aria-label={`重新寻找 ${asset.name}`} onClick={() => chooseAction(asset.id, 'replace')}><Search className="mr-1 h-3 w-3" /></Button>
</div>
</article>
);
@@ -212,37 +212,37 @@ export function GameAssetBrowser(props: {
) : null}
{assets.length > 0 ? (
<div className="mt-2 flex items-center justify-between gap-3 border-t-2 border-[#26384D]/20 pt-3">
<p className="text-[10px] font-bold text-[#68788B]"> {selectedCount} / {assets.length} {allAssetsSelected ? ',可以提交' : `,还需选择 ${assets.length - selectedCount}`}</p>
<Button type="button" size="sm" disabled={!allAssetsSelected || submitting} className="border-2 border-[#26384D] bg-[#DCE6EF] text-[11px] font-black text-[#26384D]" onClick={() => setShowSubmitDialog(true)}></Button>
<div className="mt-2 flex items-center justify-between gap-3 border-t border-foreground/15 pt-3">
<p className="text-[10px] font-medium text-muted-foreground"> {selectedCount} / {assets.length} {allAssetsSelected ? ',可以提交' : `,还需选择 ${assets.length - selectedCount}`}</p>
<Button type="button" size="sm" disabled={!allAssetsSelected || submitting} className="border border-foreground/15 bg-brand-soft text-[11px] font-semibold text-foreground" onClick={() => setShowSubmitDialog(true)}></Button>
</div>
) : null}
{review && (approvedCount > 0 || discardedCount > 0) ? <p className="mt-2 text-[10px] font-bold text-[#68788B]"> {approvedCount} {discardedCount} </p> : null}
{review && (approvedCount > 0 || discardedCount > 0) ? <p className="mt-2 text-[10px] font-medium text-muted-foreground"> {approvedCount} {discardedCount} </p> : null}
{showSubmitDialog ? (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-5" role="dialog" aria-modal="true" aria-label="确认提交本轮素材审核结果">
<div className="max-h-[85vh] w-full max-w-2xl overflow-auto rounded-lg border-4 border-[#26384D] bg-[#FFFFFF] p-5 shadow-[8px_8px_0_#26384D]">
<div className="flex items-start justify-between gap-3"><div><h3 className="text-lg font-black"></h3><p className="text-sm font-bold text-[#68788B]"></p></div><Button type="button" size="icon" variant="outline" aria-label="关闭提交确认" className="border-2 border-[#26384D]" onClick={() => setShowSubmitDialog(false)}><X className="h-4 w-4" /></Button></div>
<div className="fixed inset-0 z-50 flex items-center justify-center bg-foreground/20 p-5" role="dialog" aria-modal="true" aria-label="确认提交本轮素材审核结果">
<div className="max-h-[85vh] w-full max-w-2xl overflow-auto rounded-lg border border-foreground/15 bg-background p-5 shadow-soft">
<div className="flex items-start justify-between gap-3"><div><h3 className="text-lg font-semibold"></h3><p className="text-sm font-medium text-muted-foreground"></p></div><Button type="button" size="icon" variant="outline" aria-label="关闭提交确认" className="border border-foreground/15" onClick={() => setShowSubmitDialog(false)}><X className="h-4 w-4" /></Button></div>
<div className="mt-4 grid gap-2 sm:grid-cols-3">
{(['approve', 'discard', 'replace'] as const).map((action) => {
const selected = assets.filter((asset) => draftDecisions[asset.id] === action);
return <div key={action} className="rounded border-2 border-[#26384D] bg-white p-3 text-xs"><p className="font-black">{actionLabel(action)}{selected.length} </p><p className="mt-1 line-clamp-3 text-[#68788B]">{selected.map((asset) => asset.name).join('、') || '无'}</p></div>;
return <div key={action} className="rounded border border-foreground/15 bg-white p-3 text-xs"><p className="font-semibold">{actionLabel(action)}{selected.length} </p><p className="mt-1 line-clamp-3 text-muted-foreground">{selected.map((asset) => asset.name).join('、') || '无'}</p></div>;
})}
</div>
<div className="mt-5 flex justify-end gap-2"><Button type="button" variant="outline" disabled={submitting} className="border-2 border-[#26384D] font-black" onClick={() => setShowSubmitDialog(false)}></Button><Button type="button" disabled={submitting} className="border-2 border-[#26384D] bg-[#DCE6EF] font-black text-[#26384D]" onClick={() => void submitBatch()}>{submitting ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : null}</Button></div>
<div className="mt-5 flex justify-end gap-2"><Button type="button" variant="outline" disabled={submitting} className="border border-foreground/15 font-semibold" onClick={() => setShowSubmitDialog(false)}></Button><Button type="button" disabled={submitting} className="border border-foreground/15 bg-brand-soft font-semibold text-foreground" onClick={() => void submitBatch()}>{submitting ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : null}</Button></div>
</div>
</div>
) : null}
{previewAsset ? (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-5" role="dialog" aria-modal="true" aria-label={`${previewAsset.name} 素材预览`}>
<div className="max-h-[85vh] w-full max-w-3xl overflow-auto rounded-lg border-4 border-[#26384D] bg-[#FFFFFF] p-5 shadow-[8px_8px_0_#26384D]">
<div className="flex items-start justify-between gap-3"><div><h3 className="text-lg font-black">{previewAsset.name}</h3><p className="text-sm font-bold text-[#68788B]">{previewAsset.purpose}</p></div><Button type="button" size="icon" variant="outline" aria-label="关闭素材预览" className="border-2 border-[#26384D]" onClick={() => setPreviewAsset(null)}><X className="h-4 w-4" /></Button></div>
{previewAsset.previewDataUrl ? <img src={previewAsset.previewDataUrl} alt={previewAsset.name} className="mt-4 max-h-[50vh] w-full rounded border-2 border-[#26384D] bg-white object-contain" /> : null}
<div className="fixed inset-0 z-50 flex items-center justify-center bg-foreground/20 p-5" role="dialog" aria-modal="true" aria-label={`${previewAsset.name} 素材预览`}>
<div className="max-h-[85vh] w-full max-w-3xl overflow-auto rounded-lg border border-foreground/15 bg-background p-5 shadow-soft">
<div className="flex items-start justify-between gap-3"><div><h3 className="text-lg font-semibold">{previewAsset.name}</h3><p className="text-sm font-medium text-muted-foreground">{previewAsset.purpose}</p></div><Button type="button" size="icon" variant="outline" aria-label="关闭素材预览" className="border border-foreground/15" onClick={() => setPreviewAsset(null)}><X className="h-4 w-4" /></Button></div>
{previewAsset.previewDataUrl ? <img src={previewAsset.previewDataUrl} alt={previewAsset.name} className="mt-4 max-h-[50vh] w-full rounded border border-foreground/15 bg-white object-contain" /> : null}
{previewAsset.audioDataUrl ? <audio controls autoPlay className="mt-4 w-full" src={previewAsset.audioDataUrl} /> : null}
{previewAsset.manifest.length > 0 ? <div className="mt-4"><h4 className="text-sm font-black"></h4><ul className="mt-2 max-h-52 overflow-auto rounded border-2 border-[#26384D] bg-white p-3 text-xs">{previewAsset.manifest.map((item) => <li key={item} className="py-0.5">{item}</li>)}</ul></div> : null}
{previewAsset.unavailableReason ? <p className="mt-4 rounded border-2 border-amber-400 bg-amber-50 p-3 text-xs font-bold">{previewAsset.unavailableReason}</p> : null}
{previewAsset.manifest.length > 0 ? <div className="mt-4"><h4 className="text-sm font-semibold"></h4><ul className="mt-2 max-h-52 overflow-auto rounded border border-foreground/15 bg-white p-3 text-xs">{previewAsset.manifest.map((item) => <li key={item} className="py-0.5">{item}</li>)}</ul></div> : null}
{previewAsset.unavailableReason ? <p className="mt-4 rounded border border-amber-400 bg-amber-50 p-3 text-xs font-medium">{previewAsset.unavailableReason}</p> : null}
</div>
</div>
) : null}