From 85f034b144ea17f90319b76d2c7d0feaa491eaa5 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 4 Oct 2024 17:04:22 +1000 Subject: [PATCH] Split true retention into multiple tables; display vertically This prevents the page scrolling off screen on small devices. This is a quick fix, and further tweaks to the layout are welcome. --- ts/routes/graphs/TrueRetention.svelte | 1 - ts/routes/graphs/true-retention.ts | 111 ++++++++++++++------------ 2 files changed, 62 insertions(+), 50 deletions(-) diff --git a/ts/routes/graphs/TrueRetention.svelte b/ts/routes/graphs/TrueRetention.svelte index 37af98116e..b9a3f0efc4 100644 --- a/ts/routes/graphs/TrueRetention.svelte +++ b/ts/routes/graphs/TrueRetention.svelte @@ -35,6 +35,5 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html .true-retention-table { overflow-x: auto; margin-top: 1rem; - display: flex; } diff --git a/ts/routes/graphs/true-retention.ts b/ts/routes/graphs/true-retention.ts index 8aa5079a89..34160ec107 100644 --- a/ts/routes/graphs/true-retention.ts +++ b/ts/routes/graphs/true-retention.ts @@ -20,69 +20,82 @@ function calculateRetention(passed: number, failed: number): string { return localizedNumber((passed / total) * 100, 1) + "%"; } -function createStatsRow(name: string, data: TrueRetentionData): string { - const youngRetention = calculateRetention(data.youngPassed, data.youngFailed); - const matureRetention = calculateRetention(data.maturePassed, data.matureFailed); - const totalPassed = data.youngPassed + data.maturePassed; - const totalFailed = data.youngFailed + data.matureFailed; - const totalRetention = calculateRetention(totalPassed, totalFailed); +enum Scope { + Young, + Mature, + Total, +} + +function createStatsRow(period: string, data: TrueRetentionData, scope: Scope): string { + let pass: number, fail: number, retention: string; + switch (scope) { + case Scope.Young: + pass = data.youngPassed; + fail = data.youngFailed; + retention = calculateRetention(data.youngPassed, data.youngFailed); + break; + case Scope.Mature: + pass = data.maturePassed; + fail = data.matureFailed; + retention = calculateRetention(data.maturePassed, data.matureFailed); + break; + case Scope.Total: + pass = data.youngPassed + data.maturePassed; + fail = data.youngFailed + data.matureFailed; + retention = calculateRetention(pass, fail); + break; + } return ` - ${name} - ${localizedNumber(data.youngPassed)} - ${localizedNumber(data.youngFailed)} - ${youngRetention} - ${localizedNumber(data.maturePassed)} - ${localizedNumber(data.matureFailed)} - ${matureRetention} - ${localizedNumber(totalPassed)} - ${localizedNumber(totalFailed)} - ${totalRetention} + ${period} + ${localizedNumber(pass)} + ${localizedNumber(fail)} + ${retention} `; } export function renderTrueRetention(data: GraphsResponse, revlogRange: RevlogRange): string { const trueRetention = data.trueRetention!; - - const tableContent = ` + let output = ""; + for (const scope of Object.values(Scope)) { + if (typeof scope === "string") { continue; } + const tableContent = ` - - - - - - - + + + + - - - - - - - - - - - - ${createStatsRow(tr.statisticsTrueRetentionToday(), trueRetention.today!)} - ${createStatsRow(tr.statisticsTrueRetentionYesterday(), trueRetention.yesterday!)} - ${createStatsRow(tr.statisticsTrueRetentionWeek(), trueRetention.week!)} - ${createStatsRow(tr.statisticsTrueRetentionMonth(), trueRetention.month!)} + ${createStatsRow(tr.statisticsTrueRetentionToday(), trueRetention.today!, scope)} + ${createStatsRow(tr.statisticsTrueRetentionYesterday(), trueRetention.yesterday!, scope)} + ${createStatsRow(tr.statisticsTrueRetentionWeek(), trueRetention.week!, scope)} + ${createStatsRow(tr.statisticsTrueRetentionMonth(), trueRetention.month!, scope)} ${ - revlogRange === RevlogRange.Year - ? createStatsRow(tr.statisticsTrueRetentionYear(), trueRetention.year!) - : createStatsRow(tr.statisticsTrueRetentionAllTime(), trueRetention.allTime!) - } + revlogRange === RevlogRange.Year + ? createStatsRow(tr.statisticsTrueRetentionYear(), trueRetention.year!, scope) + : createStatsRow(tr.statisticsTrueRetentionAllTime(), trueRetention.allTime!, scope) + }
${tr.statisticsTrueRetentionRange()}${tr.statisticsReviewsTitle()}
${tr.statisticsCountsYoungCards()}${tr.statisticsCountsMatureCards()}${tr.statisticsCountsTotalCards()}${scopeRange(scope)}${tr.statisticsTrueRetentionPass()}${tr.statisticsTrueRetentionFail()}${tr.statisticsTrueRetentionRetention()}
${tr.statisticsTrueRetentionPass()}${tr.statisticsTrueRetentionFail()}${tr.statisticsTrueRetentionRetention()}${tr.statisticsTrueRetentionPass()}${tr.statisticsTrueRetentionFail()}${tr.statisticsTrueRetentionRetention()}${tr.statisticsTrueRetentionPass()}${tr.statisticsTrueRetentionFail()}${tr.statisticsTrueRetentionRetention()}
`; + output += tableContent; + } - return tableContent; + return output; +} +function scopeRange(scope: Scope) { + switch (scope) { + case Scope.Young: + return tr.statisticsCountsYoungCards(); + case Scope.Mature: + return tr.statisticsCountsMatureCards(); + case Scope.Total: + return tr.statisticsTotal(); + } }