@siegesailor/terminal-sigma 1.0.0 → 1.1.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.
@@ -1,296 +1,20 @@
1
- import { Badge } from "@inkjs/ui";
2
1
  import React from "react";
3
- import { Box, Text } from "ink";
4
- const beltShape = String.raw ` /_\ `;
5
- const visorCrest = String.raw ` /^\ `;
6
- const hoodCrest = String.raw ` /~\ `;
7
- const backslash = String.raw `\ `.trimEnd();
8
- const walkStride = `/ ${backslash}`;
9
- const armorOptions = {
10
- "scout-weave": {
11
- label: "Scout Weave",
12
- color: "greenBright",
13
- chest: "|=^=|",
14
- belt: beltShape,
15
- },
16
- "carbon-shell": {
17
- label: "Carbon Shell",
18
- color: "yellowBright",
19
- chest: "|###|",
20
- belt: beltShape,
21
- },
22
- "bulwark-plate": {
23
- label: "Bulwark Plate",
24
- color: "cyanBright",
25
- chest: "|*#*|",
26
- belt: beltShape,
27
- },
28
- };
29
- const weaponOptions = {
30
- "arc-blade": {
31
- label: "Arc Blade",
32
- color: "magentaBright",
33
- top: " /",
34
- middle: "==>",
35
- bottom: ` ${backslash}`,
36
- },
37
- "pulse-rifle": {
38
- label: "Pulse Rifle",
39
- color: "redBright",
40
- top: " _",
41
- middle: "-|>",
42
- bottom: " /",
43
- },
44
- "signal-staff": {
45
- label: "Signal Staff",
46
- color: "blueBright",
47
- top: " *",
48
- middle: " |",
49
- bottom: " |",
50
- },
51
- };
52
- const helmetOptions = {
53
- "signal-visor": {
54
- label: "Signal Visor",
55
- color: "cyanBright",
56
- crest: visorCrest,
57
- frameLeft: "[",
58
- frameRight: "]",
59
- },
60
- "horned-guard": {
61
- label: "Horned Guard",
62
- color: "yellowBright",
63
- crest: `/^^${backslash}`,
64
- frameLeft: "{",
65
- frameRight: "}",
66
- },
67
- "hood-shell": {
68
- label: "Hood Shell",
69
- color: "magentaBright",
70
- crest: hoodCrest,
71
- frameLeft: "<",
72
- frameRight: ">",
73
- },
74
- };
75
- const backpackOptions = {
76
- "field-pack": {
77
- label: "Field Pack",
78
- color: "greenBright",
79
- top: "[]",
80
- middle: "[]",
81
- bottom: "[]",
82
- },
83
- "cargo-rig": {
84
- label: "Cargo Rig",
85
- color: "yellowBright",
86
- top: "{}",
87
- middle: "{}",
88
- bottom: "{}",
89
- },
90
- "reactor-pack": {
91
- label: "Reactor Pack",
92
- color: "cyanBright",
93
- top: "()",
94
- middle: "()",
95
- bottom: "()",
96
- },
97
- };
98
- const animationFrames = [
99
- {
100
- mode: "walk",
101
- leftArm: "/",
102
- rightArm: "-",
103
- legs: walkStride,
104
- expression: "o_o",
105
- callout: "Stride calibrated.",
106
- },
107
- {
108
- mode: "walk",
109
- leftArm: "<",
110
- rightArm: backslash,
111
- legs: "| /",
112
- expression: "o_o",
113
- callout: "Route locked.",
114
- },
115
- {
116
- mode: "talk",
117
- leftArm: "/",
118
- rightArm: "^",
119
- legs: walkStride,
120
- expression: "o-o",
121
- callout: "Telemetry sounds clean.",
122
- },
123
- {
124
- mode: "talk",
125
- leftArm: "/",
126
- rightArm: "~",
127
- legs: walkStride,
128
- expression: "o_o",
129
- callout: "Backlog pressure nominal.",
130
- },
131
- {
132
- mode: "guard",
133
- leftArm: "/",
134
- rightArm: backslash,
135
- legs: walkStride,
136
- expression: "o_o",
137
- callout: "Holding formation.",
138
- },
139
- ];
140
- // Weakest first. One slot upgrades per level from level 2, then every 4 levels per slot.
141
- const weaponTiers = [
142
- "signal-staff",
143
- "pulse-rifle",
144
- "arc-blade",
145
- ];
146
- const armorTiers = [
147
- "scout-weave",
148
- "carbon-shell",
149
- "bulwark-plate",
150
- ];
151
- const helmetTiers = [
152
- "hood-shell",
153
- "signal-visor",
154
- "horned-guard",
155
- ];
156
- const backpackTiers = [
157
- "field-pack",
158
- "cargo-rig",
159
- "reactor-pack",
160
- ];
161
- const tierOf = (tiers, level, slot) => {
162
- const tier = Math.floor((level - 2 - slot) / 4) + 1;
163
- const option = tiers[Math.min(Math.max(tier, 0), tiers.length - 1)];
164
- if (option === undefined) {
165
- throw new Error("Character gear tiers are required.");
166
- }
167
- return option;
168
- };
169
- export const loadoutOf = (level) => ({
170
- weapon: tierOf(weaponTiers, level, 0),
171
- armor: tierOf(armorTiers, level, 1),
172
- helmet: tierOf(helmetTiers, level, 2),
173
- backpack: tierOf(backpackTiers, level, 3),
174
- });
175
- const modeBadgeColor = {
176
- walk: "blue",
177
- talk: "green",
178
- guard: "yellow",
179
- };
180
- const modeLabel = {
181
- walk: "WALK",
182
- talk: "TALK",
183
- guard: "GUARD",
184
- };
185
- const calloutColor = {
186
- walk: "cyanBright",
187
- talk: "magentaBright",
188
- guard: "yellowBright",
189
- };
190
- function SpriteRow({ indent, segments }) {
191
- return (React.createElement(Box, { marginLeft: indent }, segments.map((segment) => (React.createElement(Text, { key: segment.key, color: segment.color }, segment.text)))));
192
- }
193
- function LoadoutRow({ label, value, color }) {
194
- return (React.createElement(Box, { justifyContent: "space-between" },
195
- React.createElement(Text, { color: "gray" }, label),
196
- React.createElement(Text, { color: color }, value)));
197
- }
198
- export default function Character({ width, name, level }) {
199
- const [frameIndex, setFrameIndex] = React.useState(0);
200
- React.useEffect(() => {
201
- const interval = setInterval(() => {
202
- setFrameIndex((current) => (current + 1) % animationFrames.length);
203
- }, 240);
204
- return () => {
205
- clearInterval(interval);
206
- };
207
- }, []);
208
- const fallbackFrame = animationFrames[0];
209
- if (!fallbackFrame) {
210
- throw new Error("Character animation frames are required.");
211
- }
212
- const frame = animationFrames[frameIndex] ?? fallbackFrame;
213
- const { armor, weapon, helmet, backpack } = loadoutOf(level);
214
- const armorView = armorOptions[armor];
215
- const weaponView = weaponOptions[weapon];
216
- const helmetView = helmetOptions[helmet];
217
- const backpackView = backpackOptions[backpack];
218
- const face = `${helmetView.frameLeft}${frame.expression}${helmetView.frameRight}`;
219
- const spriteWidth = 13;
220
- const contentWidth = Math.max(width - 4, spriteWidth);
221
- const indent = Math.max(Math.floor((contentWidth - spriteWidth) / 2), 0);
222
- return (React.createElement(Box, { borderStyle: "round", borderColor: "cyan", flexDirection: "column", paddingX: 1, paddingY: 1, width: width },
2
+ import { Box, Text, useAnimation } from "ink";
3
+ import { animationOf, composeFrame, paletteOf, toSegments, } from "../pixel-art.js";
4
+ import { colors, spinnerFrames } from "../theme.js";
5
+ export default function Character({ name, level, levelNumber, activity, label, width, }) {
6
+ const { frame } = useAnimation({ interval: animationOf(activity).interval });
7
+ const lines = toSegments(composeFrame(activity, frame, levelNumber), paletteOf(levelNumber));
8
+ const spinner = activity === "idle" ? "·" : spinnerFrames[frame % spinnerFrames.length];
9
+ return (React.createElement(Box, { borderColor: colors.border, borderStyle: "round", flexDirection: "column", paddingX: 1, width: width },
223
10
  React.createElement(Box, { justifyContent: "space-between" },
224
- React.createElement(Text, { color: "whiteBright" }, `${name} LV ${level}`),
225
- React.createElement(Badge, { color: modeBadgeColor[frame.mode] }, modeLabel[frame.mode])),
226
- React.createElement(Text, { color: "gray" }, "Gear unlocks as you level"),
227
- React.createElement(Box, { marginTop: 1 },
228
- React.createElement(Text, { color: calloutColor[frame.mode] }, `"${frame.callout}"`)),
229
- React.createElement(Box, { flexDirection: "column", marginTop: 1 },
230
- React.createElement(SpriteRow, { indent: indent, segments: [
231
- { key: "indent", text: " " },
232
- {
233
- key: "crest",
234
- text: helmetView.crest,
235
- color: helmetView.color,
236
- },
237
- ] }),
238
- React.createElement(SpriteRow, { indent: indent, segments: [
239
- {
240
- key: "pack-top",
241
- text: backpackView.top,
242
- color: backpackView.color,
243
- },
244
- { key: "face-gap", text: " " },
245
- { key: "face", text: face, color: helmetView.color },
246
- {
247
- key: "weapon-top",
248
- text: weaponView.top,
249
- color: weaponView.color,
250
- },
251
- ] }),
252
- React.createElement(SpriteRow, { indent: indent, segments: [
253
- {
254
- key: "pack-middle",
255
- text: backpackView.middle,
256
- color: backpackView.color,
257
- },
258
- { key: "left-arm", text: frame.leftArm, color: armorView.color },
259
- { key: "chest", text: armorView.chest, color: armorView.color },
260
- {
261
- key: "right-arm",
262
- text: frame.rightArm,
263
- color: armorView.color,
264
- },
265
- {
266
- key: "weapon-middle",
267
- text: weaponView.middle,
268
- color: weaponView.color,
269
- },
270
- ] }),
271
- React.createElement(SpriteRow, { indent: indent, segments: [
272
- {
273
- key: "pack-bottom",
274
- text: backpackView.bottom,
275
- color: backpackView.color,
276
- },
277
- { key: "belt-gap-left", text: " " },
278
- { key: "belt", text: armorView.belt, color: armorView.color },
279
- { key: "belt-gap-right", text: " " },
280
- {
281
- key: "weapon-bottom",
282
- text: weaponView.bottom,
283
- color: weaponView.color,
284
- },
285
- ] }),
286
- React.createElement(SpriteRow, { indent: indent, segments: [
287
- { key: "leg-indent", text: " " },
288
- { key: "legs", text: frame.legs },
289
- ] })),
290
- React.createElement(Box, { flexDirection: "column", marginTop: 1 },
291
- React.createElement(LoadoutRow, { label: "Armor", value: armorView.label, color: armorView.color }),
292
- React.createElement(LoadoutRow, { label: "Weapon", value: weaponView.label, color: weaponView.color }),
293
- React.createElement(LoadoutRow, { label: "Helmet", value: helmetView.label, color: helmetView.color }),
294
- React.createElement(LoadoutRow, { label: "Backpack", value: backpackView.label, color: backpackView.color }))));
11
+ React.createElement(Text, { bold: true, wrap: "truncate-end" }, name),
12
+ React.createElement(Text, { color: colors.accent }, level)),
13
+ React.createElement(Box, { alignItems: "center", flexDirection: "column", flexGrow: 1, justifyContent: "center" }, lines.map((line, row) => (React.createElement(Box, { key: row }, line.map((segment, column) => (React.createElement(Text
14
+ // eslint-disable-next-line react/no-array-index-key
15
+ , {
16
+ // eslint-disable-next-line react/no-array-index-key
17
+ key: column, backgroundColor: segment.backgroundColor, color: segment.color }, segment.text))))))),
18
+ React.createElement(Text, { color: colors.accent, wrap: "truncate-end" }, `${spinner} ${label}`)));
295
19
  }
