diff --git a/projects/packages/videopress/changelog/fix-videopress-upgrade-cta-black-button b/projects/packages/videopress/changelog/fix-videopress-upgrade-cta-black-button new file mode 100644 index 000000000000..95f1259d38cb --- /dev/null +++ b/projects/packages/videopress/changelog/fix-videopress-upgrade-cta-black-button @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Restructure the free-plan upgrade notice into a balanced Notice.Title heads-up line, a Notice.Description upsell pitch, and a concise "Upgrade" Notice.ActionButton, replacing the out-of-place dark button. diff --git a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx index ebe083924eb0..72e6f6e2d63b 100644 --- a/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx +++ b/projects/packages/videopress/src/client/admin/components/admin-page/index.tsx @@ -223,6 +223,10 @@ const UPGRADE_TRIGGER_FREE_PLAN_TEXT = __( 'The free plan includes one video upload.', 'jetpack-videopress-pkg' ); +const UPGRADE_TRIGGER_UNLOCK_TEXT = __( + 'Unlock unlimited videos, 1TB of storage, and more!', + 'jetpack-videopress-pkg' +); const UpgradeTrigger = ( { hasUsedVideo = false }: { hasUsedVideo: boolean } ) => { const { adminUri, siteSuffix } = window.jetpackVideoPressInitialState; @@ -252,24 +256,20 @@ const UpgradeTrigger = ( { hasUsedVideo = false }: { hasUsedVideo: boolean } ) = // VIDP-245: keep the `Notice.Root` children shape invariant across the // `hasUsedVideo` flip. base-ui@1.4.1's `useRenderElement` swaps between two // different ref-merge hooks depending on subtree shape, so conditionally - // mounting `` (as this did before) misaligns its stored - // fork-ref and crashes on the next upload/delete. Always render the - // Description — mirroring the modern dashboard's `free-tier-notice.tsx` — - // varying only its text, with a non-empty fallback nudge before the first - // upload so we never render an empty styled row. The two strings are hoisted - // to module scope (above) to avoid the terser i18n ternary-fold. - const description = hasUsedVideo - ? UPGRADE_TRIGGER_USED_VIDEO_TEXT - : UPGRADE_TRIGGER_FREE_PLAN_TEXT; - - const cta = __( - 'Upgrade now to unlock unlimited videos, 1TB of storage, and more!', - 'jetpack-videopress-pkg' - ); + // mounting/unmounting a `Notice` subcomponent across the flip misaligns its + // stored fork-ref and crashes on the next upload/delete. Therefore always + // render `Notice.Title`, `Notice.Description` and `Notice.Actions` — never + // wrap any of them in a `hasUsedVideo && (...)` conditional. Vary only the + // TEXT: the `title` line carries the contextual heads-up (non-empty in both + // states) while the Description holds the constant upsell pitch. The strings + // are hoisted to module scope (above) to avoid the terser i18n ternary-fold. + const title = hasUsedVideo ? UPGRADE_TRIGGER_USED_VIDEO_TEXT : UPGRADE_TRIGGER_FREE_PLAN_TEXT; + const cta = __( 'Upgrade', 'jetpack-videopress-pkg' ); return ( - { description } + { title } + { UPGRADE_TRIGGER_UNLOCK_TEXT } { cta }