forked from pinks/eris
1
0
Fork 0
nyx/ui/Counter.tsx

90 lines
2.5 KiB
TypeScript
Raw Permalink Normal View History

2023-10-10 16:21:25 +00:00
import React from "react";
2023-10-21 10:40:42 +00:00
import { cx } from "twind/core";
2023-10-10 16:21:25 +00:00
2023-10-19 21:37:03 +00:00
function CounterDigit(props: { value: number; transitionDurationMs?: number | undefined }) {
2023-10-13 11:47:57 +00:00
const { value, transitionDurationMs = 1500 } = props;
2023-10-10 16:21:25 +00:00
const rads = -(Math.floor(value) % 1_000_000) * 2 * Math.PI * 0.1;
return (
2023-10-13 11:47:57 +00:00
<span className="w-[1em] relative">
2023-10-10 16:21:25 +00:00
{Array.from({ length: 10 }).map((_, i) => (
<span
key={i}
className="absolute inset-0 grid place-items-center transition-transform duration-1000 ease-in-out [backface-visibility:hidden]"
style={{
transform: `rotateX(${rads + i * 2 * Math.PI * 0.1}rad)`,
2023-10-13 11:47:57 +00:00
transformOrigin: `center center 2em`,
2023-10-10 16:21:25 +00:00
transitionDuration: `${transitionDurationMs}ms`,
}}
>
{i}
</span>
))}
</span>
);
}
2023-10-13 11:47:57 +00:00
const Spacer = () =>
<span className="border-l-1 mx-[0.1em] border-zinc-200 dark:border-zinc-700" />;
const CounterText = (props: { children: React.ReactNode }) => (
<span className="self-center px-[0.1em]">
{props.children}
</span>
);
2023-10-10 16:21:25 +00:00
export function Counter(props: {
value: number;
digits: number;
2023-10-19 21:37:03 +00:00
fractionDigits?: number | undefined;
transitionDurationMs?: number | undefined;
className?: string | undefined;
postfix?: string | undefined;
2023-10-10 16:21:25 +00:00
}) {
2023-10-13 11:47:57 +00:00
const { value, digits, fractionDigits = 0, transitionDurationMs, className, postfix } = props;
2023-10-10 16:21:25 +00:00
return (
<span
className={cx(
2023-10-13 11:47:57 +00:00
"inline-flex h-[1.5em] items-stretch border-1 border-zinc-300 dark:border-zinc-700 shadow-inner rounded-md overflow-hidden",
2023-10-10 16:21:25 +00:00
className,
)}
>
{Array.from({ length: digits })
.flatMap((_, i) => [
2023-10-13 11:47:57 +00:00
i > 0 && i % 3 === 0 ? <Spacer key={`spacer${i}`} /> : null,
2023-10-10 16:21:25 +00:00
<CounterDigit
key={`digit${i}`}
value={value / 10 ** i}
transitionDurationMs={transitionDurationMs}
/>,
])
.reverse()}
2023-10-13 11:47:57 +00:00
{fractionDigits > 0 && (
<>
<Spacer />
<CounterText>.</CounterText>
<Spacer />
{Array.from({ length: fractionDigits })
.flatMap((_, i) => [
i > 0 && i % 3 === 0 ? <Spacer key={`fractionSpacer${i}`} /> : null,
<CounterDigit
key={`fractionDigit${i}`}
value={value * 10 ** (i + 1)}
transitionDurationMs={transitionDurationMs}
/>,
])}
</>
)}
{postfix && (
<>
<Spacer />
<CounterText>{postfix}</CounterText>
</>
)}
2023-10-10 16:21:25 +00:00
</span>
);
}