feat(canvas): 左侧面板可调宽收起 + 元素多选导出与跳转动画
- 左侧画布面板支持拖拽调整宽度、展开/收起(带动画),状态与宽度持久化 - 顶栏菜单左侧新增面板开关按钮,并缩小菜单/开关按钮 - 顶栏菜单新增「导出当前画布」为压缩包 - 画布元素列表支持多选并批量导出:图片/视频/音频为文件、文本为 txt、其余各自为 json - 画布/资产切换改为滑动下划线动画,点击元素跳转带缓动动画 - 移除文本/配置/视频等非图片元素图标的灰色底色,并写入 AGENTS.md 规范 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
a3411cf9d9
commit
219b3e84db
@@ -0,0 +1,53 @@
|
||||
import { create } from "zustand";
|
||||
|
||||
export const CANVAS_SIDE_PANEL_MOTION_MS = 500;
|
||||
export const CANVAS_SIDE_PANEL_MIN_WIDTH = 220;
|
||||
export const CANVAS_SIDE_PANEL_MAX_WIDTH = 480;
|
||||
export const CANVAS_SIDE_PANEL_DEFAULT_WIDTH = 280;
|
||||
|
||||
const WIDTH_KEY = "canvas-side-panel-width";
|
||||
const OPEN_KEY = "canvas-side-panel-open";
|
||||
|
||||
function initialWidth() {
|
||||
if (typeof window === "undefined") return CANVAS_SIDE_PANEL_DEFAULT_WIDTH;
|
||||
const stored = Number(localStorage.getItem(WIDTH_KEY));
|
||||
if (!stored) return CANVAS_SIDE_PANEL_DEFAULT_WIDTH;
|
||||
return Math.min(CANVAS_SIDE_PANEL_MAX_WIDTH, Math.max(CANVAS_SIDE_PANEL_MIN_WIDTH, stored));
|
||||
}
|
||||
|
||||
function initialOpen() {
|
||||
if (typeof window === "undefined") return true;
|
||||
return localStorage.getItem(OPEN_KEY) !== "0";
|
||||
}
|
||||
|
||||
type CanvasSidePanelStore = {
|
||||
width: number;
|
||||
panelOpen: boolean;
|
||||
panelMounted: boolean;
|
||||
panelClosing: boolean;
|
||||
setWidth: (width: number) => void;
|
||||
openPanel: () => void;
|
||||
closePanel: () => void;
|
||||
togglePanel: () => void;
|
||||
};
|
||||
|
||||
export const useCanvasSidePanelStore = create<CanvasSidePanelStore>((set, get) => ({
|
||||
width: initialWidth(),
|
||||
panelOpen: initialOpen(),
|
||||
panelMounted: initialOpen(),
|
||||
panelClosing: false,
|
||||
setWidth: (width) => set({ width }),
|
||||
openPanel: () => {
|
||||
if (typeof window !== "undefined") localStorage.setItem(OPEN_KEY, "1");
|
||||
set({ panelOpen: true, panelMounted: true, panelClosing: false });
|
||||
},
|
||||
closePanel: () => {
|
||||
if (!get().panelMounted || get().panelClosing) return;
|
||||
if (typeof window !== "undefined") localStorage.setItem(OPEN_KEY, "0");
|
||||
set({ panelOpen: false, panelClosing: true });
|
||||
setTimeout(() => {
|
||||
if (get().panelClosing) set({ panelMounted: false, panelClosing: false });
|
||||
}, CANVAS_SIDE_PANEL_MOTION_MS);
|
||||
},
|
||||
togglePanel: () => (get().panelOpen ? get().closePanel() : get().openPanel()),
|
||||
}));
|
||||
Reference in New Issue
Block a user