Files
paseo/packages/app/src/usage/meter.tsx
T
Mohamed Boudra e12feb633f feat(usage): show when each limit resets, and make usage rows easier to read (#8162)
The reset countdown floored to one unit, so a weekly window read "resets 2d"
from 2d 23h down to 2d 0h and looked stuck for a day; the session window had
the same problem with hours. Countdowns now use two units ("2d 23h", "4h 59m"),
and every row also shows the clock time it resets ("7:20 AM", "Sat 8:00 AM",
"Oct 31, 3:00 PM"), so users can plan work around a reset without hovering.

Rows now put the window name and percent on one line, the bar under it, and the
reset on its own full-width line, so the exact time fits at phone width in
longer languages. The pinned-row background is gone; the pin glyph, drawn in
the foreground colour when pinned, is the only pinned signal. Bars are 6px.
2026-10-29 11:24:34 +07:00

75 lines
1.8 KiB
TypeScript

import { useMemo } from "react";
import { View, type StyleProp, type ViewStyle } from "react-native";
import { StyleSheet } from "react-native-unistyles";
import { clampPct } from "./format";
import type { UsageTone } from "./types";
function fillToneStyle(tone: UsageTone) {
switch (tone) {
case "ok":
return styles.fillOk;
case "warning":
return styles.fillWarning;
case "danger":
return styles.fillDanger;
default:
return styles.fillDefault;
}
}
/**
* A window's share as a bar, coloured by its tone. `quiet` fills it with a surface colour instead,
* for summaries where a row of coloured bars would be noise. The caller sizes the track.
*/
export function UsageMeter({
percent,
tone,
quiet = false,
style,
}: {
percent: number;
tone: UsageTone;
quiet?: boolean;
style?: StyleProp<ViewStyle>;
}) {
const fillWidth = clampPct(percent);
const fillStyle = useMemo<StyleProp<ViewStyle>>(
() => [styles.fill, quiet ? styles.fillQuiet : fillToneStyle(tone), { width: `${fillWidth}%` }],
[fillWidth, quiet, tone],
);
return (
<View style={[styles.track, style]}>
<View style={fillStyle} />
</View>
);
}
const styles = StyleSheet.create((theme) => ({
track: {
height: 6,
borderRadius: 3,
backgroundColor: theme.colors.surface3,
overflow: "hidden",
},
// Follows the track, so a caller that sizes the track sizes the bar.
fill: {
height: "100%",
borderRadius: theme.borderRadius.full,
},
fillQuiet: {
backgroundColor: theme.colors.surface4,
},
fillDefault: {
backgroundColor: theme.colors.foregroundMuted,
},
fillOk: {
backgroundColor: theme.colors.statusSuccess,
},
fillWarning: {
backgroundColor: theme.colors.statusWarning,
},
fillDanger: {
backgroundColor: theme.colors.statusDanger,
},
}));