ui: center canvas and refine project layout
Verify and deploy production / verify-and-deploy (push) Successful in 2m50s

This commit is contained in:
2026-10-05 15:36:39 +08:00
parent 99e7a16a47
commit 7e7e26d869
3 changed files with 34 additions and 40 deletions
+10 -8
View File
@@ -107,6 +107,7 @@ export default function ImageEditor({ projectId }: { projectId: string }) {
borderRadius: `${selected.settings.borderRadius}px`,
} as CSSProperties;
const ratioStyle = { "--canvas-ratio": `${project.canvas.width} / ${project.canvas.height}`, background: project.canvas.background } as CSSProperties;
const selectedIndex = project.slides.findIndex((item) => item.id === selected.id);
return <main className="image-editor-shell">
<header className="editor-topbar">
@@ -116,21 +117,22 @@ export default function ImageEditor({ projectId }: { projectId: string }) {
<input ref={fileInput} hidden type="file" accept="image/png,image/jpeg,image/webp" multiple onChange={(event) => void addImages(event.target.files)} />
</header>
<aside className="editor-filmstrip">
<div className="filmstrip-title"><span>页面</span><small>{project.slides.length}</small></div>
<div className="filmstrip-list">{project.slides.map((slide, index) => <button key={slide.id} className={`filmstrip-item ${selected.id === slide.id ? "active" : ""}`} onClick={() => setSelectedId(slide.id)}><span>{index + 1}</span><img src={imageUrl(project.id, slide.fileName)} alt={slide.originalName} /></button>)}</div>
<button className="filmstrip-add" onClick={() => fileInput.current?.click()}>+</button>
</aside>
<section className="editor-workspace">
<div className="canvas-toolbar"><button>↖ 选择</button><button>✋ 移动</button><i /><span>{project.canvas.width} × {project.canvas.height}</span><button onClick={() => updateSettings({ scale: 100, offsetX: 0, offsetY: 0, rotation: 0 })}>重置视图</button></div>
<div className="canvas-viewport">
<div className="canvas-page" style={ratioStyle} onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={onPointerUp}>
<img draggable={false} src={imageUrl(project.id, selected.fileName)} alt={selected.originalName} style={style} />
<div className="canvas-selection"><i className="handle nw"/><i className="handle ne"/><i className="handle sw"/><i className="handle se"/></div>
</div>
</div>
<div className="editor-pagination"><button disabled={project.slides[0].id === selected.id} onClick={() => setSelectedId(project.slides[Math.max(0, project.slides.findIndex((item) => item.id === selected.id) - 1)].id)}>‹</button><span>{project.slides.findIndex((item) => item.id === selected.id) + 1} / {project.slides.length}</span><button disabled={project.slides.at(-1)?.id === selected.id} onClick={() => setSelectedId(project.slides[Math.min(project.slides.length - 1, project.slides.findIndex((item) => item.id === selected.id) + 1)].id)}>›</button></div>
<div className="editor-carousel">
<button className="carousel-arrow" disabled={selectedIndex === 0} onClick={() => setSelectedId(project.slides[Math.max(0, selectedIndex - 1)].id)}>‹</button>
<div className="carousel-track">{project.slides.map((slide, index) => {
const offset = index - selectedIndex;
if (Math.abs(offset) > 2) return null;
return <button key={slide.id} className={`carousel-slide ${offset === 0 ? "active" : offset < 0 ? "left" : "right"} ${Math.abs(offset) === 2 ? "far" : ""}`} onClick={() => setSelectedId(slide.id)}><img src={imageUrl(project.id, slide.fileName)} alt={slide.originalName} /><span>{index + 1}</span></button>;
})}<button className="carousel-add" onClick={() => fileInput.current?.click()}>+</button></div>
<button className="carousel-arrow" disabled={selectedIndex === project.slides.length - 1} onClick={() => setSelectedId(project.slides[Math.min(project.slides.length - 1, selectedIndex + 1)].id)}>›</button>
</div>
</section>
<aside className="editor-inspector">
-1
View File
@@ -63,7 +63,6 @@ export default function Studio() {
const visibleProjects = projects.filter((project) => project.name.toLowerCase().includes(query.trim().toLowerCase()));
return <main className="kling-shell">
<header className="kling-windowbar"><strong>首页</strong><button aria-label="新建"><Icon name="plus" size={18} /></button></header>
<aside className="kling-sidebar">
<div className="kling-logo">R</div>
<nav>