mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat(videos): add ToolGrid and BeforeAfter components
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
import type React from "react";
|
||||||
|
import { interpolate, useCurrentFrame } from "remotion";
|
||||||
|
import { COLOR } from "@/lib/colors";
|
||||||
|
import { EASE } from "@/lib/motion";
|
||||||
|
|
||||||
|
export const BeforeAfter: React.FC<{
|
||||||
|
before: React.ReactNode;
|
||||||
|
after: React.ReactNode;
|
||||||
|
scanStartFrame: number;
|
||||||
|
scanDuration: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
}> = ({ before, after, scanStartFrame, scanDuration, width, height, style }) => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
|
||||||
|
const scanProgress = interpolate(
|
||||||
|
frame,
|
||||||
|
[scanStartFrame, scanStartFrame + scanDuration],
|
||||||
|
[0, 100],
|
||||||
|
{ extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: EASE.smooth },
|
||||||
|
);
|
||||||
|
|
||||||
|
const scanX = (scanProgress / 100) * width;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
overflow: "hidden",
|
||||||
|
borderRadius: 8,
|
||||||
|
...style,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ position: "absolute", inset: 0 }}>{before}</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
inset: 0,
|
||||||
|
clipPath: `inset(0 ${100 - scanProgress}% 0 0)`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{after}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{scanProgress > 0 && scanProgress < 100 && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "absolute",
|
||||||
|
left: scanX,
|
||||||
|
top: 0,
|
||||||
|
width: 2,
|
||||||
|
height: "100%",
|
||||||
|
backgroundColor: COLOR.accent,
|
||||||
|
boxShadow: `0 0 20px ${COLOR.accent}80`,
|
||||||
|
zIndex: 10,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import type React from "react";
|
||||||
|
import { spring, useCurrentFrame, useVideoConfig } from "remotion";
|
||||||
|
import { ToolPill } from "@/components/ToolPill";
|
||||||
|
import { CATEGORY_ORDER } from "@/lib/colors";
|
||||||
|
import { SPRING, TIMING } from "@/lib/motion";
|
||||||
|
import { getToolsByCategory, TOOLS } from "@/lib/tools";
|
||||||
|
|
||||||
|
export const ToolGrid: React.FC<{
|
||||||
|
startFrame: number;
|
||||||
|
cellWidth?: number;
|
||||||
|
cellHeight?: number;
|
||||||
|
gap?: number;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
}> = ({ startFrame, cellWidth = 140, cellHeight = 32, gap = 6, style }) => {
|
||||||
|
const frame = useCurrentFrame();
|
||||||
|
const { fps } = useVideoConfig();
|
||||||
|
|
||||||
|
let globalIndex = 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
gap: gap * 2,
|
||||||
|
...style,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{CATEGORY_ORDER.map((cat) => {
|
||||||
|
const tools = getToolsByCategory(cat);
|
||||||
|
return (
|
||||||
|
<div key={cat} style={{ display: "flex", flexDirection: "column", gap }}>
|
||||||
|
{tools.map((tool) => {
|
||||||
|
const i = globalIndex++;
|
||||||
|
const enterDelay = startFrame + i * TIMING.staggerFrames;
|
||||||
|
const s = spring({
|
||||||
|
frame: frame - enterDelay,
|
||||||
|
fps,
|
||||||
|
config: SPRING.settle,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={tool.name}
|
||||||
|
style={{
|
||||||
|
opacity: s,
|
||||||
|
transform: `translateX(${(1 - s) * 100}px) scale(${0.8 + s * 0.2})`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ToolPill
|
||||||
|
name={tool.name}
|
||||||
|
category={tool.category}
|
||||||
|
style={{ width: cellWidth, fontSize: 11, padding: "3px 8px" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user