macro-clips slice 4c: button creation in sidebar + drag to clip tracks
- store.seedDefaultButtonClip(name) adds a button clip with a single shared rect asset and four pre-populated state stacks in blue shades (normal/hover/pressed/disabled). Layer name 'Face' is consistent so transitions can later pair layers by name. - AssetSidebar gets a Buttons section below Clips: create via prompt, rename, delete, drag-to-track. Drag uses a new dataTransfer type 'application/x-animatr-button-clip' to keep it distinct from animation-clip drops. - Timeline clip-lane drop accepts both types and dispatches addClipInstance / addButtonInstance accordingly; the new-track drop zone handles both too, so dragging a button to an empty area creates a fresh clip track + instance in one step. - i18n for the sidebar strings and three dialogs. - test covers seedDefaultButtonClip: four populated states, shared asset, consistent layer name. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
fb58cd18f7
commit
024883943b
5 files changed
+193
-6
No files matched your search
@@ -1347,7 +1347,11 @@ function pixelTimeFromEvent(e: DragEvent | PointerEvent, el: HTMLElement): numbe
|
||||
}
|
||||
|
||||
function onClipLaneDragOver(e: DragEvent, _clipTrackId: string) {
|
||||
if (e.dataTransfer?.types.includes('application/x-animatr-clip')) {
|
||||
const types = e.dataTransfer?.types
|
||||
if (
|
||||
types?.includes('application/x-animatr-clip') ||
|
||||
types?.includes('application/x-animatr-button-clip')
|
||||
) {
|
||||
e.preventDefault()
|
||||
if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'
|
||||
}
|
||||
@@ -1362,6 +1366,11 @@ function onClipLaneDrop(e: DragEvent, clipTrackId: string) {
|
||||
const clipId = e.dataTransfer?.getData('application/x-animatr-clip')
|
||||
if (clipId) {
|
||||
store.addClipInstance(clipId, time, clipTrackId)
|
||||
return
|
||||
}
|
||||
const buttonClipId = e.dataTransfer?.getData('application/x-animatr-button-clip')
|
||||
if (buttonClipId) {
|
||||
store.addButtonInstance(buttonClipId, clipTrackId, time)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1421,16 +1430,24 @@ function onClipBlockPointerUp(e: PointerEvent) {
|
||||
|
||||
const clipDragOverDropzone = ref(false)
|
||||
|
||||
function isClipDragLike(e: DragEvent): boolean {
|
||||
const types = e.dataTransfer?.types
|
||||
return !!(
|
||||
types?.includes('application/x-animatr-clip') ||
|
||||
types?.includes('application/x-animatr-button-clip')
|
||||
)
|
||||
}
|
||||
|
||||
function onNewTrackDragEnter(e: DragEvent) {
|
||||
if (!e.dataTransfer?.types.includes('application/x-animatr-clip')) return
|
||||
if (!isClipDragLike(e)) return
|
||||
e.preventDefault()
|
||||
clipDragOverDropzone.value = true
|
||||
}
|
||||
|
||||
function onNewTrackDragOver(e: DragEvent) {
|
||||
if (!e.dataTransfer?.types.includes('application/x-animatr-clip')) return
|
||||
if (!isClipDragLike(e)) return
|
||||
e.preventDefault()
|
||||
e.dataTransfer.dropEffect = 'copy'
|
||||
if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy'
|
||||
clipDragOverDropzone.value = true
|
||||
}
|
||||
|
||||
@@ -1441,12 +1458,14 @@ function onNewTrackDragLeave() {
|
||||
function onNewTrackDrop(e: DragEvent) {
|
||||
clipDragOverDropzone.value = false
|
||||
const clipId = e.dataTransfer?.getData('application/x-animatr-clip')
|
||||
if (!clipId) return
|
||||
const buttonClipId = e.dataTransfer?.getData('application/x-animatr-button-clip')
|
||||
if (!clipId && !buttonClipId) return
|
||||
e.preventDefault()
|
||||
const el = e.currentTarget as HTMLElement
|
||||
const time = pixelTimeFromLane(e, el)
|
||||
const track = store.addClipTrack()
|
||||
store.addClipInstance(clipId, time, track.id)
|
||||
if (clipId) store.addClipInstance(clipId, time, track.id)
|
||||
else if (buttonClipId) store.addButtonInstance(buttonClipId, track.id, time)
|
||||
}
|
||||
|
||||
function pixelTimeFromLane(e: DragEvent, el: HTMLElement): number {
|
||||
|
||||
Reference in new issue
Block a user