diff --git a/src/tui/components/ItemsEditor.tsx b/src/tui/components/ItemsEditor.tsx index d68fbdc..caeaaaf 100644 --- a/src/tui/components/ItemsEditor.tsx +++ b/src/tui/components/ItemsEditor.tsx @@ -48,7 +48,7 @@ export const ItemsEditor: React.FC = ({ widgets, onUpdate, onB const [customEditorWidget, setCustomEditorWidget] = useState(null); const [widgetPicker, setWidgetPicker] = useState(null); const [showClearConfirm, setShowClearConfirm] = useState(false); - const separatorChars = ['|', '-', ',', ' ']; + const separatorChars = ['|', '-', ',', ' ', '·']; const widgetCatalog = getWidgetCatalog(settings); const widgetCategories = ['All', ...getWidgetCatalogCategories(widgetCatalog)]; diff --git a/src/utils/renderer.ts b/src/utils/renderer.ts index 546f30d..3dc0562 100644 --- a/src/utils/renderer.ts +++ b/src/utils/renderer.ts @@ -469,6 +469,8 @@ function formatSeparator(sep: string): string { return ', '; } else if (sep === '-') { return ' - '; + } else if (sep === '·') { + return '·'; } return sep; } diff --git a/src/utils/usage-prefetch.ts b/src/utils/usage-prefetch.ts index 9b6e9d9..37b36df 100644 --- a/src/utils/usage-prefetch.ts +++ b/src/utils/usage-prefetch.ts @@ -6,6 +6,7 @@ import { fetchUsageData } from './usage'; const USAGE_WIDGET_TYPES = new Set([ 'session-usage', 'weekly-usage', + 'weekly-usage-projected', 'block-timer', 'reset-timer', 'weekly-reset-timer' diff --git a/src/utils/widget-manifest.ts b/src/utils/widget-manifest.ts index ef3011b..1ca85fe 100644 --- a/src/utils/widget-manifest.ts +++ b/src/utils/widget-manifest.ts @@ -49,6 +49,7 @@ export const WIDGET_MANIFEST: WidgetManifestEntry[] = [ { type: 'free-memory', create: () => new widgets.FreeMemoryWidget() }, { type: 'session-usage', create: () => new widgets.SessionUsageWidget() }, { type: 'weekly-usage', create: () => new widgets.WeeklyUsageWidget() }, + { type: 'weekly-usage-projected', create: () => new widgets.ProjectedWeeklyUsageWidget() }, { type: 'reset-timer', create: () => new widgets.BlockResetTimerWidget() }, { type: 'weekly-reset-timer', create: () => new widgets.WeeklyResetTimerWidget() }, { type: 'context-bar', create: () => new widgets.ContextBarWidget() }, diff --git a/src/widgets/ProjectedWeeklyUsage.ts b/src/widgets/ProjectedWeeklyUsage.ts new file mode 100644 index 0000000..a567961 --- /dev/null +++ b/src/widgets/ProjectedWeeklyUsage.ts @@ -0,0 +1,51 @@ +import type { RenderContext } from '../types/RenderContext'; +import type { Settings } from '../types/Settings'; +import type { + Widget, + WidgetEditorDisplay, + WidgetItem +} from '../types/Widget'; +import { + getUsageErrorMessage, + getWeeklyUsageWindowFromResetAt +} from '../utils/usage-windows'; + +import { formatRawOrLabeledValue } from './shared/raw-or-labeled'; + +export class ProjectedWeeklyUsageWidget implements Widget { + getDefaultColor(): string { return 'yellow'; } + getDescription(): string { return 'Projects weekly usage percentage by end of 7-day window'; } + getDisplayName(): string { return 'Weekly Usage Projected'; } + getCategory(): string { return 'Usage'; } + + getEditorDisplay(_item: WidgetItem): WidgetEditorDisplay { + return { + displayText: this.getDisplayName(), + modifierText: undefined + }; + } + + render(item: WidgetItem, context: RenderContext, _settings: Settings): string | null { + if (context.isPreview) { + return formatRawOrLabeledValue(item, 'Projected: ', '72%'); + } + + const data = context.usageData ?? {}; + if (data.error) + return getUsageErrorMessage(data.error); + if (data.weeklyUsage === undefined) + return null; + + const window = getWeeklyUsageWindowFromResetAt(data.weeklyResetAt); + if (!window || window.elapsedPercent < 1) { + return null; + } + + const projected = data.weeklyUsage / (window.elapsedPercent / 100); + + return formatRawOrLabeledValue(item, 'Projected: ', `${projected.toFixed(0)}%`); + } + + supportsRawValue(): boolean { return true; } + supportsColors(_item: WidgetItem): boolean { return true; } +} \ No newline at end of file diff --git a/src/widgets/index.ts b/src/widgets/index.ts index 13fc932..a7f02b4 100644 --- a/src/widgets/index.ts +++ b/src/widgets/index.ts @@ -29,6 +29,7 @@ export { FreeMemoryWidget } from './FreeMemory'; export { SessionNameWidget } from './SessionName'; export { SessionUsageWidget } from './SessionUsage'; export { WeeklyUsageWidget } from './WeeklyUsage'; +export { ProjectedWeeklyUsageWidget } from './ProjectedWeeklyUsage'; export { BlockResetTimerWidget } from './BlockResetTimer'; export { WeeklyResetTimerWidget } from './WeeklyResetTimer'; export { ContextBarWidget } from './ContextBar';