From 0feccd0ad96c67db4c147676de034105844bfe13 Mon Sep 17 00:00:00 2001 From: harsh mahajan Date: Wed, 2 Sep 2026 10:18:24 +0530 Subject: [PATCH 1/5] fix(console): make the new Console banner responsive and snoozeable Three fixes found while testing on production. Responsive: the layout switched to a column at isSmallViewport (max-width 767px) but Button's .is-full-width-mobile applies at max-width 768px. At exactly 768px the row stayed horizontal while the button took the full line, crushing the copy into a ~90px column seven lines tall. Switched the direction to isTabletViewport and dropped fullWidthMobile so the button sizes to its content. 768px goes from 182px tall to 96px. Dismissal: closing the banner wrote a localStorage key that was never cleared, so one click removed the message for the entire migration. Now uses hideNotification with a one week cool-off and exponential backoff, and shouldShowNotification to gate registration. Repeated dismissals still fade it out, but a stray click no longer opts the user out permanently. Resize: AlertStack owns the shell offset for alerts inside it but only re-measured via ResizeObserver and afterNavigate. GradientBanner used to compensate with its own window resize handler, which no longer runs when a stack is in charge, so resizing left the header overlapping the banner. Added the resize listener to AlertStack, which also covers HeaderAlert. --- src/lib/components/newConsoleBanner.svelte | 15 ++++++++++----- src/lib/layout/alertStack.svelte | 4 ++++ src/routes/(console)/+layout.svelte | 3 ++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib/components/newConsoleBanner.svelte b/src/lib/components/newConsoleBanner.svelte index 82857f99c3..b59873a1c8 100644 --- a/src/lib/components/newConsoleBanner.svelte +++ b/src/lib/components/newConsoleBanner.svelte @@ -2,7 +2,8 @@ import { trackEvent } from '$lib/actions/analytics'; import { Button } from '$lib/elements/forms'; import { Layout, Typography } from '@appwrite.io/pink-svelte'; - import { isSmallViewport } from '$lib/stores/viewport'; + import { isTabletViewport } from '$lib/stores/viewport'; + import { hideNotification } from '$lib/helpers/notifications'; import { headerAlert } from '$lib/stores/headerAlert'; import { activeHeaderAlert } from '$routes/(console)/store'; import GradientBanner from './billing/gradientBanner.svelte'; @@ -13,7 +14,11 @@ function handleClose() { const { id } = $activeHeaderAlert; - localStorage.setItem(id, new Date().getTime().toString()); + + // A migration runs for months, so dismissal is a snooze rather than a permanent opt-out: + // a week at first, doubling each time. Someone who keeps closing it stops seeing it, but a + // single stray click on the X does not remove the message for the whole rollout. + hideNotification(id, { coolOffPeriod: 24 * 7, exponentialBackoff: true }); trackEvent('close_new_console_banner', { source: 'new_console_banner' }); // Clear the store entry, not just this component. headerAlert.get() picks the highest @@ -28,15 +33,15 @@ gap="m" alignItems="center" alignContent="center" - direction={$isSmallViewport ? 'column' : 'row'}> - + justifyContent="center" + direction={$isTabletViewport ? 'column' : 'row'}> + Introducing the new Appwrite Console, rebuilt from the ground up.