File size: 2,732 Bytes
3bc016b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
85
86
87
88
import { motion } from "framer-motion";
import { createContext, useContext, type ReactNode } from "react";
import { useTheme } from "../ThemeContext";
import { MONO } from "../theme";
import { spring } from "./primitives";

// Deck sets this to the current slide's auto-derived section number, so
// slides no longer hard-code their kicker index (insert freely, numbers fix
// themselves). Falls back to the `index` prop if no context is present.
export const SectionNumberContext = createContext<number | null>(null);

// Consistent deck chrome for content slides: kicker (NN / SECTION),
// big title, accent rule, and a small page index in the corner.
export function SlideShell({
  index,
  kicker,
  title,
  children,
  titleSize = 46,
}: {
  index?: number; // optional manual override; normally auto-numbered
  kicker: string; // e.g. "TRADITIONAL RL"
  title: ReactNode;
  children?: ReactNode;
  titleSize?: number; // override the (compact) default when a slide needs it
}) {
  const { T } = useTheme();
  const ctxNo = useContext(SectionNumberContext);
  const idx = String(ctxNo ?? index ?? 0).padStart(2, "0");

  return (
    <div style={{ position: "absolute", inset: 0 }}>
      {/* Header — kept compact so content gets the room */}
      <div style={{ position: "absolute", top: 52, left: 96, right: 96 }}>
        <motion.div
          initial={{ opacity: 0, x: -14 }}
          animate={{ opacity: 1, x: 0 }}
          transition={{ ...spring, delay: 0.05 }}
          style={{
            fontSize: 17,
            fontWeight: 700,
            letterSpacing: 5,
            textTransform: "uppercase",
            marginBottom: 10,
            fontFamily: MONO,
          }}
        >
          <span style={{ color: T.emerald }}>{idx}</span>
          <span style={{ color: T.textDim }}> &nbsp;/&nbsp; {kicker}</span>
        </motion.div>
        <motion.div
          initial={{ opacity: 0, y: 14 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ ...spring, delay: 0.12 }}
          style={{
            fontSize: titleSize,
            fontWeight: 800,
            color: T.white,
            letterSpacing: -1,
            lineHeight: 1.06,
            maxWidth: 1040,
          }}
        >
          {title}
        </motion.div>
      </div>

      {/* Content region — slides position their own content below the header */}
      {children}

      {/* Footer — just a small page index in the corner */}
      <div
        style={{
          position: "absolute",
          bottom: 44,
          right: 96,
          fontFamily: MONO,
          fontSize: 18,
          color: T.textDim,
          letterSpacing: 2,
        }}
      >
        {idx}
      </div>
    </div>
  );
}