File parser: - .fig files are ZIP archives with Kiwi-encoded canvas data - Detects canvas blob by name (canvas.fig) or largest binary entry - Decodes Kiwi Message → NodeChange[] → SceneGraph Node conversion: - Maps Figma types to OpenPencil types (COMPONENT → FRAME, etc.) - Extracts position from transform matrix (m02, m12) - Extracts rotation from transform matrix (atan2) - Converts fillPaints/strokePaints to Fill[]/Stroke[] - Converts effects (shadows, blurs) - Handles independent corner radii - Preserves text properties (font, size, alignment, spacing) - Builds parent-child tree from parentIndex GUIDs - Sorts children by parentIndex.position Browser compatibility: - fzstd for Zstd decompression (replaces Bun.zstd*) - fflate for ZIP extraction - Cmd+O opens file dialog for .fig files - UndoManager.clear() for resetting on file open
60 lines
1.5 KiB
TypeScript
60 lines
1.5 KiB
TypeScript
import { useEventListener } from '@vueuse/core'
|
|
|
|
import { TOOL_SHORTCUTS } from '../stores/editor'
|
|
|
|
import type { EditorStore } from '../stores/editor'
|
|
|
|
function openFileDialog(store: EditorStore) {
|
|
const input = document.createElement('input')
|
|
input.type = 'file'
|
|
input.accept = '.fig'
|
|
input.addEventListener('change', () => {
|
|
const file = input.files?.[0]
|
|
if (file) store.openFigFile(file)
|
|
})
|
|
input.click()
|
|
}
|
|
|
|
export function useKeyboard(store: EditorStore) {
|
|
useEventListener(window, 'keydown', (e: KeyboardEvent) => {
|
|
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement) return
|
|
|
|
const tool = TOOL_SHORTCUTS[e.key.toLowerCase()]
|
|
if (tool) {
|
|
store.setTool(tool)
|
|
return
|
|
}
|
|
|
|
if (e.metaKey || e.ctrlKey) {
|
|
if (e.key === 'z' && !e.shiftKey) {
|
|
e.preventDefault()
|
|
store.undoAction()
|
|
} else if ((e.key === 'z' && e.shiftKey) || e.key === 'y') {
|
|
e.preventDefault()
|
|
store.redoAction()
|
|
} else if (e.key === '0') {
|
|
e.preventDefault()
|
|
store.zoomToFit()
|
|
} else if (e.key === 'd') {
|
|
e.preventDefault()
|
|
store.duplicateSelected()
|
|
} else if (e.key === 'a') {
|
|
e.preventDefault()
|
|
store.selectAll()
|
|
} else if (e.key === 'o') {
|
|
e.preventDefault()
|
|
openFileDialog(store)
|
|
}
|
|
}
|
|
|
|
if (e.key === 'Backspace' || e.key === 'Delete') {
|
|
store.deleteSelected()
|
|
}
|
|
|
|
if (e.key === 'Escape') {
|
|
store.clearSelection()
|
|
store.setTool('SELECT')
|
|
}
|
|
})
|
|
}
|