File size: 2,874 Bytes
97289d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
 * Companion display card — shown by /buddy (no args).
 * Mirrors official vc8 component: bordered box with sprite, stats, last reaction.
 */
import React from 'react';
import { Box, Text } from '../ink.js';
import { useInput } from '../ink.js';
import { renderSprite } from './sprites.js';
import { RARITY_COLORS, RARITY_STARS, STAT_NAMES, type Companion } from './types.js';

const CARD_WIDTH = 40;
const CARD_PADDING_X = 2;

function StatBar({ name, value }: { name: string; value: number }) {
  const clamped = Math.max(0, Math.min(100, value));
  const filled = Math.round(clamped / 10);
  const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(10 - filled);
  return (
    <Text>
      {name.padEnd(10)} {bar} {String(value).padStart(3)}
    </Text>
  );
}

export function CompanionCard({
  companion,
  lastReaction,
  onDone,
}: {
  companion: Companion;
  lastReaction?: string;
  onDone?: (result?: string, options?: { display?: string }) => void;
}) {
  const color = RARITY_COLORS[companion.rarity];
  const stars = RARITY_STARS[companion.rarity];
  const sprite = renderSprite(companion, 0);

  // Press any key to dismiss
  useInput(
    () => {
      onDone?.(undefined, { display: 'skip' });
    },
    { isActive: onDone !== undefined },
  );

  return (
    <Box
      flexDirection="column"
      borderStyle="round"
      borderColor={color}
      paddingX={CARD_PADDING_X}
      paddingY={1}
      width={CARD_WIDTH}
      flexShrink={0}
    >
      {/* Header: rarity + species */}
      <Box justifyContent="space-between">
        <Text bold color={color}>
          {stars} {companion.rarity.toUpperCase()}
        </Text>
        <Text color={color}>{companion.species.toUpperCase()}</Text>
      </Box>

      {/* Shiny indicator */}
      {companion.shiny && (
        <Text color="warning" bold>
          {'\u2728'} SHINY {'\u2728'}
        </Text>
      )}

      {/* Sprite */}
      <Box flexDirection="column" marginY={1}>
        {sprite.map((line, i) => (
          <Text key={i} color={color}>
            {line}
          </Text>
        ))}
      </Box>

      {/* Name */}
      <Text bold>{companion.name}</Text>

      {/* Personality */}
      <Box marginY={1}>
        <Text dimColor italic>
          &quot;{companion.personality}&quot;
        </Text>
      </Box>

      {/* Stats */}
      <Box flexDirection="column">
        {STAT_NAMES.map(name => (
          <StatBar key={name} name={name} value={companion.stats[name] ?? 0} />
        ))}
      </Box>

      {/* Last reaction */}
      {lastReaction && (
        <Box flexDirection="column" marginTop={1}>
          <Text dimColor>last said</Text>
          <Box borderStyle="round" borderColor="inactive" paddingX={1}>
            <Text dimColor italic>
              {lastReaction}
            </Text>
          </Box>
        </Box>
      )}
    </Box>
  );
}