296
20
  //# sourceMappingURL=character.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"character.js","sourceRoot":"","sources":["../../source/components/character.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"character.js","sourceRoot":"","sources":["../../source/components/character.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,EAEN,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,GACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAWpD,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EACjC,IAAI,EACJ,KAAK,EACL,WAAW,EACX,QAAQ,EACR,KAAK,EACL,KAAK,GACW;IAChB,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,UAAU,CACvB,YAAY,CAAC,QAAQ,EAAE,KAAK,EAAE,WAAW,CAAC,EAC1C,SAAS,CAAC,WAAW,CAAC,CACtB,CAAC;IACF,MAAM,OAAO,GACZ,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;IAEzE,OAAO,CACN,oBAAC,GAAG,IACH,WAAW,EAAE,MAAM,CAAC,MAAM,EAC1B,WAAW,EAAC,OAAO,EACnB,aAAa,EAAC,QAAQ,EACtB,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,KAAK;QAEZ,oBAAC,GAAG,IAAC,cAAc,EAAC,eAAe;YAClC,oBAAC,IAAI,IAAC,IAAI,QAAC,IAAI,EAAC,cAAc,IAC5B,IAAI,CACC;YACP,oBAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,IAAG,KAAK,CAAQ,CACrC;QACN,oBAAC,GAAG,IACH,UAAU,EAAC,QAAQ,EACnB,aAAa,EAAC,QAAQ,EACtB,QAAQ,EAAE,CAAC,EACX,cAAc,EAAC,QAAQ,IAEtB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAGzB,oBAAC,GAAG,IAAC,GAAG,EAAE,GAAG,IACX,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,CAC9B,oBAAC,IAAI;QACJ,oDAAoD;;YAApD,oDAAoD;YACpD,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,OAAO,CAAC,eAAe,EACxC,KAAK,EAAE,OAAO,CAAC,KAAK,IAEnB,OAAO,CAAC,IAAI,CACP,CACP,CAAC,CACG,CACN,CAAC,CACG;QACN,oBAAC,IAAI,IACJ,KAAK,EAAE,MAAM,CAAC,MAAM,EACpB,IAAI,EAAC,cAAc,IAClB,GAAG,OAAO,IAAI,KAAK,EAAE,CAAQ,CAC1B,CACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,52 @@
