brainrot-cli 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AchievementNotification.d.ts.map +1 -1
- package/dist/AchievementNotification.js.map +1 -1
- package/dist/AppNew.d.ts +11 -0
- package/dist/AppNew.d.ts.map +1 -0
- package/dist/AppNew.js +437 -0
- package/dist/AppNew.js.map +1 -0
- package/dist/AttentionOverlay.d.ts +28 -0
- package/dist/AttentionOverlay.d.ts.map +1 -0
- package/dist/AttentionOverlay.js +92 -0
- package/dist/AttentionOverlay.js.map +1 -0
- package/dist/ClaudeChat.d.ts +38 -0
- package/dist/ClaudeChat.d.ts.map +1 -0
- package/dist/ClaudeChat.js +81 -0
- package/dist/ClaudeChat.js.map +1 -0
- package/dist/DynamicInterviewFlow.d.ts +66 -0
- package/dist/DynamicInterviewFlow.d.ts.map +1 -0
- package/dist/DynamicInterviewFlow.js +352 -0
- package/dist/DynamicInterviewFlow.js.map +1 -0
- package/dist/FeatureInput.d.ts +20 -0
- package/dist/FeatureInput.d.ts.map +1 -0
- package/dist/FeatureInput.js +66 -0
- package/dist/FeatureInput.js.map +1 -0
- package/dist/FeaturePromptScreen.d.ts +24 -0
- package/dist/FeaturePromptScreen.d.ts.map +1 -0
- package/dist/FeaturePromptScreen.js +117 -0
- package/dist/FeaturePromptScreen.js.map +1 -0
- package/dist/GameSelectScreen.d.ts +24 -0
- package/dist/GameSelectScreen.d.ts.map +1 -0
- package/dist/GameSelectScreen.js +78 -0
- package/dist/GameSelectScreen.js.map +1 -0
- package/dist/GameSelector.d.ts +9 -1
- package/dist/GameSelector.d.ts.map +1 -1
- package/dist/GameSelector.js +116 -19
- package/dist/GameSelector.js.map +1 -1
- package/dist/GameSelectorOverlay.d.ts +21 -0
- package/dist/GameSelectorOverlay.d.ts.map +1 -0
- package/dist/GameSelectorOverlay.js +98 -0
- package/dist/GameSelectorOverlay.js.map +1 -0
- package/dist/HelpOverlay.d.ts.map +1 -1
- package/dist/HelpOverlay.js +5 -2
- package/dist/HelpOverlay.js.map +1 -1
- package/dist/InterviewQuestion.d.ts +36 -0
- package/dist/InterviewQuestion.d.ts.map +1 -0
- package/dist/InterviewQuestion.js +148 -0
- package/dist/InterviewQuestion.js.map +1 -0
- package/dist/Layout.d.ts +1 -1
- package/dist/Layout.d.ts.map +1 -1
- package/dist/Layout.js +4 -4
- package/dist/Layout.js.map +1 -1
- package/dist/LogViewer.d.ts.map +1 -1
- package/dist/LogViewer.js +2 -2
- package/dist/LogViewer.js.map +1 -1
- package/dist/LoopAlertOverlay.d.ts +1 -1
- package/dist/LoopAlertOverlay.d.ts.map +1 -1
- package/dist/LoopAlertOverlay.js +1 -1
- package/dist/LoopAlertOverlay.js.map +1 -1
- package/dist/LoopComplete.d.ts +42 -0
- package/dist/LoopComplete.d.ts.map +1 -0
- package/dist/LoopComplete.js +69 -0
- package/dist/LoopComplete.js.map +1 -0
- package/dist/LoopManagementPanel.d.ts.map +1 -1
- package/dist/LoopManagementPanel.js.map +1 -1
- package/dist/OnboardingTutorial.d.ts +23 -0
- package/dist/OnboardingTutorial.d.ts.map +1 -0
- package/dist/OnboardingTutorial.js +165 -0
- package/dist/OnboardingTutorial.js.map +1 -0
- package/dist/PrdGenerationScreen.d.ts +43 -0
- package/dist/PrdGenerationScreen.d.ts.map +1 -0
- package/dist/PrdGenerationScreen.js +411 -0
- package/dist/PrdGenerationScreen.js.map +1 -0
- package/dist/PrdOverlay.d.ts +29 -0
- package/dist/PrdOverlay.d.ts.map +1 -0
- package/dist/PrdOverlay.js +174 -0
- package/dist/PrdOverlay.js.map +1 -0
- package/dist/PreStartReviewScreen.d.ts +29 -0
- package/dist/PreStartReviewScreen.d.ts.map +1 -0
- package/dist/PreStartReviewScreen.js +161 -0
- package/dist/PreStartReviewScreen.js.map +1 -0
- package/dist/ResumeOverlay.d.ts +26 -0
- package/dist/ResumeOverlay.d.ts.map +1 -0
- package/dist/ResumeOverlay.js +163 -0
- package/dist/ResumeOverlay.js.map +1 -0
- package/dist/ResumePrompt.d.ts +32 -0
- package/dist/ResumePrompt.d.ts.map +1 -0
- package/dist/ResumePrompt.js +65 -0
- package/dist/ResumePrompt.js.map +1 -0
- package/dist/SettingsMenu.d.ts.map +1 -1
- package/dist/SettingsMenu.js +14 -7
- package/dist/SettingsMenu.js.map +1 -1
- package/dist/SetupWizard.d.ts +41 -0
- package/dist/SetupWizard.d.ts.map +1 -0
- package/dist/SetupWizard.js +167 -0
- package/dist/SetupWizard.js.map +1 -0
- package/dist/SidePanel.d.ts +26 -0
- package/dist/SidePanel.d.ts.map +1 -0
- package/dist/SidePanel.js +90 -0
- package/dist/SidePanel.js.map +1 -0
- package/dist/SplitPane.d.ts.map +1 -1
- package/dist/SplitPane.js +6 -2
- package/dist/SplitPane.js.map +1 -1
- package/dist/StatsMenu.d.ts.map +1 -1
- package/dist/StatsMenu.js +24 -6
- package/dist/StatsMenu.js.map +1 -1
- package/dist/StatusBar.d.ts +45 -2
- package/dist/StatusBar.d.ts.map +1 -1
- package/dist/StatusBar.js +193 -23
- package/dist/StatusBar.js.map +1 -1
- package/dist/StatusBarMinimal.d.ts +26 -0
- package/dist/StatusBarMinimal.d.ts.map +1 -0
- package/dist/StatusBarMinimal.js +111 -0
- package/dist/StatusBarMinimal.js.map +1 -0
- package/dist/TaskBreakdownScreen.d.ts +27 -0
- package/dist/TaskBreakdownScreen.d.ts.map +1 -0
- package/dist/TaskBreakdownScreen.js +96 -0
- package/dist/TaskBreakdownScreen.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/games/MinesweeperGame.d.ts +1 -1
- package/dist/games/MinesweeperGame.d.ts.map +1 -1
- package/dist/games/MinesweeperGame.js +30 -10
- package/dist/games/MinesweeperGame.js.map +1 -1
- package/dist/games/PongGame.d.ts +1 -1
- package/dist/games/PongGame.d.ts.map +1 -1
- package/dist/games/PongGame.js +7 -2
- package/dist/games/PongGame.js.map +1 -1
- package/dist/games/SnakeGame.d.ts +1 -1
- package/dist/games/SnakeGame.d.ts.map +1 -1
- package/dist/games/SnakeGame.js +12 -4
- package/dist/games/SnakeGame.js.map +1 -1
- package/dist/games/TetrisGame.d.ts +1 -1
- package/dist/games/TetrisGame.d.ts.map +1 -1
- package/dist/games/TetrisGame.js +22 -5
- package/dist/games/TetrisGame.js.map +1 -1
- package/dist/high-scores.d.ts.map +1 -1
- package/dist/high-scores.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -236
- package/dist/index.js.map +1 -1
- package/dist/loop-state.d.ts +137 -0
- package/dist/loop-state.d.ts.map +1 -0
- package/dist/loop-state.js +228 -0
- package/dist/loop-state.js.map +1 -0
- package/dist/ralph-loop-parser.d.ts.map +1 -1
- package/dist/ralph-loop-parser.js +4 -2
- package/dist/ralph-loop-parser.js.map +1 -1
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js.map +1 -1
- package/dist/styled-components.d.ts +1 -1
- package/dist/styled-components.d.ts.map +1 -1
- package/dist/styled-components.js +5 -3
- package/dist/styled-components.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +15 -2
- package/dist/theme.js.map +1 -1
- package/dist/themes.d.ts.map +1 -1
- package/dist/themes.js.map +1 -1
- package/dist/use-claude-code.d.ts.map +1 -1
- package/dist/use-claude-code.js +7 -1
- package/dist/use-claude-code.js.map +1 -1
- package/dist/use-config.d.ts.map +1 -1
- package/dist/use-config.js.map +1 -1
- package/dist/use-loop-state.d.ts +55 -0
- package/dist/use-loop-state.d.ts.map +1 -0
- package/dist/use-loop-state.js +208 -0
- package/dist/use-loop-state.js.map +1 -0
- package/dist/use-stats.d.ts.map +1 -1
- package/dist/use-stats.js.map +1 -1
- package/dist/useTheme.d.ts.map +1 -1
- package/dist/useTheme.js.map +1 -1
- package/package.json +3 -2
- package/dist/__tests__/ralph-loop-parser.test.d.ts +0 -2
- package/dist/__tests__/ralph-loop-parser.test.d.ts.map +0 -1
- package/dist/__tests__/ralph-loop-parser.test.js +0 -143
- package/dist/__tests__/ralph-loop-parser.test.js.map +0 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Feature Input Screen
|
|
4
|
+
*
|
|
5
|
+
* Clean, minimal first screen that asks the user for a feature description.
|
|
6
|
+
* This is the entry point for the new simplified UI flow.
|
|
7
|
+
*/
|
|
8
|
+
import { Box, Text, useInput } from "ink";
|
|
9
|
+
import { useState, useCallback, useMemo } from "react";
|
|
10
|
+
import { useThemeColors } from "./useTheme.js";
|
|
11
|
+
import { navIcons } from "./theme.js";
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// CONSTANTS
|
|
14
|
+
// ============================================================================
|
|
15
|
+
const MIN_CHARS = 10;
|
|
16
|
+
const EXAMPLES = [
|
|
17
|
+
"Create a REST API for user management",
|
|
18
|
+
"Fix the login bug on mobile",
|
|
19
|
+
"Add unit tests for the payment module",
|
|
20
|
+
];
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// COMPONENT
|
|
23
|
+
// ============================================================================
|
|
24
|
+
export function FeatureInput({ onSubmit, hasFocus, dimensions, }) {
|
|
25
|
+
const [inputValue, setInputValue] = useState("");
|
|
26
|
+
const [showError, setShowError] = useState(false);
|
|
27
|
+
const colors = useThemeColors();
|
|
28
|
+
const isValid = inputValue.length >= MIN_CHARS;
|
|
29
|
+
const handleSubmit = useCallback(() => {
|
|
30
|
+
if (isValid) {
|
|
31
|
+
onSubmit(inputValue.trim());
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
setShowError(true);
|
|
35
|
+
}
|
|
36
|
+
}, [inputValue, isValid, onSubmit]);
|
|
37
|
+
// Handle keyboard input
|
|
38
|
+
useInput((input, key) => {
|
|
39
|
+
if (!hasFocus)
|
|
40
|
+
return;
|
|
41
|
+
// Enter to submit
|
|
42
|
+
if (key.return) {
|
|
43
|
+
handleSubmit();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Backspace/Delete to remove characters
|
|
47
|
+
if (key.backspace || key.delete) {
|
|
48
|
+
setInputValue((prev) => prev.slice(0, -1));
|
|
49
|
+
setShowError(false);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Printable characters (ignore control keys)
|
|
53
|
+
if (input && !key.ctrl && !key.meta && !key.escape) {
|
|
54
|
+
setInputValue((prev) => prev + input);
|
|
55
|
+
setShowError(false);
|
|
56
|
+
}
|
|
57
|
+
}, { isActive: hasFocus });
|
|
58
|
+
// Calculate input box width
|
|
59
|
+
const inputWidth = useMemo(() => {
|
|
60
|
+
return Math.min(55, dimensions.width - 8);
|
|
61
|
+
}, [dimensions.width]);
|
|
62
|
+
const cursorChar = "\u258c";
|
|
63
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsx(Box, { marginBottom: 2, children: _jsx(Text, { bold: true, color: colors.primary, children: "BRAINROT" }) }), _jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, paddingX: 2, paddingY: 1, width: inputWidth, children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: colors.text, children: "What do you want to build?" }) }), _jsx(Box, { borderStyle: "single", borderColor: hasFocus ? colors.borderFocus : colors.border, paddingX: 1, minHeight: 3, children: inputValue ? (_jsxs(Text, { children: [_jsx(Text, { color: colors.text, children: inputValue }), _jsx(Text, { color: colors.primary, children: cursorChar })] })) : (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, italic: true, children: "Add dark mode support to the app" }), _jsx(Text, { color: colors.primary, children: cursorChar })] })) }), showError && !isValid && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: colors.error, children: [navIcons.arrowRight, " Minimum ", MIN_CHARS, " characters required"] }) }))] }), _jsxs(Box, { flexDirection: "column", marginTop: 2, paddingX: 2, children: [_jsx(Text, { dimColor: true, children: "Examples:" }), EXAMPLES.map((example, i) => (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: [navIcons.bullet, " ", example] }) }, i)))] }), _jsx(Box, { position: "absolute", marginTop: dimensions.height - 2, borderStyle: "single", borderColor: colors.border, paddingX: 2, width: dimensions.width - 4, children: _jsxs(Text, { dimColor: true, children: [_jsx(Text, { color: colors.primary, children: "Enter" }), ": Submit |", " ", _jsx(Text, { color: colors.primary, children: "Ctrl+C" }), ": Quit |", " ", _jsx(Text, { color: colors.primary, children: "?" }), ": Help"] }) })] }));
|
|
64
|
+
}
|
|
65
|
+
export default FeatureInput;
|
|
66
|
+
//# sourceMappingURL=FeatureInput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeatureInput.js","sourceRoot":"","sources":["../src/FeatureInput.tsx"],"names":[],"mappings":";AAAA;;;;;GAKG;AAEH,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAetC,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB,MAAM,QAAQ,GAAG;IACf,uCAAuC;IACvC,6BAA6B;IAC7B,uCAAuC;CACxC,CAAC;AAEF,+EAA+E;AAC/E,YAAY;AACZ,+EAA+E;AAE/E,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,QAAQ,EACR,UAAU,GACQ;IAClB,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,cAAc,EAAE,CAAC;IAEhC,MAAM,OAAO,GAAG,UAAU,CAAC,MAAM,IAAI,SAAS,CAAC;IAE/C,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,IAAI,OAAO,EAAE,CAAC;YACZ,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAEpC,wBAAwB;IACxB,QAAQ,CACN,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACb,IAAI,CAAC,QAAQ;YAAE,OAAO;QAEtB,kBAAkB;QAClB,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YACf,YAAY,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QAED,wCAAwC;QACxC,IAAI,GAAG,CAAC,SAAS,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;YAChC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QAED,6CAA6C;QAC7C,IAAI,KAAK,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;YACnD,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,KAAK,CAAC,CAAC;YACtC,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,EACD,EAAE,QAAQ,EAAE,QAAQ,EAAE,CACvB,CAAC;IAEF,4BAA4B;IAC5B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE;QAC9B,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAEvB,MAAM,UAAU,GAAG,QAAQ,CAAC;IAE5B,OAAO,CACL,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,UAAU,EAAC,QAAQ,EACnB,cAAc,EAAC,QAAQ,EACvB,KAAK,EAAC,MAAM,EACZ,MAAM,EAAC,MAAM,aAGb,KAAC,GAAG,IAAC,YAAY,EAAE,CAAC,YAClB,KAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAE,MAAM,CAAC,OAAO,yBAEzB,GACH,EAGN,MAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,WAAW,EAAC,OAAO,EACnB,WAAW,EAAE,MAAM,CAAC,MAAM,EAC1B,QAAQ,EAAE,CAAC,EACX,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,UAAU,aAGjB,KAAC,GAAG,IAAC,YAAY,EAAE,CAAC,YAClB,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,IAAI,2CAAmC,GACvD,EAGN,KAAC,GAAG,IACF,WAAW,EAAC,QAAQ,EACpB,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAC1D,QAAQ,EAAE,CAAC,EACX,SAAS,EAAE,CAAC,YAEX,UAAU,CAAC,CAAC,CAAC,CACZ,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,IAAI,YAAG,UAAU,GAAQ,EAC7C,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,OAAO,YAAG,UAAU,GAAQ,IAC3C,CACR,CAAC,CAAC,CAAC,CACF,MAAC,IAAI,eACH,KAAC,IAAI,IAAC,QAAQ,QAAC,MAAM,uDAEd,EACP,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,OAAO,YAAG,UAAU,GAAQ,IAC3C,CACR,GACG,EAGL,SAAS,IAAI,CAAC,OAAO,IAAI,CACxB,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,MAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,KAAK,aACtB,QAAQ,CAAC,UAAU,eAAW,SAAS,4BACnC,GACH,CACP,IACG,EAGN,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,aACnD,KAAC,IAAI,IAAC,QAAQ,gCAAiB,EAC9B,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,CAC5B,KAAC,GAAG,IAAS,WAAW,EAAE,CAAC,YACzB,MAAC,IAAI,IAAC,QAAQ,mBACX,QAAQ,CAAC,MAAM,OAAG,OAAO,IACrB,IAHC,CAAC,CAIL,CACP,CAAC,IACE,EAGN,KAAC,GAAG,IACF,QAAQ,EAAC,UAAU,EACnB,SAAS,EAAE,UAAU,CAAC,MAAM,GAAG,CAAC,EAChC,WAAW,EAAC,QAAQ,EACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAC1B,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,UAAU,CAAC,KAAK,GAAG,CAAC,YAE3B,MAAC,IAAI,IAAC,QAAQ,mBACZ,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,OAAO,sBAAc,gBAAW,GAAG,EACvD,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,OAAO,uBAAe,cAAS,GAAG,EACtD,KAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,OAAO,kBAAU,cAChC,GACH,IACF,CACP,CAAC;AACJ,CAAC;AAED,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Prompt Screen Component
|
|
3
|
+
*
|
|
4
|
+
* Full-screen modal that asks the user for a feature description.
|
|
5
|
+
* Part of the setup wizard flow after onboarding tutorial.
|
|
6
|
+
*/
|
|
7
|
+
export interface FeaturePromptScreenProps {
|
|
8
|
+
/** Whether the screen is visible */
|
|
9
|
+
isVisible: boolean;
|
|
10
|
+
/** Callback when feature prompt is submitted */
|
|
11
|
+
onComplete: (prompt: string) => void;
|
|
12
|
+
/** Callback when user wants to go back */
|
|
13
|
+
onBack?: () => void;
|
|
14
|
+
/** Whether the component has focus */
|
|
15
|
+
hasFocus: boolean;
|
|
16
|
+
/** Terminal dimensions for centering */
|
|
17
|
+
dimensions?: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function FeaturePromptScreen({ isVisible, onComplete, onBack, hasFocus, dimensions, }: FeaturePromptScreenProps): import("react/jsx-runtime").JSX.Element | null;
|
|
23
|
+
export default FeaturePromptScreen;
|
|
24
|
+
//# sourceMappingURL=FeaturePromptScreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeaturePromptScreen.d.ts","sourceRoot":"","sources":["../src/FeaturePromptScreen.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAWH,MAAM,WAAW,wBAAwB;IACvC,oCAAoC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,gDAAgD;IAChD,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,0CAA0C;IAC1C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,wCAAwC;IACxC,UAAU,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAChD;AA2JD,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,UAAU,EACV,MAAM,EACN,QAAQ,EACR,UAAU,GACX,EAAE,wBAAwB,kDA+H1B;AAED,eAAe,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Feature Prompt Screen Component
|
|
4
|
+
*
|
|
5
|
+
* Full-screen modal that asks the user for a feature description.
|
|
6
|
+
* Part of the setup wizard flow after onboarding tutorial.
|
|
7
|
+
*/
|
|
8
|
+
import { Box, Text, useInput } from "ink";
|
|
9
|
+
import { useState, useCallback, useMemo } from "react";
|
|
10
|
+
import { useThemeColors } from "./useTheme.js";
|
|
11
|
+
import { navIcons, decorChars } from "./theme.js";
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// CONSTANTS
|
|
14
|
+
// ============================================================================
|
|
15
|
+
const MIN_CHARS = 10;
|
|
16
|
+
const PLACEHOLDER_EXAMPLES = [
|
|
17
|
+
"Build a user authentication system with JWT",
|
|
18
|
+
"Create a REST API for task management",
|
|
19
|
+
"Implement a real-time chat feature",
|
|
20
|
+
"Add dark mode support to the UI",
|
|
21
|
+
];
|
|
22
|
+
function InputDisplay({ value, colors, width }) {
|
|
23
|
+
const displayWidth = Math.max(width - 4, 30);
|
|
24
|
+
const cursorChar = "▌";
|
|
25
|
+
// Show placeholder when empty
|
|
26
|
+
if (!value) {
|
|
27
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { borderStyle: "single", borderColor: colors.borderFocus, paddingX: 1, width: displayWidth, children: [_jsx(Text, { dimColor: true, italic: true, children: PLACEHOLDER_EXAMPLES[0] }), _jsx(Text, { color: colors.primary, children: cursorChar })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, italic: true, children: "Examples:" }) }), PLACEHOLDER_EXAMPLES.slice(1).map((example, i) => (_jsx(Box, { paddingLeft: 2, children: _jsxs(Text, { dimColor: true, children: [navIcons.bullet, " ", example] }) }, i)))] }));
|
|
28
|
+
}
|
|
29
|
+
// Show input with cursor
|
|
30
|
+
// Wrap text if it exceeds display width
|
|
31
|
+
const maxTextWidth = displayWidth - 4; // Account for padding and cursor
|
|
32
|
+
const lines = [];
|
|
33
|
+
let remaining = value;
|
|
34
|
+
while (remaining.length > 0) {
|
|
35
|
+
if (remaining.length <= maxTextWidth) {
|
|
36
|
+
lines.push(remaining);
|
|
37
|
+
remaining = "";
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// Find a good break point (space) or just cut
|
|
41
|
+
const breakPoint = remaining.lastIndexOf(" ", maxTextWidth);
|
|
42
|
+
const cutPoint = breakPoint > maxTextWidth / 2 ? breakPoint : maxTextWidth;
|
|
43
|
+
lines.push(remaining.slice(0, cutPoint));
|
|
44
|
+
remaining = remaining.slice(cutPoint).trimStart();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return (_jsx(Box, { borderStyle: "single", borderColor: colors.borderFocus, paddingX: 1, width: displayWidth, flexDirection: "column", children: lines.map((line, i) => (_jsxs(Box, { children: [_jsx(Text, { color: colors.text, children: line }), i === lines.length - 1 && (_jsx(Text, { color: colors.primary, children: cursorChar }))] }, i))) }));
|
|
48
|
+
}
|
|
49
|
+
function ValidationMessage({ charCount, colors, showError, }) {
|
|
50
|
+
const remaining = MIN_CHARS - charCount;
|
|
51
|
+
const isValid = charCount >= MIN_CHARS;
|
|
52
|
+
return (_jsxs(Box, { marginTop: 1, justifyContent: "space-between", width: "100%", children: [_jsx(Box, { children: showError && !isValid && (_jsxs(Text, { color: colors.error, children: [navIcons.arrowRight, " Minimum ", MIN_CHARS, " characters required"] })) }), _jsx(Box, { children: _jsxs(Text, { color: isValid ? colors.success : colors.textMuted, children: [charCount, " / ", MIN_CHARS, isValid && " ✓", !isValid && ` (${remaining} more)`] }) })] }));
|
|
53
|
+
}
|
|
54
|
+
function NavigationHints({ colors, canSubmit, hasBack }) {
|
|
55
|
+
return (_jsxs(Box, { justifyContent: "center", marginTop: 2, children: [hasBack && _jsx(Text, { color: colors.textMuted, children: "Esc: Go Back | " }), _jsxs(Text, { color: canSubmit ? colors.primary : colors.textMuted, children: ["Enter: ", canSubmit ? "Submit" : "Need more text", " ", navIcons.arrowRight] })] }));
|
|
56
|
+
}
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// MAIN COMPONENT
|
|
59
|
+
// ============================================================================
|
|
60
|
+
export function FeaturePromptScreen({ isVisible, onComplete, onBack, hasFocus, dimensions, }) {
|
|
61
|
+
const [inputValue, setInputValue] = useState("");
|
|
62
|
+
const [showError, setShowError] = useState(false);
|
|
63
|
+
const colors = useThemeColors();
|
|
64
|
+
const isValid = inputValue.length >= MIN_CHARS;
|
|
65
|
+
const handleSubmit = useCallback(() => {
|
|
66
|
+
if (isValid) {
|
|
67
|
+
onComplete(inputValue.trim());
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
setShowError(true);
|
|
71
|
+
}
|
|
72
|
+
}, [inputValue, isValid, onComplete]);
|
|
73
|
+
const handleBack = useCallback(() => {
|
|
74
|
+
if (onBack) {
|
|
75
|
+
onBack();
|
|
76
|
+
}
|
|
77
|
+
}, [onBack]);
|
|
78
|
+
// Handle keyboard input
|
|
79
|
+
useInput((input, key) => {
|
|
80
|
+
if (!hasFocus || !isVisible)
|
|
81
|
+
return;
|
|
82
|
+
// Enter to submit
|
|
83
|
+
if (key.return) {
|
|
84
|
+
handleSubmit();
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
// Escape to go back
|
|
88
|
+
if (key.escape) {
|
|
89
|
+
handleBack();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// Backspace/Delete to remove characters
|
|
93
|
+
if (key.backspace || key.delete) {
|
|
94
|
+
setInputValue((prev) => prev.slice(0, -1));
|
|
95
|
+
setShowError(false);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
// Printable characters (ignore control keys)
|
|
99
|
+
if (input && !key.ctrl && !key.meta) {
|
|
100
|
+
setInputValue((prev) => prev + input);
|
|
101
|
+
setShowError(false);
|
|
102
|
+
}
|
|
103
|
+
}, { isActive: hasFocus && isVisible });
|
|
104
|
+
// Calculate box dimensions
|
|
105
|
+
const boxWidth = useMemo(() => {
|
|
106
|
+
if (dimensions?.width) {
|
|
107
|
+
return Math.min(70, dimensions.width - 4);
|
|
108
|
+
}
|
|
109
|
+
return 70;
|
|
110
|
+
}, [dimensions?.width]);
|
|
111
|
+
if (!isVisible) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsxs(Box, { flexDirection: "column", borderStyle: "double", borderColor: colors.primary, paddingX: 2, paddingY: 1, width: boxWidth, children: [_jsx(Box, { justifyContent: "center", marginBottom: 1, children: _jsxs(Text, { color: colors.secondary, bold: true, children: [decorChars.sparkle, " NEW FEATURE ", decorChars.sparkle] }) }), _jsx(Box, { justifyContent: "center", marginBottom: 2, children: _jsx(Text, { color: colors.primary, bold: true, children: "What feature do you want to build?" }) }), _jsx(Box, { flexDirection: "column", alignItems: "center", children: _jsx(InputDisplay, { value: inputValue, colors: colors, width: boxWidth }) }), _jsx(Box, { paddingX: 2, children: _jsx(ValidationMessage, { charCount: inputValue.length, colors: colors, showError: showError }) }), _jsx(NavigationHints, { colors: colors, canSubmit: isValid, hasBack: !!onBack })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, italic: true, children: "Be specific about what you want to achieve" }) })] }));
|
|
115
|
+
}
|
|
116
|
+
export default FeaturePromptScreen;
|
|
117
|
+
//# sourceMappingURL=FeaturePromptScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeaturePromptScreen.js","sourceRoot":"","sources":["../src/FeaturePromptScreen.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Game Select Screen
|
|
3
|
+
*
|
|
4
|
+
* Full-screen game picker that appears after Claude finishes planning.
|
|
5
|
+
* User selects a game, then the loop starts and they begin playing.
|
|
6
|
+
*/
|
|
7
|
+
export interface GameSelectScreenProps {
|
|
8
|
+
/** Feature being built */
|
|
9
|
+
featureDescription: string;
|
|
10
|
+
/** Number of tasks planned */
|
|
11
|
+
taskCount: number;
|
|
12
|
+
/** Callback when user selects a game and starts the loop */
|
|
13
|
+
onSelectGame: (gameId: string) => void;
|
|
14
|
+
/** Whether the component has focus */
|
|
15
|
+
hasFocus: boolean;
|
|
16
|
+
/** Terminal dimensions */
|
|
17
|
+
dimensions: {
|
|
18
|
+
width: number;
|
|
19
|
+
height: number;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export declare function GameSelectScreen({ featureDescription, taskCount, onSelectGame, hasFocus, dimensions, }: GameSelectScreenProps): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
export default GameSelectScreen;
|
|
24
|
+
//# sourceMappingURL=GameSelectScreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameSelectScreen.d.ts","sourceRoot":"","sources":["../src/GameSelectScreen.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,MAAM,WAAW,qBAAqB;IACpC,0BAA0B;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,sCAAsC;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,0BAA0B;IAC1B,UAAU,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAgDD,wBAAgB,gBAAgB,CAAC,EAC/B,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,QAAQ,EACR,UAAU,GACX,EAAE,qBAAqB,2CAsHvB;AAED,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Game Select Screen
|
|
4
|
+
*
|
|
5
|
+
* Full-screen game picker that appears after Claude finishes planning.
|
|
6
|
+
* User selects a game, then the loop starts and they begin playing.
|
|
7
|
+
*/
|
|
8
|
+
import { Box, Text, useInput } from "ink";
|
|
9
|
+
import { useState, useCallback, useMemo } from "react";
|
|
10
|
+
import { useThemeColors } from "./useTheme.js";
|
|
11
|
+
import { navIcons } from "./theme.js";
|
|
12
|
+
import { getGameList } from "./games/index.js";
|
|
13
|
+
function GameItem({ game, isSelected, colors }) {
|
|
14
|
+
const icon = getGameIcon(game.id);
|
|
15
|
+
return (_jsxs(Box, { flexDirection: "column", paddingY: 0, children: [_jsx(Box, { children: _jsxs(Text, { color: isSelected ? colors.primary : colors.text, bold: isSelected, children: [isSelected ? navIcons.arrowRight : " ", " ", icon, " ", game.name] }) }), _jsx(Box, { paddingLeft: 4, children: _jsx(Text, { dimColor: true, children: game.description }) })] }));
|
|
16
|
+
}
|
|
17
|
+
function getGameIcon(gameId) {
|
|
18
|
+
switch (gameId) {
|
|
19
|
+
case "snake":
|
|
20
|
+
return "\u{1F40D}"; // snake emoji
|
|
21
|
+
case "pong":
|
|
22
|
+
return "\u{1F3D3}"; // ping pong emoji
|
|
23
|
+
case "tetris":
|
|
24
|
+
return "\u{1F9F1}"; // brick emoji
|
|
25
|
+
case "minesweeper":
|
|
26
|
+
return "\u{1F4A3}"; // bomb emoji
|
|
27
|
+
default:
|
|
28
|
+
return "\u{1F3AE}"; // video game emoji
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// MAIN COMPONENT
|
|
33
|
+
// ============================================================================
|
|
34
|
+
export function GameSelectScreen({ featureDescription, taskCount, onSelectGame, hasFocus, dimensions, }) {
|
|
35
|
+
const colors = useThemeColors();
|
|
36
|
+
const games = useMemo(() => getGameList(), []);
|
|
37
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
38
|
+
const handleSelect = useCallback(() => {
|
|
39
|
+
const selectedGame = games[selectedIndex];
|
|
40
|
+
if (selectedGame) {
|
|
41
|
+
onSelectGame(selectedGame.id);
|
|
42
|
+
}
|
|
43
|
+
}, [games, selectedIndex, onSelectGame]);
|
|
44
|
+
// Handle keyboard input
|
|
45
|
+
useInput((input, key) => {
|
|
46
|
+
if (!hasFocus)
|
|
47
|
+
return;
|
|
48
|
+
// Arrow keys or j/k to navigate
|
|
49
|
+
if (key.upArrow || input === "k" || input === "K") {
|
|
50
|
+
setSelectedIndex((prev) => (prev > 0 ? prev - 1 : games.length - 1));
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
if (key.downArrow || input === "j" || input === "J") {
|
|
54
|
+
setSelectedIndex((prev) => (prev < games.length - 1 ? prev + 1 : 0));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Enter or Space to select
|
|
58
|
+
if (key.return || input === " ") {
|
|
59
|
+
handleSelect();
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Number keys for quick selection
|
|
63
|
+
const num = parseInt(input, 10);
|
|
64
|
+
if (num >= 1 && num <= games.length) {
|
|
65
|
+
setSelectedIndex(num - 1);
|
|
66
|
+
handleSelect();
|
|
67
|
+
}
|
|
68
|
+
}, { isActive: hasFocus });
|
|
69
|
+
// Calculate content width
|
|
70
|
+
const contentWidth = useMemo(() => {
|
|
71
|
+
return Math.min(55, dimensions.width - 8);
|
|
72
|
+
}, [dimensions.width]);
|
|
73
|
+
return (_jsxs(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", children: [_jsx(Box, { marginBottom: 1, children: _jsx(Text, { bold: true, color: colors.primary, children: "BRAINROT" }) }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginBottom: 2, children: [_jsx(Text, { color: colors.success, children: "Claude is ready to start working!" }), _jsx(Text, { dimColor: true, children: "Pick a game to play while you wait." })] }), _jsx(Box, { flexDirection: "column", borderStyle: "round", borderColor: colors.border, paddingX: 2, paddingY: 1, width: contentWidth, children: games.map((game, index) => (_jsx(GameItem, { game: game, isSelected: index === selectedIndex, colors: colors }, game.id))) }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: 2, children: [_jsxs(Text, { dimColor: true, children: ["Task: \"", featureDescription.length > 35
|
|
74
|
+
? featureDescription.slice(0, 35) + "..."
|
|
75
|
+
: featureDescription, "\""] }), _jsxs(Text, { dimColor: true, children: [taskCount, " task", taskCount !== 1 ? "s" : "", " planned ", navIcons.bullet, " Ready to start"] })] }), _jsx(Box, { position: "absolute", marginTop: dimensions.height - 2, borderStyle: "single", borderColor: colors.border, paddingX: 2, width: dimensions.width - 4, children: _jsxs(Text, { dimColor: true, children: [_jsx(Text, { color: colors.primary, children: "\u2191\u2193" }), ": Navigate |", " ", _jsx(Text, { color: colors.primary, children: "Enter" }), ": Start Loop & Play |", " ", _jsx(Text, { color: colors.primary, children: "?" }), ": Help"] }) })] }));
|
|
76
|
+
}
|
|
77
|
+
export default GameSelectScreen;
|
|
78
|
+
//# sourceMappingURL=GameSelectScreen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GameSelectScreen.js","sourceRoot":"","sources":["../src/GameSelectScreen.tsx"],"names":[],"mappings":"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"}
|
package/dist/GameSelector.d.ts
CHANGED
|
@@ -16,10 +16,18 @@ export interface GameSelectorProps {
|
|
|
16
16
|
onSelectGame: (gameId: string) => void;
|
|
17
17
|
/** Callback when stats menu is requested */
|
|
18
18
|
onOpenStats?: () => void;
|
|
19
|
+
/** Whether games are enabled (unlocked after loop start) */
|
|
20
|
+
gamesEnabled?: boolean;
|
|
21
|
+
/** Whether a loop is currently active */
|
|
22
|
+
hasActiveLoop?: boolean;
|
|
23
|
+
/** Callback when Start New Loop is selected */
|
|
24
|
+
onStartNewLoop?: () => void;
|
|
25
|
+
/** Callback when View Current Loop is selected */
|
|
26
|
+
onViewCurrentLoop?: () => void;
|
|
19
27
|
}
|
|
20
28
|
/**
|
|
21
29
|
* Game selector menu component
|
|
22
30
|
*/
|
|
23
|
-
export declare function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, }: GameSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, gamesEnabled, hasActiveLoop, onStartNewLoop, onViewCurrentLoop, }: GameSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
24
32
|
export default GameSelector;
|
|
25
33
|
//# sourceMappingURL=GameSelector.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GameSelector.d.ts","sourceRoot":"","sources":["../src/GameSelector.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKhE,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,2BAA2B;IAC3B,UAAU,EAAE,cAAc,CAAC;IAC3B,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"GameSelector.d.ts","sourceRoot":"","sources":["../src/GameSelector.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAKhE,MAAM,WAAW,iBAAiB;IAChC,qCAAqC;IACrC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,EAAE,OAAO,CAAC;IAClB,2BAA2B;IAC3B,UAAU,EAAE,cAAc,CAAC;IAC3B,uCAAuC;IACvC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,yCAAyC;IACzC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,kDAAkD;IAClD,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;CAChC;AAuLD;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAmB,EACnB,aAAqB,EACrB,cAAc,EACd,iBAAiB,GAClB,EAAE,iBAAiB,2CAsMnB;AAED,eAAe,YAAY,CAAC"}
|
package/dist/GameSelector.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* GameSelector Component
|
|
4
4
|
*
|
|
@@ -10,13 +10,26 @@ import { useState, useCallback, useEffect } from "react";
|
|
|
10
10
|
import { navIcons } from "./theme.js";
|
|
11
11
|
import { useThemeColors } from "./useTheme.js";
|
|
12
12
|
import { getAchievementCount } from "./stats.js";
|
|
13
|
-
function GameCard({ game, isSelected, isHighlighted, dimensions }) {
|
|
13
|
+
function GameCard({ game, isSelected, isHighlighted, dimensions, isDisabled = false, }) {
|
|
14
14
|
const colors = useThemeColors();
|
|
15
|
-
|
|
16
|
-
const
|
|
15
|
+
// When disabled, use muted colors; otherwise use normal highlight colors
|
|
16
|
+
const borderColor = isDisabled
|
|
17
|
+
? colors.border
|
|
18
|
+
: isHighlighted
|
|
19
|
+
? colors.primary
|
|
20
|
+
: isSelected
|
|
21
|
+
? colors.accent
|
|
22
|
+
: colors.border;
|
|
23
|
+
const titleColor = isDisabled
|
|
24
|
+
? colors.textMuted
|
|
25
|
+
: isHighlighted
|
|
26
|
+
? colors.primary
|
|
27
|
+
: isSelected
|
|
28
|
+
? colors.accent
|
|
29
|
+
: colors.text;
|
|
17
30
|
// Calculate card width based on available space
|
|
18
31
|
const cardWidth = Math.min(Math.max(dimensions.width - 4, 30), 50);
|
|
19
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", game.name] }) }), _jsx(Text, { dimColor: true, wrap: "truncate", children: game.description }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Controls: " }), _jsx(Text, { dimColor: true, children: game.controls })] }), game.minWidth && game.minHeight && (_jsxs(Text, { dimColor: true, children: ["Min size: ", game.minWidth, "x", game.minHeight] }))] }));
|
|
32
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", isDisabled ? "🔒 " : "", game.name] }) }), _jsx(Text, { dimColor: true, wrap: "truncate", children: game.description }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Controls: " }), _jsx(Text, { dimColor: true, children: game.controls })] }), game.minWidth && game.minHeight && (_jsxs(Text, { dimColor: true, children: ["Min size: ", game.minWidth, "x", game.minHeight] }))] }));
|
|
20
33
|
}
|
|
21
34
|
function SelectorHeader({ hasFocus }) {
|
|
22
35
|
const colors = useThemeColors();
|
|
@@ -24,13 +37,25 @@ function SelectorHeader({ hasFocus }) {
|
|
|
24
37
|
? "↑/↓: Navigate | Enter: Select | S: Stats | Q: Back"
|
|
25
38
|
: "Press Tab to focus game selector" })] }));
|
|
26
39
|
}
|
|
27
|
-
function StatsMenuCard({ isHighlighted, dimensions, achievementCount }) {
|
|
40
|
+
function StatsMenuCard({ isHighlighted, dimensions, achievementCount, }) {
|
|
28
41
|
const colors = useThemeColors();
|
|
29
42
|
const borderColor = isHighlighted ? colors.warning : colors.border;
|
|
30
43
|
const titleColor = isHighlighted ? colors.warning : colors.textMuted;
|
|
31
44
|
const cardWidth = Math.min(Math.max(dimensions.width - 4, 30), 50);
|
|
32
45
|
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", "Stats & Achievements"] }) }), _jsx(Text, { dimColor: true, children: "View your gameplay statistics and unlock achievements" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Progress: " }), _jsxs(Text, { color: colors.success, children: [achievementCount.unlocked, "/", achievementCount.total, " achievements"] })] })] }));
|
|
33
46
|
}
|
|
47
|
+
function LoopMenuCard({ isHighlighted, dimensions, hasActiveLoop, }) {
|
|
48
|
+
const colors = useThemeColors();
|
|
49
|
+
const borderColor = isHighlighted ? colors.success : colors.border;
|
|
50
|
+
const titleColor = isHighlighted ? colors.success : colors.text;
|
|
51
|
+
const cardWidth = Math.min(Math.max(dimensions.width - 4, 30), 50);
|
|
52
|
+
const title = hasActiveLoop ? "View Current Loop" : "Start New Loop";
|
|
53
|
+
const description = hasActiveLoop
|
|
54
|
+
? "View progress on your current feature development loop"
|
|
55
|
+
: "Begin a new feature development loop with Claude";
|
|
56
|
+
const icon = hasActiveLoop ? "📋" : "🚀";
|
|
57
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: borderColor, paddingX: 1, width: cardWidth, children: [_jsx(Box, { children: _jsxs(Text, { bold: true, color: titleColor, children: [isHighlighted ? `${navIcons.arrowRight} ` : " ", icon, " ", title] }) }), _jsx(Text, { dimColor: true, children: description }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.textMuted, children: "Shortcut: " }), _jsx(Text, { dimColor: true, children: "N" })] })] }));
|
|
58
|
+
}
|
|
34
59
|
function EmptyState() {
|
|
35
60
|
const colors = useThemeColors();
|
|
36
61
|
return (_jsxs(Box, { flexDirection: "column", padding: 2, children: [_jsx(Text, { color: colors.accent, children: "No games available" }), _jsx(Text, { dimColor: true, children: "Check back later for new games!" })] }));
|
|
@@ -38,12 +63,20 @@ function EmptyState() {
|
|
|
38
63
|
/**
|
|
39
64
|
* Game selector menu component
|
|
40
65
|
*/
|
|
41
|
-
export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, }) {
|
|
66
|
+
export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpenStats, gamesEnabled = true, hasActiveLoop = false, onStartNewLoop, onViewCurrentLoop, }) {
|
|
42
67
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
43
|
-
const [achievementCount, setAchievementCount] = useState({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
const [achievementCount, setAchievementCount] = useState({
|
|
69
|
+
unlocked: 0,
|
|
70
|
+
total: 0,
|
|
71
|
+
});
|
|
72
|
+
const [showLockedMessage, setShowLockedMessage] = useState(false);
|
|
73
|
+
const colors = useThemeColors();
|
|
74
|
+
// Menu structure: [Loop option] + [Games] + [Stats]
|
|
75
|
+
// Loop option is always at index 0
|
|
76
|
+
const loopIndex = 0;
|
|
77
|
+
const firstGameIndex = 1;
|
|
78
|
+
const statsIndex = games.length + 1; // Stats is always last
|
|
79
|
+
const totalItems = games.length + 2; // Loop option + games + stats
|
|
47
80
|
// Load achievement count
|
|
48
81
|
useEffect(() => {
|
|
49
82
|
const loadCount = async () => {
|
|
@@ -52,14 +85,53 @@ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpen
|
|
|
52
85
|
};
|
|
53
86
|
void loadCount();
|
|
54
87
|
}, []);
|
|
88
|
+
// Clear the locked message after a timeout
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
if (showLockedMessage) {
|
|
91
|
+
const timer = setTimeout(() => {
|
|
92
|
+
setShowLockedMessage(false);
|
|
93
|
+
}, 2000);
|
|
94
|
+
return () => clearTimeout(timer);
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}, [showLockedMessage]);
|
|
55
98
|
const handleSelect = useCallback(() => {
|
|
56
|
-
if (selectedIndex ===
|
|
99
|
+
if (selectedIndex === loopIndex) {
|
|
100
|
+
// Loop option - first item
|
|
101
|
+
if (hasActiveLoop) {
|
|
102
|
+
onViewCurrentLoop?.();
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
onStartNewLoop?.();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (selectedIndex === statsIndex) {
|
|
109
|
+
// Stats is always accessible
|
|
57
110
|
onOpenStats?.();
|
|
58
111
|
}
|
|
59
|
-
else
|
|
60
|
-
|
|
112
|
+
else {
|
|
113
|
+
// Game selection (indices are offset by 1 due to loop option)
|
|
114
|
+
const gameIndex = selectedIndex - firstGameIndex;
|
|
115
|
+
if (games.length > 0 && games[gameIndex]) {
|
|
116
|
+
// Check if games are enabled
|
|
117
|
+
if (!gamesEnabled) {
|
|
118
|
+
setShowLockedMessage(true);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
onSelectGame(games[gameIndex].id);
|
|
122
|
+
}
|
|
61
123
|
}
|
|
62
|
-
}, [
|
|
124
|
+
}, [
|
|
125
|
+
games,
|
|
126
|
+
selectedIndex,
|
|
127
|
+
onSelectGame,
|
|
128
|
+
onOpenStats,
|
|
129
|
+
statsIndex,
|
|
130
|
+
gamesEnabled,
|
|
131
|
+
hasActiveLoop,
|
|
132
|
+
onStartNewLoop,
|
|
133
|
+
onViewCurrentLoop,
|
|
134
|
+
]);
|
|
63
135
|
useInput((input, key) => {
|
|
64
136
|
if (!hasFocus)
|
|
65
137
|
return;
|
|
@@ -83,11 +155,29 @@ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpen
|
|
|
83
155
|
onOpenStats?.();
|
|
84
156
|
return;
|
|
85
157
|
}
|
|
158
|
+
// Quick trigger loop option with N key
|
|
159
|
+
if (input === "n" || input === "N") {
|
|
160
|
+
setSelectedIndex(loopIndex);
|
|
161
|
+
if (hasActiveLoop) {
|
|
162
|
+
onViewCurrentLoop?.();
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
onStartNewLoop?.();
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
86
169
|
// Quick select game by number (1-9)
|
|
87
170
|
const num = parseInt(input, 10);
|
|
88
171
|
if (!isNaN(num) && num >= 1 && num <= games.length) {
|
|
89
|
-
|
|
172
|
+
// Map number to game index (account for loop option at index 0)
|
|
173
|
+
const gameMenuIndex = num - 1 + firstGameIndex;
|
|
174
|
+
setSelectedIndex(gameMenuIndex);
|
|
90
175
|
if (games[num - 1]) {
|
|
176
|
+
// Check if games are enabled before quick-selecting
|
|
177
|
+
if (!gamesEnabled) {
|
|
178
|
+
setShowLockedMessage(true);
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
91
181
|
onSelectGame(games[num - 1].id);
|
|
92
182
|
}
|
|
93
183
|
return;
|
|
@@ -97,9 +187,16 @@ export function GameSelector({ games, hasFocus, dimensions, onSelectGame, onOpen
|
|
|
97
187
|
if (selectedIndex >= totalItems && totalItems > 0) {
|
|
98
188
|
setSelectedIndex(totalItems - 1);
|
|
99
189
|
}
|
|
100
|
-
return (_jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [_jsx(SelectorHeader, { hasFocus: hasFocus }),
|
|
101
|
-
|
|
102
|
-
|
|
190
|
+
return (_jsxs(Box, { flexDirection: "column", padding: 1, height: "100%", children: [_jsx(SelectorHeader, { hasFocus: hasFocus }), showLockedMessage && (_jsx(Box, { marginBottom: 1, paddingX: 1, children: _jsx(Text, { color: colors.warning, children: "\uD83D\uDD12 Start a loop to unlock games!" }) })), _jsxs(Box, { flexDirection: "column", gap: 1, children: [_jsx(LoopMenuCard, { isHighlighted: hasFocus && selectedIndex === loopIndex, dimensions: dimensions, hasActiveLoop: hasActiveLoop }), games.length === 0 ? (_jsx(EmptyState, {})) : (_jsx(_Fragment, { children: games.map((game, index) => {
|
|
191
|
+
const menuIndex = index + firstGameIndex;
|
|
192
|
+
return (_jsx(GameCard, { game: game, isSelected: menuIndex === selectedIndex, isHighlighted: hasFocus && menuIndex === selectedIndex, dimensions: dimensions, isDisabled: !gamesEnabled }, game.id));
|
|
193
|
+
}) })), _jsx(StatsMenuCard, { isHighlighted: hasFocus && selectedIndex === statsIndex, dimensions: dimensions, achievementCount: achievementCount })] }), totalItems > 0 && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: selectedIndex === loopIndex
|
|
194
|
+
? hasActiveLoop
|
|
195
|
+
? "View Current Loop"
|
|
196
|
+
: "Start New Loop"
|
|
197
|
+
: selectedIndex === statsIndex
|
|
198
|
+
? "Stats & Achievements"
|
|
199
|
+
: `Game ${selectedIndex - firstGameIndex + 1} of ${games.length}` }) }))] }));
|
|
103
200
|
}
|
|
104
201
|
export default GameSelector;
|
|
105
202
|
//# sourceMappingURL=GameSelector.js.map
|