fix(mail): legend rows justify-between + per-connection chart sparse-data zoom
1. Donut-Legend-Rows als space-between: Name links + dot, Count rechts. Vorher: alle Elemente eng aneinander (gap:6), Count direkt nach Name. Jetzt: feste Legend-Width 180px, jede Row hat Name+Dot links (flex:1) und Count rechts mit Whitespace dazwischen. 2. Per-Connection-Bar-Chart in Account-Card: sparse-data-zoom. Vorher: bei nonEmpty.length > 0 && days <= 7 wurde gezoomt — bei 30-Tage- Range mit nur 1-2 Hits passierte das aber NICHT → 30 leere Bars + 1 Bar ganz rechts (Screenshot bei GMX-expanded). Jetzt: zoom IMMER wenn nonEmpty.length * 3 < raw.length (= mehr als 2/3 der Range sind leer). Trim auf die echte Hit-Range. User sieht damit nur die Tage mit Daten + die paar dazwischen, statt 30 leere Slots. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
aac6c00720
commit
b47ac2427e
@ -112,7 +112,7 @@ export function MailDistributionChart({ data, hero, totalBlocked, isLegend }: Pr
|
||||
centerLabel={centerLabel}
|
||||
width={DONUT_WIDTH}
|
||||
/>
|
||||
<View style={{ gap: 6 }}>
|
||||
<View style={{ gap: 6, width: 180 }}>
|
||||
{slices.map((slice) => (
|
||||
<LegendRow key={slice.label} slice={slice} colors={colors} />
|
||||
))}
|
||||
@ -159,26 +159,35 @@ function LegendRow({
|
||||
colors: ReturnType<typeof useColors>;
|
||||
}) {
|
||||
return (
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
|
||||
<View
|
||||
style={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: slice.color,
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontFamily: slice.isOther ? 'Nunito_400Regular' : 'Nunito_600SemiBold',
|
||||
color: slice.isOther ? colors.textMuted : colors.text,
|
||||
maxWidth: 160,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{slice.label}
|
||||
</Text>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 6, flex: 1, minWidth: 0 }}>
|
||||
<View
|
||||
style={{
|
||||
width: 8,
|
||||
height: 8,
|
||||
borderRadius: 4,
|
||||
backgroundColor: slice.color,
|
||||
}}
|
||||
/>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
fontFamily: slice.isOther ? 'Nunito_400Regular' : 'Nunito_600SemiBold',
|
||||
color: slice.isOther ? colors.textMuted : colors.text,
|
||||
flexShrink: 1,
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{slice.label}
|
||||
</Text>
|
||||
</View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 12,
|
||||
|
||||
@ -73,8 +73,10 @@ export function useMailConnectionStats(
|
||||
data = aggregateToWeeks(raw);
|
||||
} else if (granularity === 'month') {
|
||||
data = aggregateToMonths(raw);
|
||||
} else if (nonEmpty.length > 0 && days <= 7) {
|
||||
// Short window: keep only days with data + days between first and last hit
|
||||
} else if (nonEmpty.length > 0 && nonEmpty.length * 3 < raw.length) {
|
||||
// Sparse data (z.B. nur 1-2 Tage von 30): zoom in auf die echte Range
|
||||
// zwischen erstem und letztem Hit. Vermeidet 30 leere Bars + 1 Bar
|
||||
// ganz rechts wie bei einer frischen Outlook-Connection.
|
||||
const firstDate = nonEmpty[0].date;
|
||||
const lastDate = nonEmpty[nonEmpty.length - 1].date;
|
||||
data = raw.filter((e) => e.date >= firstDate && e.date <= lastDate);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user