refactor: 重构纹理图集工具,实现浏览器端实时处理
将合图处理从服务端迁移到浏览器端,使用 Web Worker 实现高性能打包算法,新增三栏布局界面和精灵动画预览功能 - 新增 atlasStore 状态管理,实现文件、配置、结果的统一管理 - 新增 atlas-packer 打包算法库(MaxRects/Shelf),支持浏览器端快速合图 - 新增 atlas-worker Web Worker,实现异步打包处理避免阻塞 UI - 新增三栏布局组件:FileListPanel、CanvasPreview、AtlasConfigPanel - 新增 AnimationPreviewDialog 支持精灵动画帧预览和帧率控制 - 优化所有工具页面的响应式布局和交互体验 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,13 +8,15 @@ import { Badge } from "@/components/ui/badge";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useSafeTranslation } from "@/lib/i18n";
|
||||
|
||||
export type ConfigValue = string | number | boolean | undefined;
|
||||
|
||||
export interface ConfigOption {
|
||||
id: string;
|
||||
type: "slider" | "select" | "toggle" | "radio";
|
||||
label: string;
|
||||
description?: string;
|
||||
value: any;
|
||||
options?: { label: string; value: any }[];
|
||||
value: ConfigValue;
|
||||
options?: { label: string; value: ConfigValue }[];
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
@@ -26,7 +28,7 @@ interface ConfigPanelProps {
|
||||
title: string;
|
||||
description?: string;
|
||||
options: ConfigOption[];
|
||||
onChange: (id: string, value: any) => void;
|
||||
onChange: (id: string, value: ConfigValue) => void;
|
||||
onReset?: () => void;
|
||||
className?: string;
|
||||
}
|
||||
@@ -86,7 +88,7 @@ export function ConfigPanel({
|
||||
min={option.min ?? 0}
|
||||
max={option.max ?? 100}
|
||||
step={option.step ?? 1}
|
||||
value={[option.value]}
|
||||
value={[typeof option.value === "number" ? option.value : 0]}
|
||||
onValueChange={(values: number[]) => onChange(option.id, values[0])}
|
||||
className="mt-2"
|
||||
/>
|
||||
@@ -96,7 +98,7 @@ export function ConfigPanel({
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{option.options.map((opt) => (
|
||||
<Button
|
||||
key={opt.value}
|
||||
key={String(opt.value)}
|
||||
variant={option.value === opt.value ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => onChange(option.id, opt.value)}
|
||||
@@ -111,7 +113,7 @@ export function ConfigPanel({
|
||||
<div className="space-y-2">
|
||||
{option.options.map((opt) => (
|
||||
<label
|
||||
key={opt.value}
|
||||
key={String(opt.value)}
|
||||
className={cn(
|
||||
"flex cursor-pointer items-center gap-3 rounded-lg border p-3 transition-colors hover:bg-accent",
|
||||
option.value === opt.value && "border-primary bg-primary/10"
|
||||
@@ -120,7 +122,7 @@ export function ConfigPanel({
|
||||
<input
|
||||
type="radio"
|
||||
name={option.id}
|
||||
value={opt.value}
|
||||
value={String(opt.value)}
|
||||
checked={option.value === opt.value}
|
||||
onChange={() => onChange(option.id, opt.value)}
|
||||
className="h-4 w-4"
|
||||
|
||||
Reference in New Issue
Block a user