1
+ import React from "react";
2
+ import { Select, TextInput } from "@inkjs/ui";
3
+ import { Box, Text } from "ink";
4
+ import { parseWholeNumber } from "../progress.js";
5
+ import { colors } from "../theme.js";
6
+ export default function EntryForm({ title, fields, messages, onSubmit, onValues, }) {
7
+ const [values, setValues] = React.useState({});
8
+ const [error, setError] = React.useState();
9
+ const field = fields[Object.keys(values).length];
10
+ const accept = (value) => {
11
+ if (!field) {
12
+ return;
13
+ }
14
+ if (field.kind === "text" && !value.trim()) {
15
+ setError(messages.form.required);
16
+ return;
17
+ }
18
+ if (field.kind === "number" &&
19
+ parseWholeNumber(value, field.minimum, field.maximum) === undefined) {
20
+ setError(messages.form.wholeNumber(field.minimum, field.maximum));
21
+ return;
22
+ }
23
+ const next = { ...values, [field.key]: value.trim() };
24
+ setError(undefined);
25
+ setValues(next);
26
+ onValues?.(next);
27
+ if (Object.keys(next).length === fields.length) {
28
+ onSubmit(next);
29
+ }
30
+ };
31
+ const shown = (done) => {
32
+ const value = values[done.key] ?? "";
33
+ return done.kind === "select"
34
+ ? (done.options.find((option) => option.value === value)?.label ?? value)
35
+ : value;
36
+ };
37
+ return (React.createElement(Box, { flexDirection: "column" },
38
+ React.createElement(Text, { bold: true, color: colors.accent }, title),
39
+ fields
40
+ .filter((done) => done.key in values)
41
+ .map((done) => (React.createElement(Text, { key: done.key },
42
+ React.createElement(Text, { color: colors.focus }, "\u2713 "),
43
+ React.createElement(Text, { dimColor: true }, `${done.label}: `),
44
+ React.createElement(Text, null, shown(done))))),
45
+ field ? (React.createElement(Box, { flexDirection: "column" },
46
+ React.createElement(Text, { bold: true }, `❯ ${field.label}`),
47
+ React.createElement(Box, { paddingLeft: 2 }, field.kind === "select" ? (React.createElement(Select, { key: field.key, options: field.options, visibleOptionCount: field.options.length, onChange: accept })) : (React.createElement(TextInput, { key: field.key, placeholder: field.kind === "text"
48
+ ? field.placeholder
49
+ : `${field.minimum} - ${field.maximum}`, onSubmit: accept }))))) : null,
50
+ error ? React.createElement(Text, { color: colors.error }, error) : null));
51
+ }
52
+ //# sourceMappingURL=entry-form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry-form.js","sourceRoot":"","sources":["../../source/components/entry-form.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ import { Box, Text, useAnimation } from "ink";
3
+ import { colors, spinnerFrames } from "../theme.js";
4
+ function Spinner() {
5
+ const { frame } = useAnimation({ interval: 120 });
6
+ return (React.createElement(Text, { color: colors.accent }, spinnerFrames[frame % spinnerFrames.length]));
7
+ }
8
+ const toneColor = {
9
+ info: undefined,
10
+ success: colors.focus,
11
+ error: colors.error,
12
+ };
13
+ // Like Claude Code's status line: a spinner while something runs, a bullet otherwise.
14
+ export default function Footer({ status, message, tone, hint }) {
15
+ return (React.createElement(Box, { flexShrink: 0, gap: 2, justifyContent: "space-between", paddingX: 1 },
16
+ React.createElement(Text, { wrap: "truncate-end" }, status ? (React.createElement(React.Fragment, null,
17
+ React.createElement(Spinner, null),
18
+ React.createElement(Text, { color: colors.accent }, ` ${status}`),
19
+ React.createElement(Text, { dimColor: true }, ` ${message}`))) : (React.createElement(React.Fragment, null,
20
+ React.createElement(Text, { color: toneColor[tone], dimColor: tone === "info" }, "\u23FA"),
21
+ React.createElement(Text, null, ` ${message}`)))),
22
+ React.createElement(Box, { flexShrink: 0 },
23
+ React.createElement(Text, { dimColor: true }, hint))));
24
+ }
25
+ //# sourceMappingURL=footer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"footer.js","sourceRoot":"","sources":["../../source/components/footer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,KAAK,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAWpD,SAAS,OAAO;IACf,MAAM,EAAE,KAAK,EAAE,GAAG,YAAY,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;IAClD,OAAO,CACN,oBAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,IACxB,aAAa,CAAC,KAAK,GAAG,aAAa,CAAC,MAAM,CAAC,CACtC,CACP,CAAC;AACH,CAAC;AAED,MAAM,SAAS,GAAqC;IACnD,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,MAAM,CAAC,KAAK;IACrB,KAAK,EAAE,MAAM,CAAC,KAAK;CACnB,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAe;IAC1E,OAAO,CACN,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,cAAc,EAAC,eAAe,EAAC,QAAQ,EAAE,CAAC;QACrE,oBAAC,IAAI,IAAC,IAAI,EAAC,cAAc,IACvB,MAAM,CAAC,CAAC,CAAC,CACT;YACC,oBAAC,OAAO,OAAG;YACX,oBAAC,IAAI,IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,IAAG,IAAI,MAAM,EAAE,CAAQ;YACjD,oBAAC,IAAI,IAAC,QAAQ,UAAE,KAAK,OAAO,EAAE,CAAQ,CACpC,CACH,CAAC,CAAC,CAAC,CACH;YACC,oBAAC,IAAI,IAAC,KAAK,EAAE,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,IAAI,KAAK,MAAM,aAEhD;YACP,oBAAC,IAAI,QAAE,IAAI,OAAO,EAAE,CAAQ,CAC1B,CACH,CACK;QACP,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;YACjB,oBAAC,IAAI,IAAC,QAAQ,UAAE,IAAI,CAAQ,CACvB,CACD,CACN,CAAC;AACH,CAAC"}
@@ -0,0 +1,96 @@
1
+ import React from "react";
2
+ import { Box, Text, useInput } from "ink";
3
+ import { formatNumber, workoutActivities, } from "../i18n.js";
4
+ import { colors } from "../theme.js";
5
+ const filters = ["all", "focus", "meal", "workout"];
6
+ const kindColor = {
7
+ focus: colors.focus,
8
+ meal: colors.diet,
9
+ workout: colors.workout,
10
+ };
11
+ const isWorkoutActivity = (activity) => workoutActivities.includes(activity);
12
+ export function describeLog(log, language, messages) {
13
+ const amount = (value) => value === undefined ? "-" : formatNumber(language, value);
14
+ switch (log.kind) {
15
+ case "focus": {
16
+ return messages.logs.focusEntry(log.entry.minutes);
17
+ }
18
+ case "meal": {
19
+ return messages.logs.mealEntry(log.entry.food, amount(log.entry.calories), amount(log.entry.protein));
20
+ }
21
+ case "workout": {
22
+ const { activity, minutes, intensity } = log.entry;
23
+ return messages.logs.workoutEntry(isWorkoutActivity(activity)
24
+ ? messages.workoutActivity[activity]
25
+ : activity, minutes, intensity ? messages.intensity[intensity] : "-");
26
+ }
27
+ }
28
+ }
29
+ export default function LogsView({ logs, language, messages, height, }) {
30
+ const [filter, setFilter] = React.useState("all");
31
+ const [offset, setOffset] = React.useState(0);
32
+ const shown = logs.filter((log) => filter === "all" || log.kind === filter);
33
+ // Title, tabs, summary, and their spacing take 4 rows.
34
+ const pageSize = Math.max(height - 4, 3);
35
+ const maximumOffset = Math.max(shown.length - pageSize, 0);
36
+ const labels = {
37
+ all: messages.logs.all,
38
+ focus: messages.logs.focus,
39
+ meal: messages.logs.diet,
40
+ workout: messages.logs.workout,
41
+ };
42
+ const formatDate = new Intl.DateTimeFormat(language, {
43
+ month: "2-digit",
44
+ day: "2-digit",
45
+ hour: "2-digit",
46
+ minute: "2-digit",
47
+ hour12: false,
48
+ });
49
+ useInput((input, key) => {
50
+ const move = (step) => {
51
+ const next = filters[(filters.indexOf(filter) + step + filters.length) % filters.length];
52
+ if (next) {
53
+ setFilter(next);
54
+ setOffset(0);
55
+ }
56
+ };
57
+ const scroll = (step) => {
58
+ setOffset((current) => Math.min(Math.max(current + step, 0), maximumOffset));
59
+ };
60
+ if (key.leftArrow || input === "h") {
61
+ move(-1);
62
+ }
63
+ else if (key.rightArrow || input === "l" || key.tab) {
64
+ move(1);
65
+ }
66
+ else if (key.upArrow || input === "k") {
67
+ scroll(-1);
68
+ }
69
+ else if (key.downArrow || input === "j") {
70
+ scroll(1);
71
+ }
72
+ else if (key.pageUp) {
73
+ scroll(-pageSize);
74
+ }
75
+ else if (key.pageDown) {
76
+ scroll(pageSize);
77
+ }
78
+ });
79
+ return (React.createElement(Box, { flexDirection: "column", flexGrow: 1 },
80
+ React.createElement(Box, { gap: 2 },
81
+ React.createElement(Text, { bold: true, color: colors.accent }, messages.logs.title),
82
+ filters.map((option) => (React.createElement(Text, { key: option, bold: option === filter, color: option === filter ? colors.accent : undefined, dimColor: option !== filter, underline: option === filter }, labels[option])))),
83
+ React.createElement(Text, { dimColor: true }, messages.logs.summary(shown.length, shown.reduce((total, log) => total + log.experience, 0))),
84
+ React.createElement(Box, { flexDirection: "column", marginTop: 1 },
85
+ shown.length === 0 ? (React.createElement(Text, { dimColor: true }, messages.logs.empty)) : null,
86
+ shown.slice(offset, offset + pageSize).map((log) => (React.createElement(Box, { key: `${log.kind}-${log.at}`, gap: 2 },
87
+ React.createElement(Box, { flexShrink: 0, width: 12 },
88
+ React.createElement(Text, { dimColor: true }, formatDate.format(new Date(log.at)))),
89
+ React.createElement(Box, { flexShrink: 0, width: 8 },
90
+ React.createElement(Text, { color: kindColor[log.kind] }, labels[log.kind])),
91
+ React.createElement(Box, { flexGrow: 1 },
92
+ React.createElement(Text, { wrap: "truncate-end" }, describeLog(log, language, messages))),
93
+ React.createElement(Box, { flexShrink: 0, justifyContent: "flex-end", width: 8 },
94
+ React.createElement(Text, { color: colors.accent }, `+${log.experience} XP`))))))));
95
+ }
96
+ //# sourceMappingURL=logs-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs-view.js","sourceRoot":"","sources":["../../source/components/logs-view.tsx"],"names":[],"mappings":"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"}
@@ -1,61 +1,42 @@
1
1
  import React from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
+ import { colors } from "../theme.js";
3
4
  const clamp = (value, minimum, maximum) => Math.min(Math.max(value, minimum), maximum);
4
- const formatMenuCell = (item, index, isSelected, cellWidth) => {
5
- const prefix = isSelected ? ">" : " ";
6
- const label = `${prefix} [${index + 1}] ${item.label}`;
7
- const signal = item.signal.toUpperCase();
8
- const gapWidth = Math.max(cellWidth - label.length - signal.length, 1);
9
- return `${label}${" ".repeat(gapWidth)}${signal}`;
10
- };
11
- export default function MenuGrid({ title, width, items: menuItems, onSelect, columns = 2, isActive = true, }) {
5
+ export default function MenuGrid({ items, columns, onSelect, isActive = true, }) {
12
6
  const [selectedIndex, setSelectedIndex] = React.useState(0);
13
- const safeColumns = Math.max(columns, 1);
14
- const gapWidth = safeColumns > 1 ? 3 : 0;
15
- const cellWidth = Math.max(Math.floor((width - gapWidth * (safeColumns - 1)) / safeColumns), 20);
7
+ const last = items.length - 1;
16
8
  useInput((input, key) => {
17
9
  if (key.leftArrow || input === "h") {
18
- setSelectedIndex((current) => Math.max(current - 1, 0));
19
- return;
10
+ setSelectedIndex((current) => clamp(current - 1, 0, last));
20
11
  }
21
- if (key.rightArrow || input === "l") {
22
- setSelectedIndex((current) => Math.min(current + 1, menuItems.length - 1));
23
- return;
12
+ else if (key.rightArrow || input === "l") {
13
+ setSelectedIndex((current) => clamp(current + 1, 0, last));
24
14
  }
25
- if (key.upArrow || input === "k") {
26
- setSelectedIndex((current) => Math.max(current - safeColumns, 0));
27
- return;
15
+ else if (key.upArrow || input === "k") {
16
+ setSelectedIndex((current) => clamp(current - columns, 0, last));
28
17
  }
29
- if (key.downArrow || input === "j") {
30
- setSelectedIndex((current) => Math.min(current + safeColumns, menuItems.length - 1));
31
- return;
18
+ else if (key.downArrow || input === "j") {
19
+ setSelectedIndex((current) => clamp(current + columns, 0, last));
32
20
  }
33
- if (key.return) {
21
+ else if (key.return) {
34
22
  onSelect(selectedIndex);
35
- return;
36
23
  }
37
- const numericChoice = Number.parseInt(input, 10);
38
- if (Number.isNaN(numericChoice)) {
39
- return;
24
+ else if (/^[1-9]$/v.test(input)) {
25
+ setSelectedIndex(clamp(Number(input) - 1, 0, last));
40
26
  }
41
- const nextIndex = clamp(numericChoice - 1, 0, menuItems.length - 1);
42
- setSelectedIndex(nextIndex);
43
27
  }, { isActive });
44
- const activeItem = menuItems[selectedIndex] ?? menuItems[0];
45
- const rowCount = Math.ceil(menuItems.length / safeColumns);
46
- const rows = Array.from({ length: rowCount }, (_, rowIndex) => menuItems.slice(rowIndex * safeColumns, rowIndex * safeColumns + safeColumns));
47
- return (React.createElement(Box, { flexDirection: "column", width: width },
48
- React.createElement(Box, { justifyContent: "space-between" },
49
- React.createElement(Text, { color: "greenBright" }, title),
50
- React.createElement(Text, { color: "gray" }, "Arrows / hjkl / Enter / q")),
51
- React.createElement(Box, { flexDirection: "column", marginTop: 1 }, rows.map((row, rowIndex) => (React.createElement(Box, { key: row.map((item) => item.label).join("-") }, row.map((item, columnIndex) => {
52
- const index = rowIndex * safeColumns + columnIndex;
53
- const isSelected = index === selectedIndex;
54
- const marginRight = columnIndex < row.length - 1 ? gapWidth : 0;
55
- return (React.createElement(Box, { key: item.label, marginRight: marginRight, width: cellWidth },
56
- React.createElement(Text, { backgroundColor: isSelected ? "cyan" : undefined, color: isSelected ? "black" : item.color }, formatMenuCell(item, index, isSelected, cellWidth))));
57
- }))))),
58
- activeItem ? (React.createElement(Box, { marginTop: 1 },
59
- React.createElement(Text, { color: activeItem.color }, activeItem.description))) : null));
28
+ const rows = Array.from({ length: Math.ceil(items.length / columns) }, (_, row) => items.slice(row * columns, row * columns + columns));
29
+ return (React.createElement(Box, { flexDirection: "column" },
30
+ rows.map((row, rowIndex) => (React.createElement(Box, { key: row.map((item) => item.label).join("-"), gap: 3 },
31
+ row.map((item, columnIndex) => {
32
+ const index = rowIndex * columns + columnIndex;
33
+ const isSelected = index === selectedIndex;
34
+ return (React.createElement(Box, { key: item.label, flexBasis: 0, flexGrow: 1, justifyContent: "space-between" },
35
+ React.createElement(Text, { bold: isSelected, color: isSelected ? colors.accent : undefined, wrap: "truncate-end" }, `${isSelected ? "❯" : " "} ${index + 1}. ${item.label}`),
36
+ React.createElement(Text, { dimColor: true }, item.signal)));
37
+ }),
38
+ Array.from({ length: columns - row.length }, (_, filler) => (React.createElement(Box, { key: `filler-${filler}`, flexBasis: 0, flexGrow: 1 })))))),
39
+ React.createElement(Box, { marginTop: 1 },
40
+ React.createElement(Text, { dimColor: true }, items[selectedIndex]?.description))));
60
41
  }
61
42
  //# sourceMappingURL=menu-grid.js.map