From 45a4cda8d9d5b205804216b9089918f1718b96f4 Mon Sep 17 00:00:00 2001 From: lonkaars Date: Tue, 25 May 2021 20:32:07 +0200 Subject: keyframe placement :tada: --- components/icons.tsx | 2 +- package.json | 1 + pages/editor.tsx | 50 +++++++++++++++++++++++++++++++++++--------------- styles/editor.css | 4 ++++ styles/keyframes.css | 10 ++++++++++ yarn.lock | 5 +++++ 6 files changed, 56 insertions(+), 16 deletions(-) diff --git a/components/icons.tsx b/components/icons.tsx index ea73b26..cf60f54 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -121,7 +121,7 @@ export function SlideKeyframe(props: { loopEnd?: boolean; }) { return
- {props.ghost && } +
; } diff --git a/package.json b/package.json index a8438b3..9ece09e 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@material-ui/lab": "^4.0.0-alpha.58", "@mdi/js": "^5.9.55", "@mdi/react": "^1.5.0", + "@types/uuid": "^8.3.0", "ajv": "^8.3.0", "mousetrap": "^1.6.5", "next": "^10.2.0", diff --git a/pages/editor.tsx b/pages/editor.tsx index 2058485..c2406a5 100644 --- a/pages/editor.tsx +++ b/pages/editor.tsx @@ -1,6 +1,7 @@ import { CSSProperties, ReactNode, useEffect, useRef, useState } from 'react'; import { animated, useSpring } from 'react-spring'; import { useDrag } from 'react-use-gesture'; +import { v4 as uuid } from 'uuid'; import create from 'zustand'; import { anySlide, loopSlide, slide, slideTypes } from '../timeline'; import { TimedVideoPlayer } from './present'; @@ -25,9 +26,19 @@ import { PressureIcon, SlideKeyframe } from '../components/icons'; import PlaySkipIconAni from '../components/play-skip'; var player = new TimedVideoPlayer(); -var useWorkingTimeline = create(set => ({ +var useWorkingTimeline = create((set, get) => ({ timeline: [], setTimeline: (newTimeline: anySlide[]) => set(() => ({ timeline: newTimeline })), + refreshLiveTimeline: () => { + player.timeline.slides = Array(...((get() as any).timeline)); + player.timeline.slides.sort((a: anySlide, b: anySlide) => a.frame - b.frame); + player.timeline.slides[-1] = { // TODO: dry + id: '00000000-0000-0000-0000-000000000000', + frame: 0, + type: 'default', + clickThroughBehaviour: 'ImmediatelySkip', + }; + }, })); var getTimelineZoom = create(set => ({ @@ -59,6 +70,7 @@ function TimelineKeyframe(props: { }) { var workingTimeline = useWorkingTimeline((st: any) => st.timeline); var setWorkingTimeline = useWorkingTimeline((st: any) => st.setTimeline); + var updateTimeline = useWorkingTimeline((st: any) => st.refreshLiveTimeline); function modifySlide(newProps: Partial) { var slide = workingTimeline.find((s: anySlide) => s.id == props.slide.id); @@ -130,14 +142,7 @@ function TimelineKeyframe(props: { var mouseUpListener = useRef(null); useDrag(({ last }) => { if (!last) return; - player.timeline.slides = Array(...workingTimeline); - player.timeline.slides.sort((a: anySlide, b: anySlide) => a.frame - b.frame); - player.timeline.slides[-1] = { // TODO: dry - id: '00000000-0000-0000-0000-000000000000', - frame: 0, - type: 'default', - clickThroughBehaviour: 'ImmediatelySkip', - }; + updateTimeline(); }, { domTarget: mouseUpListener, eventOptions: { passive: false } }); return st.setLabels); var workingTimeline = useWorkingTimeline((st: any) => st.timeline); + var setWorkingTimeline = useWorkingTimeline((st: any) => st.setTimeline); - // var frame = useFrame((st: any) => st.currentFrame); var setFrame = useFrame((st: any) => st.setFrame); useEffect(() => { @@ -305,18 +310,33 @@ function TimelineEditor(props: { useEffect(() => { document.querySelector('.timeline').addEventListener('mousemove', (e: MouseEvent) => { var rect = document.querySelector('.timeline').getBoundingClientRect(); - var offset = 16; - var x = e.clientX - rect.left - offset; - var y = e.clientY - rect.top - offset; + var x = e.clientX - rect.left; + var y = e.clientY - rect.top; ghostApi.start({ x, y }); }); }, []); return <> - + { + // place new keyframe + var x = event.clientX - 240; + var frame = Math.round(getFrameAtOffset(x, timelineZoom)); + var id = uuid(); + workingTimeline.push({ + frame, + id, + type: props.selectedTool as slideTypes, + clickThroughBehaviour: 'ImmediatelySkip', + }); + setWorkingTimeline(workingTimeline); + }} + />
-
+