File size: 2,241 Bytes
9332ccf | 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 | /**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import type React from 'react';
import { Box, Text } from 'ink';
import { theme } from '../semantic-colors.js';
import { checkExhaustive } from '@google/gemini-cli-core';
export type ChecklistStatus =
| 'pending'
| 'in_progress'
| 'completed'
| 'cancelled'
| 'blocked';
export interface ChecklistItemData {
status: ChecklistStatus;
label: string;
}
const ChecklistStatusDisplay: React.FC<{ status: ChecklistStatus }> = ({
status,
}) => {
switch (status) {
case 'completed':
return (
<Text color={theme.status.success} aria-label="Completed">
✓
</Text>
);
case 'in_progress':
return (
<Text color={theme.text.accent} aria-label="In Progress">
»
</Text>
);
case 'pending':
return (
<Text color={theme.text.secondary} aria-label="Pending">
☐
</Text>
);
case 'cancelled':
return (
<Text color={theme.status.error} aria-label="Cancelled">
✗
</Text>
);
case 'blocked':
return (
<Text color={theme.status.warning} aria-label="Blocked">
⛔
</Text>
);
default:
checkExhaustive(status);
}
};
export interface ChecklistItemProps {
item: ChecklistItemData;
wrap?: 'truncate';
role?: 'listitem';
}
export const ChecklistItem: React.FC<ChecklistItemProps> = ({
item,
wrap,
role: ariaRole,
}) => {
const textColor = (() => {
switch (item.status) {
case 'in_progress':
return theme.text.accent;
case 'completed':
case 'cancelled':
case 'blocked':
return theme.text.secondary;
case 'pending':
return theme.text.primary;
default:
checkExhaustive(item.status);
}
})();
const strikethrough = item.status === 'cancelled';
return (
<Box flexDirection="row" columnGap={1} aria-role={ariaRole}>
<ChecklistStatusDisplay status={item.status} />
<Box flexShrink={1}>
<Text color={textColor} wrap={wrap} strikethrough={strikethrough}>
{item.label}
</Text>
</Box>
</Box>
);
};
|