aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/MVPlayer/index.tsx
blob: 186f6e97564bb6948c79ae6f2214b0726e976039 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import React from "react";
import * as Styled from "./index.styled";

interface Props {
  currentTry: number;
  date: string;
}

const MV_CDN_URL = import.meta.env.VITE_CDN_URL || "";

function getRevealedCount(currentTry: number): number {
  if (currentTry >= 5) return 3;
  if (currentTry >= 2) return 2;
  return 1;
}

export function MVPlayer({ currentTry, date }: Props) {
  const revealed = getRevealedCount(currentTry);
  const [errored, setErrored] = React.useState<Set<number>>(new Set());

  const [activeImage, setActiveImage] = React.useState<string | null>(null);

  const markError = React.useCallback((index: number) => {
    setErrored((prev) => {
      const next = new Set(prev);
      next.add(index);
      return next;
    });
  }, []);

  React.useEffect(() => {
    setErrored(new Set());
    setActiveImage(null);
  }, [date]);

  return (
    <Styled.Frame>
      <Styled.Images>
        {Array.from({ length: 3 }, (_, i) => {
          const index = i + 1;
          const isRevealed = index <= revealed;
          const src = `${MV_CDN_URL}/k-heardle-mvs/${date}/${index}.jpg`;
          const hasError = errored.has(index);

          return (
            <Styled.ImageSlot key={index} $revealed={isRevealed}>
              {isRevealed && !hasError ? (
                <img
                  src={src}
                  alt={`MV frame ${index}`}
                  onError={() => markError(index)}
                  onClick={() => setActiveImage(src)}
                  style={{ cursor: "zoom-in" }}
                />
              ) : isRevealed && hasError ? (
                <Styled.Placeholder>
                  Frame {index} not available yet.
                </Styled.Placeholder>
              ) : (
                <Styled.Placeholder>?</Styled.Placeholder>
              )}
            </Styled.ImageSlot>
          );
        })}
      </Styled.Images>

      <Styled.Hint>
        {revealed < 3
          ? `More frames unlock as you guess. (${revealed}/3 revealed)`
          : "All frames revealed."}
      </Styled.Hint>

      {activeImage && (
        <Styled.Overlay onClick={() => setActiveImage(null)}>
          <Styled.LightboxImage
            src={activeImage}
            alt="Full size MV frame"
            onClick={(e) => e.stopPropagation()}
          />
        </Styled.Overlay>
      )}
    </Styled.Frame>
  );
}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage