shimmer.tsx 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. import { RGBA } from "@opentui/core"
  2. import { useTimeline } from "@opentui/solid"
  3. import { createMemo, createSignal } from "solid-js"
  4. export type ShimmerProps = {
  5. text: string
  6. color: RGBA
  7. }
  8. const DURATION = 2_500
  9. export function Shimmer(props: ShimmerProps) {
  10. const timeline = useTimeline({
  11. duration: DURATION,
  12. loop: true,
  13. })
  14. const characters = props.text.split("")
  15. const color = props.color
  16. const shimmerSignals = characters.map((_, i) => {
  17. const [shimmer, setShimmer] = createSignal(0.4)
  18. const target = {
  19. shimmer: shimmer(),
  20. setShimmer,
  21. }
  22. timeline!.add(
  23. target,
  24. {
  25. shimmer: 1,
  26. duration: DURATION / (props.text.length + 1),
  27. ease: "linear",
  28. alternate: true,
  29. loop: 2,
  30. onUpdate: () => {
  31. target.setShimmer(target.shimmer)
  32. },
  33. },
  34. (i * (DURATION / (props.text.length + 1))) / 2,
  35. )
  36. return shimmer
  37. })
  38. return (
  39. <text>
  40. {(() => {
  41. return characters.map((ch, i) => {
  42. const shimmer = shimmerSignals[i]
  43. const fg = RGBA.fromInts(color.r * 255, color.g * 255, color.b * 255, shimmer() * 255)
  44. return <span style={{ fg }}>{ch}</span>
  45. })
  46. })()}
  47. </text>
  48. )
  49. }