aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--components/icons.tsx2
-rw-r--r--package.json1
-rw-r--r--pages/editor.tsx50
-rw-r--r--styles/editor.css4
-rw-r--r--styles/keyframes.css10
-rw-r--r--yarn.lock5
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 <div className={'keyframe dispinbl posrel' + (props.ghost ? ' ghost' : '')}>
- {props.ghost && <SlideKeyframeOutline type={props.type} loopEnd={props.loopEnd} />}
+ <SlideKeyframeOutline type={props.type} loopEnd={props.loopEnd} />
<SlideKeyframeBackground type={props.type} loopEnd={props.loopEnd} />
</div>;
}
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<anySlide>) {
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 <animated.div
@@ -177,8 +182,8 @@ function TimelineEditor(props: {
var setTimelineLabels = useTimelineLabels((st: any) => 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 <>
- <canvas className='timeScale posabs a0' id='timeScaleCanvas' />
+ <canvas
+ className='timeScale posabs a0'
+ id='timeScaleCanvas'
+ onClick={event => {
+ // 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);
+ }}
+ />
<div className='labels' children={timelineLabels} />
<div className='scrubberJumpArea posabs h0 t0' ref={scrubberDragRef} />
- <div className='timelineInner posabs a0'>
+ <div className={'timelineInner posabs a0' + (props.selectedTool != 'cursor' ? ' blur' : '')}>
<animated.div
className='scrubber posabs v0'
style={{ '--frame': scrubberPos.frame } as CSSProperties}
diff --git a/styles/editor.css b/styles/editor.css
index 7eda309..a333a56 100644
--- a/styles/editor.css
+++ b/styles/editor.css
@@ -217,6 +217,10 @@
white-space: nowrap;
}
+.appGrid .timeline .timelineInner.blur {
+ pointer-events: none;
+}
+
.timeline .scrubber {
width: 2px;
overflow: visible;
diff --git a/styles/keyframes.css b/styles/keyframes.css
index 8a4f06f..4d9f472 100644
--- a/styles/keyframes.css
+++ b/styles/keyframes.css
@@ -44,5 +44,15 @@
fill: currentColor;
}
+.keyframe .background,
+.keyframe .outline {
+ opacity: 1;
+ transition-property: opacity;
+ transition-duration: 200ms;
+}
+
.keyframe.ghost .background { opacity: .2; }
.keyframe.ghost .outline { opacity: .7; }
+
+#ghost { transform: translate(-16px, -16px); }
+
diff --git a/yarn.lock b/yarn.lock
index ba785de..31091a8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -323,6 +323,11 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275"
integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==
+"@types/uuid@^8.3.0":
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f"
+ integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==
+
ajv@^8.3.0:
version "8.5.0"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.5.0.tgz#695528274bcb5afc865446aa275484049a18ae4b"