feat(ads): client banner rotation, fade UX & live toggle (PR2)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 50s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 58s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 50s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 58s
Consume the server-driven banner block (PR1) in the UI and retire the gate. - banner.ts: createScheduler — a smooth weighted round-robin over campaigns (each appears its weight share per cycle, evenly interleaved) with round-robin over a campaign's messages; the rotator drives fade-in -> hold/scroll -> fade-out -> gap -> fade-in, a lone message stays put, reduce-motion swaps instantly without scroll. - model.ts/codec.ts: Profile.banner (Banner/BannerCampaign/BannerTimings) decoded from the fbs block. - Screen.svelte: drop the compile-time SHOW_AD_BANNER; render AdBanner from app.profile.banner (campaigns + timings + reduceMotion). - AdBanner.svelte: opacity-driven fades + scroll host; the rotator is recreated when the campaigns/timings change (a `banner` notify re-fetch swaps them in place). - app.svelte.ts: on the `notify` `banner` sub-kind, refreshProfile() so the banner shows/hides in place. - tests: scheduler distribution + round-robin, the fade sequence, single-message, reduce-motion, stop(); codec banner decode. UI_DESIGN.md + trackers updated.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import type { Snippet } from 'svelte';
|
||||
import Header from './Header.svelte';
|
||||
import AdBanner from './AdBanner.svelte';
|
||||
import { app } from '../lib/app.svelte';
|
||||
import { navigate } from '../lib/router.svelte';
|
||||
|
||||
// The app-shell layout (all screens): the nav bar grows; the ad strip, content and
|
||||
@@ -27,12 +28,6 @@
|
||||
column?: boolean;
|
||||
} = $props();
|
||||
|
||||
// The promotional banner is feature-gated OFF until it is polished after release. The flag is
|
||||
// a compile-time `false`, so the {#if} branch — and with it the AdBanner import and its
|
||||
// banner.ts logic — is dead-code-eliminated from the production bundle. Flip to
|
||||
// true to bring it back.
|
||||
const SHOW_AD_BANNER = false;
|
||||
|
||||
// Edge-swipe back: a rightward drag begun in the left band returns to `back`, the standard
|
||||
// mobile gesture (instant on release — the route slide plays the animation). Listened at the
|
||||
// window in the CAPTURE phase so the board's own pointer handlers (which capture/stop the
|
||||
@@ -94,7 +89,13 @@
|
||||
|
||||
<div class="screen">
|
||||
<Header {title} {back} grow={growNav} />
|
||||
{#if SHOW_AD_BANNER}<AdBanner />{/if}
|
||||
{#if app.profile?.banner && app.profile.banner.campaigns.length}
|
||||
<AdBanner
|
||||
campaigns={app.profile.banner.campaigns}
|
||||
timings={app.profile.banner.timings}
|
||||
reduceMotion={app.reduceMotion}
|
||||
/>
|
||||
{/if}
|
||||
<main class="content" class:scroll class:fill={!growNav} class:column>{@render children?.()}</main>
|
||||
{#if tabbar}
|
||||
<nav class="tabbar">{@render tabbar()}</nav>
|
||||
|
||||
Reference in New Issue
Block a user