From 76bd05f228347d64071871ab587db8dd29f2fff4 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 20 Aug 2026 16:59:07 -0700 Subject: [PATCH] Dashboard: let the trial be a detail line, not an alarm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Usage card gives each of its three columns a meter and two lines. The plan column had a boxed, tinted, bordered paragraph instead — and at the ~230px a third of that card comes to, thirty words of it wrapped into a five-line ribbon standing twice as tall as the storage and resources meters beside it. The box is the shape we use for the dunning banner. A trial is a date you should know about, not a fault, and it was reading as the loudest thing on the card. So it takes the slot its neighbours use for "n% of 100 GB": a quiet hint- coloured line under the badge. All three columns now measure the same. The copy stopped repeating itself while it was there. The badge said "ends Sep 20" and the sentence beneath it said "ends on September 20, 2026" — two elements, one fact, and neither of them answering the question someone actually has, which is how much room is left to decide. The badge now carries "31 days left" and the line under it carries the consequence: "First charge Sep 20 unless you cancel." Billing keeps the full sentence and the opt-out, and Manage is directly below. --- src/gui/src/UI/Dashboard/TabHome.js | 38 +++++++++++++++++++++-------- src/gui/src/css/dashboard.css | 25 ++++++++++++------- 2 files changed, 44 insertions(+), 19 deletions(-) diff --git a/src/gui/src/UI/Dashboard/TabHome.js b/src/gui/src/UI/Dashboard/TabHome.js index 1f20c83e1..55ae12371 100644 --- a/src/gui/src/UI/Dashboard/TabHome.js +++ b/src/gui/src/UI/Dashboard/TabHome.js @@ -91,6 +91,7 @@ function buildUsageHTML() { ''; h += ''; h += ''; + h += ''; h += ''; h += ''; @@ -133,13 +134,21 @@ function buildUsageHTML() { return h; } -// Trial end date in two lengths: `short` for the badge, `long` for the -// sentence under it. Returns null when the subscription carries no end date, +// Trial end date in two lengths — `short` for the note under the badge, +// `long` for anywhere with room for a sentence — plus `countdown`, which is +// what the badge carries: a date says when, only a countdown says how long +// there is to decide. Returns null when the subscription carries no end date, // so callers fall back to unqualified "Free trial" wording. function formatTrialEnd(trialEndsAt) { if (!Number.isFinite(trialEndsAt)) return null; const date = new Date(trialEndsAt); if (Number.isNaN(date.getTime())) return null; + // Rounded up, so a trial with any time on it never reads "0 days left" + // before the day it actually converts. + const days = Math.max( + 0, + Math.ceil((date.getTime() - Date.now()) / 86400000), + ); return { short: date.toLocaleDateString(undefined, { month: 'short', @@ -150,6 +159,13 @@ function formatTrialEnd(trialEndsAt) { month: 'long', day: 'numeric', }), + days, + countdown: + days === 0 + ? 'ends today' + : days === 1 + ? '1 day left' + : `${days} days left`, }; } @@ -457,8 +473,8 @@ const TabHome = { const $warning = $el_window .find('.bento-plan-warning') .hide() - .removeClass('info') .text(''); + const $note = $el_window.find('.bento-plan-note').hide().text(''); if (hasSubscription) { if (pastDue) { @@ -469,22 +485,24 @@ const TabHome = { ) .show(); } else if (trialing) { - // A trial grants the full tier and then continues as a paid - // plan, so say when that happens and where to opt out. + // This is a glance surface sitting between two usage + // meters, so the trial gets the same two lines they get: + // how much is left, then the one consequence worth + // knowing. Billing carries the full sentence and the + // opt-out — "Manage →" is directly below. $badge .text( trialEnds - ? `Free trial — ends ${trialEnds.short}` + ? `Free trial · ${trialEnds.countdown}` : 'Free trial', ) .addClass('trial'); - $warning + $note .text( trialEnds - ? `Your free trial ends on ${trialEnds.long}, after which the plan continues at the usual monthly price. Cancel any time before then under Billing.` - : 'When your free trial ends the plan continues at the usual monthly price. Cancel any time before then under Billing.', + ? `First charge ${trialEnds.short} unless you cancel.` + : 'Continues as a paid plan when the trial ends.', ) - .addClass('info') .show(); } else { $badge.text('Current').addClass('active'); diff --git a/src/gui/src/css/dashboard.css b/src/gui/src/css/dashboard.css index cd3e3a752..e6f5b5b0a 100644 --- a/src/gui/src/css/dashboard.css +++ b/src/gui/src/css/dashboard.css @@ -5197,9 +5197,10 @@ body.myapps-reordering .myapps-tile { gap: 24px; } -/* Three even columns need real width. Below that the plan column lands around - 230px, which wraps its badge and renewal notice into a tall ribbon — so give - the plan its own row and let the two usage meters share the next one. */ +/* Three even columns need real width. Below that, give the plan its own row + and let the two usage meters share the next one — they are the pair that + reads as a set, and splitting them to put the plan beside one of them makes + the row look accidental. */ @media (max-width: 1200px) { .dashboard .bento-usage-grid { grid-template-columns: 1fr 1fr; @@ -5272,12 +5273,18 @@ body.myapps-reordering .myapps-tile { line-height: 1.4; } -/* Time-boxed but not broken — a trial notice reads as advisory, not as the - red dunning banner and not as an amber warning either. */ -.dashboard .bento-plan-warning.info { - color: var(--dashboard-notice-text); - background: var(--dashboard-notice-background); - border-color: var(--dashboard-notice-border); +/* Time-boxed but not broken. A boxed, tinted, bordered panel is the shape of + an alarm, and in a ~230px column it wrapped a trial into a five-line ribbon + that stood twice as tall as the storage and resources meters beside it. A + trial is a date, not a fault: it reads as the quiet detail line under the + badge, exactly where those two columns put their "n% of X". The box stays + for the dunning banner, which has earned it. */ +.dashboard .bento-plan-note { + display: block; + margin-top: 6px; + font-size: 13px; + line-height: 1.45; + color: var(--dashboard-text-hint); } .dashboard .bento-plan-upgrade {