initial work

This commit is contained in:
FromTheLOLAshes committed 2024-03-24 19:00:44 +07:00
1 parent dbaa6e561b
commit 200d6659e8
74 files changed
+783 -156

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+11
View File
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="SonarLintModuleSettings">
<option name="uniqueId" value="235600e7-719d-4c51-a8ab-0dad8280bf12" />
</component>
</module>
+78
View File
@@ -0,0 +1,78 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<HTMLCodeStyleSettings>
<option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" />
</HTMLCodeStyleSettings>
<JSCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</JSCodeStyleSettings>
<PHPCodeStyleSettings>
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
<option name="LOWER_CASE_NULL_CONST" value="true" />
<option name="ELSE_IF_STYLE" value="COMBINE" />
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
</PHPCodeStyleSettings>
<TypeScriptCodeStyleSettings version="0">
<option name="FORCE_SEMICOLON_STYLE" value="true" />
<option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" />
<option name="FORCE_QUOTE_STYlE" value="true" />
<option name="ENFORCE_TRAILING_COMMA" value="Remove" />
<option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" />
<option name="SPACES_WITHIN_IMPORTS" value="true" />
</TypeScriptCodeStyleSettings>
<VueCodeStyleSettings>
<option name="INTERPOLATION_NEW_LINE_AFTER_START_DELIMITER" value="false" />
<option name="INTERPOLATION_NEW_LINE_BEFORE_END_DELIMITER" value="false" />
</VueCodeStyleSettings>
<codeStyleSettings language="HTML">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="JavaScript">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="PHP">
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="true" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_LBRACE_ON_NEXT_LINE" value="true" />
<option name="ARRAY_INITIALIZER_RBRACE_ON_NEXT_LINE" value="true" />
<option name="IF_BRACE_FORCE" value="3" />
<option name="DOWHILE_BRACE_FORCE" value="3" />
<option name="WHILE_BRACE_FORCE" value="3" />
<option name="FOR_BRACE_FORCE" value="3" />
</codeStyleSettings>
<codeStyleSettings language="TypeScript">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="TAB_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="Vue">
<option name="SOFT_MARGINS" value="80" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="2" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>
+5
View File
@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>
+6
View File
@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/GottaGoFast.iml" filepath="$PROJECT_DIR$/.idea/GottaGoFast.iml" />
</modules>
</component>
</project>
Generated
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PrettierConfiguration">
<option name="myConfigurationMode" value="AUTOMATIC" />
<option name="myRunOnSave" value="true" />
</component>
</project>
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
+55
View File
@@ -0,0 +1,55 @@
9
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d
L
app/contexts/TopBarInner.tsx,b/1/b137962450c33edc117c975cf0bdf9f95b0cb188
C
app/styles/base.css,c/b/cbc16b6483d87b2c5af91b2f6ee5b84e644e9f88
H
app/styles/normalize.css,1/1/1193d972f0d2d8e13bf2a89c9f1b856c95dfd960
G
app/styles/tailwind.css,6/4/64b5dc72a41f7c1b594f0c4f67057c3fac409dba
B
tailwind.config.ts,5/2/52c961376029165b06e7861b1dc68c3b2455eeff
=
␍tsconfig.json,6/1/61ebb9fd6e8cf9082658121d5d81e297791dacd0
>
vite.config.ts,7/5/75ea7f3ea6d80d54bb5b2357996972d1632a5038
J
app/routes/IdealEnigma.tsx,5/d/5d3ccf1210662cac26b4f75e4524acb75a3e05c9
E
app/routes/_index.tsx,9/4/948fdf96da2c0e9325e8e3e8f8d14a3350da1b3e
S
#app/pages/PageEnigma/PageEnigma.tsx,1/4/1420acf507a4c451001a79a2943ae324a632cb7f
`
0app/pages/PageEnigma/comps/Timeline/Timeline.tsx,8/8/887452a6317b847c87ae01be3bf58418fdeb2e04
U
%app/modules/LowerPanel/LowerPanel.tsx,9/b/9b3cd0ade34737345060fc9dd9d369dbb2733205
b
2app/pages/PageEnigma/comps/Character/Character.tsx,a/e/ae6393cb0765a08a83849b56f401b2f8614aa21c
]
-app/pages/PageEnigma/comps/Timeline/index.tsx,b/a/ba2e6c6255fa02042bec9e54e0f73263850a1fdd
^
.app/pages/PageEnigma/comps/Character/index.tsx,0/1/01907caaf8abcd59e24d8d26bdd37f7a07238793
j
:app/pages/PageEnigma/comps/ControlsVideo/ControlsVideo.tsx,1/d/1d2d0feb3a048b584049c5ba95077f97e967bb36
f
6app/pages/PageEnigma/comps/Character/CharacterClip.tsx,c/2/c2403f3b1e36ca4357db2d4ba8d5cce7a637a0fc
a
1app/pages/PageEnigma/comps/Timeline/Character.tsx,4/0/4078c3af2bc43a60f7345e34a7230534f9f7b245
a
1app/pages/PageEnigma/comps/Timeline/TrackClip.tsx,4/f/4fbf6de228c6518666127eb4b8bf99bd053f99fe
j
:app/pages/PageEnigma/comps/Timeline/utils/onPointerDown.ts,c/7/c77be8c5fbeeea4a34fb2465336598ccff026866
k
;app/pages/PageEnigma/comps/Timeline/utils/useMouseEvents.ts,e/e/ee716328020ea5d007c5d60a9deed2c398037e16
B
app/models/clip.ts,8/1/81a15ef2fee7c3e161b66ac6f5bbd6523327059f
M
app/contexts/TrackContext.tsx,2/a/2ae173334be35fe61e7a084bd67ecfa5b05015e4
C
app/models/track.ts,f/c/fcfd183a1d0f4cd1a9e368888c85ea2fbe212d56
M
app/contexts/TrackProvider.ts,5/f/5f22b1bbace0f13f764b3c745759a6b7c4d6e5d9
N
app/contexts/TrackProvider.tsx,f/4/f4da9805e7b7c03da93082b44221693aec65a52e
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
Whitespace-only changes.
+55
View File
@@ -0,0 +1,55 @@
9
README.md,8/e/8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d
L
app/contexts/TopBarInner.tsx,b/1/b137962450c33edc117c975cf0bdf9f95b0cb188
C
app/styles/base.css,c/b/cbc16b6483d87b2c5af91b2f6ee5b84e644e9f88
H
app/styles/normalize.css,1/1/1193d972f0d2d8e13bf2a89c9f1b856c95dfd960
G
app/styles/tailwind.css,6/4/64b5dc72a41f7c1b594f0c4f67057c3fac409dba
B
tailwind.config.ts,5/2/52c961376029165b06e7861b1dc68c3b2455eeff
=
␍tsconfig.json,6/1/61ebb9fd6e8cf9082658121d5d81e297791dacd0
>
vite.config.ts,7/5/75ea7f3ea6d80d54bb5b2357996972d1632a5038
J
app/routes/IdealEnigma.tsx,5/d/5d3ccf1210662cac26b4f75e4524acb75a3e05c9
E
app/routes/_index.tsx,9/4/948fdf96da2c0e9325e8e3e8f8d14a3350da1b3e
S
#app/pages/PageEnigma/PageEnigma.tsx,1/4/1420acf507a4c451001a79a2943ae324a632cb7f
`
0app/pages/PageEnigma/comps/Timeline/Timeline.tsx,8/8/887452a6317b847c87ae01be3bf58418fdeb2e04
U
%app/modules/LowerPanel/LowerPanel.tsx,9/b/9b3cd0ade34737345060fc9dd9d369dbb2733205
b
2app/pages/PageEnigma/comps/Character/Character.tsx,a/e/ae6393cb0765a08a83849b56f401b2f8614aa21c
]
-app/pages/PageEnigma/comps/Timeline/index.tsx,b/a/ba2e6c6255fa02042bec9e54e0f73263850a1fdd
^
.app/pages/PageEnigma/comps/Character/index.tsx,0/1/01907caaf8abcd59e24d8d26bdd37f7a07238793
j
:app/pages/PageEnigma/comps/ControlsVideo/ControlsVideo.tsx,1/d/1d2d0feb3a048b584049c5ba95077f97e967bb36
f
6app/pages/PageEnigma/comps/Character/CharacterClip.tsx,c/2/c2403f3b1e36ca4357db2d4ba8d5cce7a637a0fc
a
1app/pages/PageEnigma/comps/Timeline/Character.tsx,4/0/4078c3af2bc43a60f7345e34a7230534f9f7b245
a
1app/pages/PageEnigma/comps/Timeline/TrackClip.tsx,4/f/4fbf6de228c6518666127eb4b8bf99bd053f99fe
j
:app/pages/PageEnigma/comps/Timeline/utils/onPointerDown.ts,c/7/c77be8c5fbeeea4a34fb2465336598ccff026866
k
;app/pages/PageEnigma/comps/Timeline/utils/useMouseEvents.ts,e/e/ee716328020ea5d007c5d60a9deed2c398037e16
B
app/models/clip.ts,8/1/81a15ef2fee7c3e161b66ac6f5bbd6523327059f
M
app/contexts/TrackContext.tsx,2/a/2ae173334be35fe61e7a084bd67ecfa5b05015e4
C
app/models/track.ts,f/c/fcfd183a1d0f4cd1a9e368888c85ea2fbe212d56
M
app/contexts/TrackProvider.ts,5/f/5f22b1bbace0f13f764b3c745759a6b7c4d6e5d9
N
app/contexts/TrackProvider.tsx,f/4/f4da9805e7b7c03da93082b44221693aec65a52e
Generated
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+20
View File
@@ -0,0 +1,20 @@
import { createContext } from "react";
import { CharacterTrack } from "~/models/track";
export const TrackContext = createContext<{
characters: CharacterTrack[];
updateCharacters: (options: {
type: "animations" | "positions" | "lipSync";
id: string;
length: number;
offset: number;
}) => void;
selectClip: (options: {
type: "animations" | "positions" | "lipSync";
id: string;
}) => void;
}>({
characters: [],
updateCharacters: () => {},
selectClip: () => {},
});
+133
View File
@@ -0,0 +1,133 @@
import { TrackContext } from "~/contexts/TrackContext";
import { ReactNode, useCallback, useMemo, useState } from "react";
import { CharacterTrack } from "~/models/track";
interface Props {
children: ReactNode;
}
export const TrackProvider = ({ children }: Props) => {
const [characters, setCharacters] = useState<CharacterTrack[]>([
{
id: "t1",
animationClips: [
{
id: "1",
length: 200,
offset: 0,
name: "track 1",
selected: false,
},
{
id: "2",
length: 180,
offset: 300,
name: "track 2",
selected: false,
},
],
positionClips: [],
lipSyncClips: [],
},
]);
const updateCharacters = useCallback(
({
type,
id,
offset,
length,
}: {
type: "animations" | "positions" | "lipSync";
id: string;
length: number;
offset: number;
}) => {
if (type === "animations") {
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
const newAnimationClips = [...character.animationClips];
const clipIndex = newAnimationClips.findIndex(
(row) => row.id === id,
);
if (clipIndex === -1) {
return { ...character };
}
const clip = newAnimationClips[clipIndex];
clip.offset = offset;
clip.length = length;
return {
...character,
animationClips: newAnimationClips,
};
});
});
return;
}
},
[],
);
const selectClip = useCallback(
({
type,
id,
}: {
type: "animations" | "positions" | "lipSync";
id: string;
}) => {
if (type === "animations") {
setCharacters((oldCharacters) => {
return oldCharacters.map((character) => {
const newAnimationClips = character.animationClips.map((clip) => ({
...clip,
selected: false,
}));
const newPositionClips = character.positionClips.map((clip) => ({
...clip,
selected: false,
}));
const newLipSyncClips = character.lipSyncClips.map((clip) => ({
...clip,
selected: false,
}));
const clipIndex = newAnimationClips.findIndex(
(row) => row.id === id,
);
if (clipIndex === -1) {
return {
...character,
animationClips: newAnimationClips,
positionClips: newPositionClips,
lipSyncClips: newLipSyncClips,
};
}
const clip = newAnimationClips[clipIndex];
clip.selected = true;
return {
...character,
animationClips: newAnimationClips,
positionClips: newPositionClips,
lipSyncClips: newLipSyncClips,
};
});
});
return;
}
},
[],
);
console.log(characters);
const values = useMemo(() => {
return {
characters,
updateCharacters,
selectClip,
};
}, [characters, updateCharacters]);
return (
<TrackContext.Provider value={values}>{children}</TrackContext.Provider>
);
};
+20
View File
@@ -0,0 +1,20 @@
export interface BaseClip {
id: string;
name: string;
offset: number;
length: number;
selected: boolean;
}
export interface AnimationClip extends BaseClip {}
export interface PositionClip extends BaseClip {}
export interface LipSyncClip extends BaseClip {}
export interface CharacterTrack {
id: string;
animationClips: AnimationClip[];
positionClips: PositionClip[];
lipSyncClips: LipSyncClip[];
}
+63 -69
View File
@@ -1,28 +1,22 @@
import {
useCallback,
useEffect,
useRef,
} from 'react';
import { useCallback, useEffect, useRef } from "react";
import {
faChevronLeft,
faWandSparkles,
} from "@fortawesome/pro-solid-svg-icons";
import { Button, ButtonLink } from "~/components";
import { ButtonDialogue } from "~/modules/ButtonDialogue";
import { TopBarHelmet } from "~/modules/TopBarHelmet/TopBarHelmet";
import { SidePanel } from "~/modules/SidePanel";
import { Tabs } from "~/modules/Tabs";
import { Controls3D } from "./comps/Controls3D";
import { ControlsVideo } from "./comps/ControlsVideo";
import { Timeline } from "./comps/Timeline";
import {
Button,
ButtonLink,
} from '~/components';
import { ButtonDialogue } from '~/modules/ButtonDialogue';
import { TopBarHelmet } from '~/modules/TopBarHelmet/TopBarHelmet';
import { SidePanel } from '~/modules/SidePanel';
import { Tabs } from '~/modules/Tabs';
import { Controls3D } from './comps/Controls3D';
import { ControlsVideo } from './comps/ControlsVideo';
import { Timeline } from './comps/Timeline';
import Editor from './js/editor';
import Editor from "./js/editor";
import { TrackContext } from "~/contexts/TrackContext";
import { TrackProvider } from "~/contexts/TrackProvider";
export const PageEnigma = () => {
// const { setTopBarInner } = useContext(TopBarInnerContext) || {};
@@ -30,61 +24,54 @@ export const PageEnigma = () => {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const editorRef = useRef<Editor | null>(null);
const editorCallback = useCallback(() => {
// handle editorCallback here
},[]);
}, []);
useEffect(() => { //componentDidMount
useEffect(() => {
//componentDidMount
editorRef.current = new Editor();
function init(){
if(editorRef.current!==null){
function init() {
if (editorRef.current !== null) {
//TODO: init with editorRef.current.initialize(editorCallback);
editorRef.current.initialize();
}
}
if(canvasRef!==null){
if (canvasRef !== null) {
init();
}else{
} else {
setTimeout(init, 500);
}
}, []);
const handleButtonSave = ()=>{
const handleButtonSave = () => {
editorRef.current?.save();
}
};
return(
return (
<div>
<TopBarHelmet>
<div className="flex grow justify-between">
<ButtonLink
to={"/"}
variant='secondary'
icon={faChevronLeft}
>
Back to Dashboard
</ButtonLink>
<Button
icon={faWandSparkles}
>
Generate Movie
</Button>
<span className="w-8"/>
</div>
<ButtonLink to={"/"} variant="secondary" icon={faChevronLeft}>
Back to Dashboard
</ButtonLink>
<Button icon={faWandSparkles}>Generate Movie</Button>
<span className="w-8" />
</div>
</TopBarHelmet>
<canvas ref={canvasRef} id="video-scene" width="1280px" height="720px" />
<div className='fixed top-20 left-4'>
<div className="flex mt-2 gap-2">
<div className="fixed left-4 top-20">
<div className="mt-2 flex gap-2">
<Button variant="secondary">Toggle Camera View</Button>
<Button variant="secondary" onClick={handleButtonSave}>Save Scene</Button>
<Button variant="secondary" onClick={handleButtonSave}>
Save Scene
</Button>
<ButtonDialogue
buttonProps={{
variant: 'secondary',
label: 'Help'
variant: "secondary",
label: "Help",
}}
title="Help"
>
@@ -93,28 +80,35 @@ export const PageEnigma = () => {
<p>Ask Miles about ThreeJS</p>
<p>Ask Wil about React</p>
</ButtonDialogue>
<Controls3D/>
<ControlsVideo/>
<Controls3D />
<ControlsVideo />
</div>
</div>
<SidePanel>
<Tabs tabs={[
{
header: 'Animation',
children: <p>Animation Tab</p>
},{
header: 'Camera',
children: <p>Camera Tab</p>
},{
header: 'Audio',
children: <p>Audio Tab</p>
},{
header: 'Styling',
children: <p>Styling Tab</p>
}
]}/>
<Tabs
tabs={[
{
header: "Animation",
children: <p>Animation Tab</p>,
},
{
header: "Camera",
children: <p>Camera Tab</p>,
},
{
header: "Audio",
children: <p>Audio Tab</p>,
},
{
header: "Styling",
children: <p>Styling Tab</p>,
},
]}
/>
</SidePanel>
<Timeline editorCurrent={editorRef.current}/>
<TrackProvider>
<Timeline editorCurrent={editorRef.current} />
</TrackProvider>
</div>
);
}
};
@@ -0,0 +1,50 @@
import { TrackClip } from "./TrackClip";
import { CharacterTrack } from "~/models/track";
interface Props {
scale: number;
time: number;
character: CharacterTrack;
updateClip: (id: string, offset: number, length: number) => void;
}
export const Character = ({
character: { animationClips },
updateClip,
}: Props) => {
return (
<div className="bg-charcter-groupBg block h-48 w-full rounded-lg p-2">
<div className="mb-2 text-sm text-white">Character</div>
<div className="flex flex-col gap-2">
<div className="px-4">
<div className="bg-character-clip relative mt-4 block h-8 w-full rounded">
{animationClips.map((clip, index) => (
<TrackClip
key={clip.id}
min={
index > 0
? animationClips[index - 1].offset +
animationClips[index - 1].length
: 0
}
max={
index < animationClips.length - 1
? animationClips[index + 1].offset
: 1000
}
updateClip={updateClip}
clip={clip}
/>
))}
</div>
</div>
<div className="px-4">
<div className="relative mt-4 block h-8 w-full rounded bg-brand-secondary-800"></div>
</div>
<div className="px-4">
<div className="relative mt-4 block h-8 w-full rounded bg-brand-secondary-800"></div>
</div>
</div>
</div>
);
};
@@ -1,31 +1,43 @@
import { LowerPanel } from "~/modules/LowerPanel";
import {
Button,
} from '~/components';
import Editor from '../../js/editor';
import Editor from "../../js/editor";
import { Character } from "./Character";
import { useCallback, useContext } from "react";
import { TrackContext } from "~/contexts/TrackContext";
export const Timeline = ({
editorCurrent
}:{
editorCurrent: Editor|null;
})=>{
const handleButtonLoad = ()=>{
document.getElementById("load-upload")?.click();
}
const handleButtonRender = ()=>{
editorCurrent?.togglePlayback();
}
const handleButtonPlay = ()=>{
editorCurrent,
}: {
editorCurrent: Editor | null;
}) => {
const { characters, updateCharacters } = useContext(TrackContext);
}
const updateClip = useCallback(
(id: string, offset: number, length: number) => {
updateCharacters({ type: "animations", id, offset, length });
},
[],
);
return(
return (
<LowerPanel>
<div className='h-10 w-full border-b border-ui-panel-border'></div>
<input style={{ display: 'none' }} type="file" id="load-upload" name="load-upload"></input>
<Button onClick={handleButtonLoad}>Load</Button>
<Button onClick={handleButtonRender}>Render</Button>
<Button onClick={handleButtonPlay}>Play</Button>
<div className="h-10 w-full border-b border-ui-panel-border"></div>
<input
style={{ display: "none" }}
type="file"
id="load-upload"
name="load-upload"
></input>
<div className="mr-4 p-4">
{characters.map((character) => (
<Character
key={character.id}
scale={1}
time={0}
character={character}
updateClip={updateClip}
/>
))}
</div>
</LowerPanel>
)
}
);
};
@@ -0,0 +1,65 @@
import { useMouseEvents } from "./utils/useMouseEvents";
import { BaseClip } from "~/models/track";
import { TrackContext } from "~/contexts/TrackContext";
import { useContext } from "react";
interface Props {
min: number;
max: number;
clip: BaseClip;
updateClip: (id: string, offset: number, length: number) => void;
selected?: boolean;
}
export const TrackClip = ({ clip, min, max, updateClip }: Props) => {
const { selectClip } = useContext(TrackContext);
const {
onPointerDown,
onPointerUp,
onMouseLeave,
onMouseMove,
offset,
length,
} = useMouseEvents(clip, max, min, updateClip);
if (clip.selected) {
console.log("selected", clip);
}
return (
<>
<div
className="absolute text-sm text-white"
style={{ top: -20, left: offset }}
>
{clip.name}
</div>
<button
className={`bg-character-${clip.selected ? "selected" : "unselected"} absolute block h-full rounded-l`}
style={{ width: 15, left: offset, cursor: "w-resize" }}
onPointerDown={(event) => onPointerDown(event, "left")}
onPointerUp={onPointerUp}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
onClick={() => selectClip({ type: "animations", id: clip.id })}
/>
<button
className={`bg-character-${clip.selected ? "selected" : "unselected"} absolute block h-full`}
style={{ width: length - 30, left: offset + 15, cursor: "move" }}
onPointerDown={(event) => onPointerDown(event, "drag")}
onPointerUp={onPointerUp}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
onClick={() => selectClip({ type: "animations", id: clip.id })}
/>
<button
className={`bg-character-${clip.selected ? "selected" : "unselected"} absolute block h-full rounded-r`}
style={{ width: 15, left: offset + length - 15, cursor: "e-resize" }}
onPointerDown={(event) => onPointerDown(event, "right")}
onPointerUp={onPointerUp}
onMouseLeave={onMouseLeave}
onMouseMove={onMouseMove}
onClick={() => selectClip({ type: "animations", id: clip.id })}
/>
</>
);
};
@@ -0,0 +1,63 @@
import { useState, PointerEvent, MouseEvent } from "react";
export const useMouseEvents = (
clip: { id: string; offset: number; length: number; name: string },
max: number,
min: number,
updateClip: (id: string, offset: number, length: number) => void,
) => {
const [isActive, setIsActive] = useState("");
const [clientX, setClientX] = useState(0);
const [offset, setOffset] = useState(clip.offset);
const [length, setLength] = useState(clip.length);
return {
onPointerDown: (event: PointerEvent<HTMLButtonElement>, type: string) => {
if (event.button === 0) {
const x = event.clientX - 40;
setClientX(event.clientX);
setIsActive(type);
}
},
onPointerUp: () => {
if (isActive) {
updateClip(clip.id, offset, length);
setIsActive("");
}
},
onMouseLeave: () => {
if (isActive) {
updateClip(clip.id, offset, length);
setIsActive("");
}
},
onMouseMove: (event: MouseEvent) => {
const deltaOffset = event.clientX - clientX + clip.offset;
const delta = event.clientX - clientX;
if (isActive === "drag") {
if (deltaOffset < min || deltaOffset + length > max) {
return;
}
setOffset(deltaOffset);
return;
}
if (isActive === "left") {
if (deltaOffset < min) {
return;
}
setOffset(deltaOffset);
setLength(clip.length - delta);
return;
}
if (isActive === "right") {
if (clip.length + delta < 30 || offset + clip.length + delta > max) {
return;
}
setLength(clip.length + delta);
}
},
length,
offset,
};
};
+75 -63
View File
@@ -1,5 +1,5 @@
import type { Config } from 'tailwindcss';
import colors from 'tailwindcss/colors';
import type { Config } from "tailwindcss";
import colors from "tailwindcss/colors";
export default {
content: [
@@ -9,75 +9,87 @@ export default {
],
theme: {
// extend: {},
colors:{
transparent: 'transparent',
current: 'currentColor',
colors: {
transparent: "transparent",
current: "currentColor",
'brand-primary': { //sunglo
DEFAULT: '#e66462', //=500
'50': '#fdf3f3',
'100': '#fce4e4',
'200': '#facfce',
'300': '#f6acab',
'400': '#ef7c7a',
'500': '#e66462',
'600': '#cf3533',
'700': '#ae2927',
'800': '#902624',
'900': '#782524',
'950': '#410f0e',
"brand-primary": {
//sunglo
DEFAULT: "#e66462", //=500
"50": "#fdf3f3",
"100": "#fce4e4",
"200": "#facfce",
"300": "#f6acab",
"400": "#ef7c7a",
"500": "#e66462",
"600": "#cf3533",
"700": "#ae2927",
"800": "#902624",
"900": "#782524",
"950": "#410f0e",
},
'brand-secondary': { //gunpowder
DEFAULT: '#39394c', //=950
'50': '#f5f6f9',
'100': '#e8eaf1',
'200': '#d7dbe6',
'300': '#bbc1d5',
'400': '#9aa2c0',
'500': '#8188b0',
'600': '#6f74a1',
'700': '#636492',
'800': '#545579',
'900': '#464762',
'950': '#39394c',
"brand-secondary": {
//gunpowder
DEFAULT: "#39394c", //=950
"50": "#f5f6f9",
"100": "#e8eaf1",
"200": "#d7dbe6",
"300": "#bbc1d5",
"400": "#9aa2c0",
"500": "#8188b0",
"600": "#6f74a1",
"700": "#636492",
"800": "#545579",
"900": "#464762",
"950": "#39394c",
},
danger: { //copper rust
DEFAULT: '#8f4951', //=700
'50': '#fbf5f5',
'100': '#f7ecec',
'200': '#efdcdc',
'300': '#e2c0bf',
'400': '#d19b9c',
'500': '#bd7679',
'600': '#a5595f',
'700': '#8f4951',
'800': '#743d45',
'900': '#64373f',
'950': '#361b1e',
danger: {
//copper rust
DEFAULT: "#8f4951", //=700
"50": "#fbf5f5",
"100": "#f7ecec",
"200": "#efdcdc",
"300": "#e2c0bf",
"400": "#d19b9c",
"500": "#bd7679",
"600": "#a5595f",
"700": "#8f4951",
"800": "#743d45",
"900": "#64373f",
"950": "#361b1e",
},
success:{ //apple
DEFAULT: '#40ad48', //=500
'50': '#f2fbf2',
'100': '#e2f6e3',
'200': '#c5edc7',
'300': '#98dd9d',
'400': '#64c46b',
'500': '#40ad48',
'600': '#2f8a35',
'700': '#286d2e',
'800': '#245728',
'900': '#1f4823',
'950': '#0c270f',
success: {
//apple
DEFAULT: "#40ad48", //=500
"50": "#f2fbf2",
"100": "#e2f6e3",
"200": "#c5edc7",
"300": "#98dd9d",
"400": "#64c46b",
"500": "#40ad48",
"600": "#2f8a35",
"700": "#286d2e",
"800": "#245728",
"900": "#1f4823",
"950": "#0c270f",
},
'ui-background': '#1a1a27',
'ui-panel': '#242433',
'ui-panel-border': '#5e6097',
character: {
unselected: "#46527C",
selected: "#6384F4",
clip: "#7E92DA",
groupBg: "#2B3448",
},
"ui-background": "#1a1a27",
"ui-panel": "#242433",
"ui-panel-border": "#5e6097",
gray: colors.gray,
white: colors.white
}
white: colors.white,
},
},
plugins: [],
} satisfies Config
safelist: ["bg-character-selected", "bg-character-unselected"],
} satisfies Config;