add app readme
lots of styling improvements fix dark/bright mode
This commit is contained in:
@@ -17,7 +17,8 @@ const SelectTrigger = React.forwardRef<
|
||||
<SelectPrimitive.Trigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm",
|
||||
"placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -38,7 +39,7 @@ const SelectContent = React.forwardRef<
|
||||
<SelectPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-slate-900 text-popover-foreground shadow-md animate-in fade-in-80",
|
||||
"relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-neutral-accent text-popover-foreground shadow-md animate-in fade-in-80",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
@@ -70,7 +71,8 @@ const SelectItem = React.forwardRef<
|
||||
<SelectPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-indigo-800 focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none",
|
||||
"focus:bg-primary focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
15
app/src/components/Panel.tsx
Normal file
15
app/src/components/Panel.tsx
Normal file
@@ -0,0 +1,15 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
|
||||
const Panel: FC<{ title: string; children: ReactNode }> = ({
|
||||
title,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<h3>{title}</h3>
|
||||
<div>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Panel;
|
||||
@@ -36,12 +36,8 @@ export const PaintProperties: FC<PaintPropertiesProps> = ({
|
||||
}) => {
|
||||
return (
|
||||
<div>
|
||||
<fieldset>
|
||||
<label htmlFor="staggered-text-letter-font">Font</label>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<label htmlFor="paint-style-type">PaintStyle</label>
|
||||
|
||||
<Select
|
||||
defaultValue={entity.style.type}
|
||||
onValueChange={(value) => {
|
||||
|
||||
17
app/src/components/ScrollArea.tsx
Normal file
17
app/src/components/ScrollArea.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||
import { FC } from "react";
|
||||
|
||||
const ScrollBar: FC<{ orientation?: "horizontal" | "vertical" }> = ({
|
||||
orientation = "vertical",
|
||||
}) => {
|
||||
return (
|
||||
<ScrollArea.Scrollbar
|
||||
className="flex select-none touch-none p-0.5 bg-neutral-accent transition-colors duration-[160ms] ease-out data-[orientation=vertical]:w-2.5 data-[orientation=horizontal]:flex-col data-[orientation=horizontal]:h-2.5"
|
||||
orientation={orientation}
|
||||
>
|
||||
<ScrollArea.Thumb className="flex-1 bg-main rounded-[10px] relative before:content-[''] before:absolute before:top-1/2 before:left-1/2 before:-translate-x-1/2 before:-translate-y-1/2 before:w-full before:h-full before:min-w-[44px] before:min-h-[44px]" />
|
||||
</ScrollArea.Scrollbar>
|
||||
);
|
||||
};
|
||||
|
||||
export default ScrollBar;
|
||||
@@ -79,6 +79,14 @@ const KeyframeIndicator: FC<{
|
||||
}}
|
||||
whileTap={{
|
||||
scale: 1.6,
|
||||
transition: {
|
||||
scale: {
|
||||
type: "spring",
|
||||
stiffness: 200,
|
||||
damping: 10,
|
||||
mass: 1,
|
||||
},
|
||||
},
|
||||
}}
|
||||
animate={{
|
||||
x: (animationData.offset + keyframe.offset) * TIMELINE_SCALE + 2,
|
||||
@@ -97,8 +105,8 @@ const KeyframeIndicator: FC<{
|
||||
>
|
||||
<motion.span
|
||||
data-selected={selected}
|
||||
className="bg-gray-200
|
||||
data-[selected=true]:bg-indigo-600
|
||||
className="bg-secondary
|
||||
data-[selected=true]:bg-secondary
|
||||
h-full transition-colors"
|
||||
style={{
|
||||
width: 10,
|
||||
@@ -108,7 +116,7 @@ const KeyframeIndicator: FC<{
|
||||
/>
|
||||
</motion.div>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80 backdrop-blur-md bg-slate-700/50">
|
||||
<PopoverContent className="w-80 backdrop-blur-md bg-neutral/50">
|
||||
<KeyframePopover
|
||||
onClose={() => deselectKeyframe()}
|
||||
onUpdate={handleValueUpdate}
|
||||
|
||||
@@ -21,11 +21,11 @@ const TimePicker: FC<TimePickerProps> = () => {
|
||||
step={1}
|
||||
aria-label="Current Frame"
|
||||
>
|
||||
<Slider.Track className="bg-blackA10 relative grow rounded-full h-[3px]">
|
||||
<Slider.Range className="absolute bg-white rounded-full h-full" />
|
||||
<Slider.Track className="bg-neutral-accent relative grow rounded-full h-[3px]">
|
||||
<Slider.Range className="absolute bg-main rounded-full h-full" />
|
||||
</Slider.Track>
|
||||
<Slider.Thumb
|
||||
className="block w-5 h-5 bg-white shadow-[0_2px_10px] shadow-blackA7 rounded-[10px] hover:bg-violet3 focus:outline-none focus:shadow-[0_0_0_5px] focus:shadow-blackA8"
|
||||
className="transition-colors block w-4 h-4 bg-main shadow-[0_2px_10px] shadow-main/20 rounded-[10px] hover:bg-secondary focus:outline-none focus:shadow-[0_0_0_2px] focus:shadow-main"
|
||||
aria-label="Volume"
|
||||
/>
|
||||
</Slider.Root>
|
||||
|
||||
@@ -45,7 +45,7 @@ const Track: FC<TrackProps> = ({ animationData, index, name, entity }) => {
|
||||
dragListener={false}
|
||||
dragControls={controls}
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
className="min-h-8 relative flex flex-1 flex-col gap-1 select-none"
|
||||
className="h-6 relative flex flex-1 flex-col gap-1 select-none"
|
||||
>
|
||||
<motion.div
|
||||
layout
|
||||
@@ -56,7 +56,7 @@ const Track: FC<TrackProps> = ({ animationData, index, name, entity }) => {
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
onPointerDown={(e) => controls.start(e)}
|
||||
className={`h-full transition-all rounded-sm min-w-[200px] p-1 px-2 flex flex-col ${
|
||||
selectedEntity === index ? "bg-gray-800" : "bg-gray-900"
|
||||
selectedEntity === index ? "bg-highlight" : "bg-neutral-accent"
|
||||
}`}
|
||||
>
|
||||
<div className="flex flex-row">
|
||||
@@ -77,17 +77,18 @@ const Track: FC<TrackProps> = ({ animationData, index, name, entity }) => {
|
||||
? deselectEntity()
|
||||
: selectEntity(index)
|
||||
}
|
||||
className="text-white-800 select-none cursor-pointer"
|
||||
className="text-white-800 h-2 text-base leading-loose font-semibold select-none cursor-pointer"
|
||||
>
|
||||
{name}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{ width: TIMELINE_SCALE * 10 }}
|
||||
className="flex h-full flex-row relative bg-gray-900 select-none shrink-0"
|
||||
>
|
||||
<div className="flex h-full w-full flex-row relative rounded-sm bg-neutral-accent/50 select-none shrink-0">
|
||||
<div
|
||||
className="absolute top-0 h-full bg-neutral-accent"
|
||||
style={{ width: TIMELINE_SCALE * 10 }}
|
||||
/>
|
||||
{!isExpanded &&
|
||||
flattenedKeyframes.map((keyframe, index) => (
|
||||
<KeyframeIndicator
|
||||
@@ -132,10 +133,10 @@ const Track: FC<TrackProps> = ({ animationData, index, name, entity }) => {
|
||||
},
|
||||
});
|
||||
}}
|
||||
className="z-10 w-4 bg-slate-500 h-8 top-1 absolute rounded-md select-none cursor-w-resize"
|
||||
className="z-10 w-4 bg-primary/80 h-full top-0 absolute rounded-md select-none cursor-w-resize"
|
||||
/>
|
||||
<motion.div
|
||||
className="z-10 w-4 bg-slate-500 h-8 top-1 absolute rounded-md select-none cursor-e-resize"
|
||||
className="z-10 w-4 bg-primary/80 h-full top-0 absolute rounded-md select-none cursor-e-resize"
|
||||
onMouseDown={(e) => e.preventDefault()}
|
||||
drag="x"
|
||||
animate={{
|
||||
@@ -194,7 +195,7 @@ const Track: FC<TrackProps> = ({ animationData, index, name, entity }) => {
|
||||
},
|
||||
});
|
||||
}}
|
||||
className="z-5 h-8 top-1 absolute rounded-md transition-colors bg-gray-700 hover:bg-gray-600 select-none cursor-grab"
|
||||
className="z-5 h-full top-0 absolute rounded-md transition-colors bg-primary/30 hover:bg-primary/50 select-none cursor-grab"
|
||||
></motion.div>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
@@ -78,10 +78,10 @@ const TrackAnimatedProperty: FC<{
|
||||
<motion.div
|
||||
transition={ease.quint(0.8).out}
|
||||
variants={{ enter: { y: 0, opacity: 1 }, from: { y: -10, opacity: 0 } }}
|
||||
className="flex flex-row bg-slate-900 ml-2 align-center"
|
||||
className="flex flex-row bg-neutral-accent ml-2 align-center"
|
||||
>
|
||||
<div className="min-w-[195px] flex flex-row justify-between px-2">
|
||||
<h4>{animatedProperty.label}</h4>
|
||||
<h4 className="text-main/70">{animatedProperty.label}</h4>
|
||||
<ToggleGroup>
|
||||
<ToggleGroupItem
|
||||
onClick={() =>
|
||||
|
||||
@@ -6,6 +6,8 @@ import Timestamp from "./Timestamp";
|
||||
import { PauseIcon, PlayIcon } from "@radix-ui/react-icons";
|
||||
import { useRenderStateStore } from "stores/render-state.store";
|
||||
import Track from "./Track";
|
||||
import * as ScrollArea from "@radix-ui/react-scroll-area";
|
||||
import ScrollBar from "components/ScrollArea";
|
||||
|
||||
export type AnimationEntity = {
|
||||
offset: number;
|
||||
@@ -37,27 +39,34 @@ const Timeline: FC<TimelineProps> = () => {
|
||||
</div>
|
||||
<Timestamp />
|
||||
</div>
|
||||
<div className="gap-1 w-full flex flex-col overflow-x-auto overflow-y-visible">
|
||||
<div className="z-20 flex flex-row gap-2">
|
||||
<div className="flex-shrink-0 min-w-[200px]" />
|
||||
<TimePicker />
|
||||
<ScrollArea.Root>
|
||||
<ScrollArea.Viewport className="w-full h-full">
|
||||
<div className="gap-1 w-full flex flex-col">
|
||||
<div className="z-20 flex flex-row gap-1">
|
||||
<div className="flex-shrink-0 min-w-[200px]" />
|
||||
<TimePicker />
|
||||
</div>
|
||||
<Reorder.Group
|
||||
className="gap-1 flex flex-col"
|
||||
values={entities}
|
||||
onReorder={setEntities}
|
||||
>
|
||||
{entities.map((entity, index) => (
|
||||
<Track
|
||||
entity={entity}
|
||||
key={entity.id}
|
||||
name={entity.type}
|
||||
index={index}
|
||||
animationData={entity.animation_data}
|
||||
/>
|
||||
))}
|
||||
</Reorder.Group>
|
||||
</div>
|
||||
</ScrollArea.Viewport>
|
||||
<div className="h-4 sticky bottom-0">
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</div>
|
||||
<Reorder.Group
|
||||
className="gap-1 flex flex-col"
|
||||
values={entities}
|
||||
onReorder={setEntities}
|
||||
>
|
||||
{entities.map((entity, index) => (
|
||||
<Track
|
||||
entity={entity}
|
||||
key={entity.id}
|
||||
name={entity.type}
|
||||
index={index}
|
||||
animationData={entity.animation_data}
|
||||
/>
|
||||
))}
|
||||
</Reorder.Group>
|
||||
</div>
|
||||
</ScrollArea.Root>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -12,9 +12,9 @@ const ToggleGroupItem: FC<{
|
||||
data-selected={selected}
|
||||
asChild
|
||||
onClick={onClick}
|
||||
className="hover:bg-indigo-600 text-white data-[selected=true]:bg-indigo-700
|
||||
className="hover:bg-primary/30 text-main data-[selected=true]:bg-primary/60
|
||||
data-[selected=true]:text-indigo-200 flex h-6 w-6
|
||||
items-center justify-center bg-slate-800 text-sm leading-4
|
||||
items-center justify-center bg-neutral text-sm leading-4
|
||||
first:rounded-l last:rounded-r focus:z-10 focus:shadow-[0_0_0_2px] focus:shadow-black
|
||||
focus:outline-none transition-colors"
|
||||
value="left"
|
||||
@@ -29,7 +29,7 @@ const ToggleGroupItem: FC<{
|
||||
|
||||
const ToggleGroup: FC<{ children: ReactNode }> = ({ children }) => (
|
||||
<ToggleGroupComponents.Root
|
||||
className="inline-flex my-auto bg-slate-800 h-fit rounded shadow-[0_2px_10px] shadow-black space-x-px"
|
||||
className="inline-flex my-auto bg-neutral-accent h-fit rounded shadow-[0_2px_10px] shadow-black space-x-px"
|
||||
type="single"
|
||||
defaultValue="center"
|
||||
aria-label="Text alignment"
|
||||
|
||||
@@ -25,9 +25,9 @@ const ToolBarButton: FC<{ children: ReactNode; onClick?: () => void }> = ({
|
||||
onClick={onClick}
|
||||
onMouseOver={() => !didHover && setDidHover(true)}
|
||||
asChild
|
||||
className="text-white p-[10px] bg-gray-900 flex-shrink-0 flex-grow-0
|
||||
className="text-main p-[10px] bg-neutral flex-shrink-0 flex-grow-0
|
||||
basis-auto w-[40px] h-[40px] rounded inline-flex text-[13px] leading-none
|
||||
items-center justify-center outline-none hover:bg-indigo-900
|
||||
items-center justify-center outline-none hover:bg-primary/50
|
||||
transition-colors
|
||||
focus:relative focus:shadow-[0_0_0_2px] focus:shadow-indigo"
|
||||
>
|
||||
@@ -52,7 +52,7 @@ const ToolBar = () => {
|
||||
return (
|
||||
<Toolbar.Root
|
||||
asChild
|
||||
className="bg-gray-800 flex flex-col gap-1 p-1 h-full"
|
||||
className="bg-neutral-accent flex flex-col gap-1 p-1 h-full"
|
||||
orientation="vertical"
|
||||
>
|
||||
<motion.div
|
||||
|
||||
Reference in New Issue
Block a user