feat(onboarding): extension showcase experiment on the extension step - #6679
tsahimatsliah wants to merge 7 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
b287a01 to
c4e6e61
Compare
Behind onboarding_extension_showcase (default off) the onboarding funnel's extension step swaps the explainer and demo video for a feature showcase: the funnel headline, a caption that changes per feature, a centred tab carousel and an illustrated stage, mirroring the product tour on the daily.dev homepage. Control keeps the current step untouched. The eight features are only what the extension adds on top of the web app, with the new-tab feed in the middle so the carousel opens on it and plays the same new-tab video the step already uses. The other seven illustrations are served from the webapp's public assets through fromCDN, and Storybook maps that directory so the same paths resolve there. Tabs carry data-funnel-track with a new FunnelTargetId.ExtensionFeature, so the funnel logs which feature was clicked alongside the existing download event for the experiment's analysis. Mockup-to-eng-pass: 1 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
c4e6e61 to
ac78796
Compare
…lves Painting the video step and swapping to the showcase when the flag landed showed the control arm to treatment users first, so the body now waits for the flag the way the hero step does, capped at 200ms in case boot returned no experiment features. The showcase also renders nothing for an empty feature list instead of throwing, and re-centres the selected tab once web fonts settle the pill widths. Mockup-to-eng-pass: 1 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rebelchris
left a comment
There was a problem hiding this comment.
Summary
Flag-gated (onboarding_extension_showcase, default false) swap of the onboarding extension step's explainer + demo video for a tab carousel and illustrated stage. Control markup is preserved verbatim, the step stays laptop-only via useOnboardingExtension, tracking reuses the existing data-funnel-track capture (so target_id lands as the tab's innerText, i.e. the feature label — that part checks out), and there are tests for both arms plus Storybook coverage at four laptop resolutions. Scope is clean: every file belongs to the variant.
Two things I would want resolved before this goes to a real cohort, plus some non-blocking notes. Details are inline.
Blocking
defaultFeatures.ts— the "Daily brief" caption promises behaviour the extension does not have.FunnelBrowserExtension.tsx— the 200ms flag-hold changes the control arm and does not actually close the flash it targets.
Non-blocking — manual scroll centering vs scrollIntoView, tab-set semantics/keyboard, illustration preloading, and the cross-repo duplication of the tour data.
Verification
- Read root
AGENTS.md/CLAUDE.mdand traced the step's guards (withShouldSkipStepGuard→shouldShowExtensionOnboardingisisLaptop-gated, so phone layouts are genuinely out of scope here) - Control arm compared against
mainmarkup - Analytics path traced through
useFunnelTracking'strackOnMouseCapture - Existing primitives searched (
components/tabs/TabContainer,containers/Carousel) - CI inspected (all green except
test_shared/buildstill running at review time) - Not verified: the live preview with the flag pinned on, at 1024×768 and 1440×900
Reviewed by AI.
The 200ms flag hold gated the body for every onboarding user, so control rendered an empty step on mount; an unresolved flag now falls through to control untouched, which is also what the step sits deep enough in the funnel to always get. The "Daily brief" caption promised a first-tab brief the extension does not open; it now describes the brief itself. The carousel is a real tab set (tablist/tab/tabpanel, aria-selected, roving tabindex, arrow/Home/End keys, live caption) instead of a nav of toggles, centres the selected tab with scrollIntoView, honours prefers-reduced-motion, and warms every illustration up on mount so the first click on a tab does not show an empty stage. Mockup-to-eng-pass: 1 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rebelchris
left a comment
There was a problem hiding this comment.
Re-review of 2157d95
Both blockers are properly resolved, not papered over.
- Control arm —
hasWaitedForFlag/FLAG_RESOLVE_TIMEOUT_MSare gone and the unresolved flag falls through to control, so with the flag off the step is byte-identical tomainagain. Diffed it againstmainto confirm. Thanks for saying plainly that nothing was observed behind the hold; that is the right call. - Copy — the brief caption no longer claims the first tab of the day auto-opens a brief, and it matches what the illustration shows.
- The three non-blocking items are all addressed, and the ownership/refresh story for the tour content is now recorded in the code comment rather than only in the thread.
CI is fully green on this commit.
The tab-pattern rewrite is the right shape and the keyboard coverage is good, but it picked up four small things on the way in — all non-blocking, two of them mean the a11y fix does not fully land at runtime. Details inline. I would not hold the experiment for them if you would rather fix them in a follow-up; say which and I am happy with either.
Verification
- Control render diffed against
main - Flag-loading path re-traced through
useConditionalFeature - New tests read (arrow/Home/End, reduced motion, preload, flag-loading-renders-control)
- CI green:
test_shared,test_webapp,test_extension,lint_shared,typecheck_strict_changed,build - Still not verified by me: the live preview with the flag pinned on, and a screen-reader pass over the new tab set
Reviewed by AI.
The tablist role sat on the scroll container with a layout div between it and the tabs, so the tree had no tabs to count; the role now sits on the row that holds them. The live caption region is a stable wrapper so the keyed caption inside it is announced, the illustration panel takes focus since it holds nothing focusable, arrow-key focus moves without the browser's own scroll so the effect centres once, and the preload runs once per set of sources rather than per render. Mockup-to-eng-pass: 1 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
What
Behind
onboarding_extension_showcase(default off), the onboarding funnel's extension step swaps the explainer and demo video for a feature showcase that mirrors the product tour on the daily.dev homepage:Control keeps the current step untouched.
Features
Only what the extension adds on top of the web app, with the new-tab feed in the middle so the carousel opens on it: Read it here · Daily brief · Most visited · Shortcuts · New tab feed · Companion · Reading streak · Focus mode.
The feed plays
cloudinaryOnboardingExtensionVideo(the clip the step already uses). The other seven illustrations live inpackages/webapp/public/app/assets/extension-showcase/and load throughfromCDN, the same wayHackathonHeroloads its cover; Storybook maps that directory so the same paths resolve there. Four are captured from the homepage tour, four (Most visited, Shortcuts, Companion, Focus mode) are built in the same visual language from the real product surfaces.Tracking
Tabs carry
data-funnel-track={FunnelTargetId.ExtensionFeature}, so the funnel logsclick funnel elementwith the feature label, alongside the existingdownload extensionevent.Layout
The stage is sized from the viewport height (
clamp(40rem, (100dvh - 30rem) * 2.04, 64rem)) so the whole step fits on 1440×900 and 1024×768 laptops without scrolling; on shorter screens it bottoms out at the video's width and the sticky CTA stays on screen.Verification
FunnelBrowserExtension.spec.tsx: flag off renders the video step, flag on renders the showcase.ExtensionShowcase.spec.tsx: default selection, caption and illustration swap.Components/Onboarding/Steps/BrowserExtension showcase(showcase, control, and a four-resolution comparison),Components/Onboarding/ExtensionShowcase(component playground).Notes
🤖 Generated with Claude Code
Preview domain
https://claude-extension-install-modal-r.preview.app.daily.dev