diff options
Diffstat (limited to 'renderer/src/components/ActionBar.tsx')
| -rw-r--r-- | renderer/src/components/ActionBar.tsx | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/renderer/src/components/ActionBar.tsx b/renderer/src/components/ActionBar.tsx new file mode 100644 index 0000000..22f34b4 --- /dev/null +++ b/renderer/src/components/ActionBar.tsx | |||
| @@ -0,0 +1,97 @@ | |||
| 1 | import React from "react"; | ||
| 2 | import type { Phase, PermissionMode, TokenUsage } from "../types"; | ||
| 3 | |||
| 4 | interface ActionBarProps { | ||
| 5 | phase: Phase; | ||
| 6 | hasChanges: boolean; | ||
| 7 | isLoading: boolean; | ||
| 8 | tokenUsage: TokenUsage; | ||
| 9 | permissionMode: PermissionMode; | ||
| 10 | onReview: () => void; | ||
| 11 | onSubmit: () => void; | ||
| 12 | onPermissionModeChange: (mode: PermissionMode) => void; | ||
| 13 | disabled: boolean; | ||
| 14 | } | ||
| 15 | |||
| 16 | export function ActionBar({ | ||
| 17 | phase, | ||
| 18 | hasChanges, | ||
| 19 | isLoading, | ||
| 20 | tokenUsage, | ||
| 21 | permissionMode, | ||
| 22 | onReview, | ||
| 23 | onSubmit, | ||
| 24 | onPermissionModeChange, | ||
| 25 | disabled, | ||
| 26 | }: ActionBarProps) { | ||
| 27 | const totalTokens = tokenUsage.inputTokens + tokenUsage.outputTokens; | ||
| 28 | const maxTokens = 200000; | ||
| 29 | const usagePercent = Math.min((totalTokens / maxTokens) * 100, 100); | ||
| 30 | |||
| 31 | const getBarColor = () => { | ||
| 32 | if (usagePercent > 80) return "#ef4444"; | ||
| 33 | if (usagePercent > 50) return "#f59e0b"; | ||
| 34 | return "#10b981"; | ||
| 35 | }; | ||
| 36 | |||
| 37 | return ( | ||
| 38 | <div className="action-bar"> | ||
| 39 | <div className="action-bar-left"> | ||
| 40 | <div className="token-indicator"> | ||
| 41 | <div className="token-bar"> | ||
| 42 | <div | ||
| 43 | className="token-fill" | ||
| 44 | style={{ | ||
| 45 | width: `${usagePercent}%`, | ||
| 46 | backgroundColor: getBarColor(), | ||
| 47 | }} | ||
| 48 | /> | ||
| 49 | </div> | ||
| 50 | <span className="token-label"> | ||
| 51 | {(totalTokens / 1000).toFixed(1)}k / 200k | ||
| 52 | </span> | ||
| 53 | </div> | ||
| 54 | |||
| 55 | {phase === "implement" && ( | ||
| 56 | <label className="permission-toggle"> | ||
| 57 | <input | ||
| 58 | type="checkbox" | ||
| 59 | checked={permissionMode === "bypassPermissions"} | ||
| 60 | onChange={(e) => | ||
| 61 | onPermissionModeChange( | ||
| 62 | e.target.checked ? "bypassPermissions" : "acceptEdits" | ||
| 63 | ) | ||
| 64 | } | ||
| 65 | disabled={disabled} | ||
| 66 | /> | ||
| 67 | Bypass Permissions | ||
| 68 | </label> | ||
| 69 | )} | ||
| 70 | </div> | ||
| 71 | |||
| 72 | <div className="action-bar-right"> | ||
| 73 | {phase !== "implement" && ( | ||
| 74 | <> | ||
| 75 | <button | ||
| 76 | onClick={onReview} | ||
| 77 | disabled={disabled || isLoading || !hasChanges} | ||
| 78 | className="btn-secondary" | ||
| 79 | > | ||
| 80 | Review | ||
| 81 | </button> | ||
| 82 | <button | ||
| 83 | onClick={onSubmit} | ||
| 84 | disabled={disabled || isLoading} | ||
| 85 | className="btn-primary" | ||
| 86 | > | ||
| 87 | Submit → | ||
| 88 | </button> | ||
| 89 | </> | ||
| 90 | )} | ||
| 91 | {phase === "implement" && isLoading && ( | ||
| 92 | <span className="implementing-status">Implementing...</span> | ||
| 93 | )} | ||
| 94 | </div> | ||
| 95 | </div> | ||
| 96 | ); | ||
| 97 | } | ||
