From afdd7b85fea898690799bacfec334dbf64ee90ce Mon Sep 17 00:00:00 2001 From: Marcel Veselka Date: Thu, 4 Jun 2026 07:09:15 +0200 Subject: [PATCH] =?UTF-8?q?Revert=20"feat(home):=20hero=20redesign=20?= =?UTF-8?q?=E2=80=94=20full-screen=20form=20over=20a=20faint=20demo-video?= =?UTF-8?q?=20backdrop=20(#230)"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit bb0f4d0a7a5f38bf5e50fbe6de2f7fea52b7f814. --- src/components/home-page/HeroVideoInline.tsx | 77 ----- src/components/home-page/HeroVideoModal.tsx | 77 +---- src/components/home-page/HomeHeroVibe.tsx | 289 ++++++++----------- src/css/custom.css | 3 - 4 files changed, 133 insertions(+), 313 deletions(-) delete mode 100644 src/components/home-page/HeroVideoInline.tsx diff --git a/src/components/home-page/HeroVideoInline.tsx b/src/components/home-page/HeroVideoInline.tsx deleted file mode 100644 index d2bee76..0000000 --- a/src/components/home-page/HeroVideoInline.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React, { useEffect, useRef, useState } from "react"; -import { Maximize2 } from "lucide-react"; - -interface HeroVideoInlineProps { - sources: string[]; - poster?: string; - onExpand?: () => void; - className?: string; - aspectClassName?: string; -} - -// Muted autoplay loop of the demo clips, cycling through `sources`. Muting is -// required for browsers to allow autoplay without a user gesture; onExpand -// opens the fullscreen modal with sound + controls. -const HeroVideoInline: React.FC = ({ - sources, - poster, - onExpand, - className = "", - aspectClassName = "aspect-video", -}) => { - const [index, setIndex] = useState(0); - const videoRef = useRef(null); - - useEffect(() => { - videoRef.current?.play().catch(() => {}); - }, [index]); - - const currentSrc = sources[index]; - - return ( -
- {/* gradient frame, faded in on hover */} -
- ); -}; - -export default HeroVideoInline; diff --git a/src/components/home-page/HeroVideoModal.tsx b/src/components/home-page/HeroVideoModal.tsx index 65ba693..1c88f2e 100644 --- a/src/components/home-page/HeroVideoModal.tsx +++ b/src/components/home-page/HeroVideoModal.tsx @@ -1,22 +1,14 @@ import React, { useEffect, useRef, useState } from "react"; import { X } from "lucide-react"; -interface HeroVideoStep { - number?: number; - title: string; - subtitle?: string; -} - interface HeroVideoModalProps { sources: string[]; - steps?: HeroVideoStep[]; isOpen: boolean; onClose: () => void; } const HeroVideoModal: React.FC = ({ sources, - steps, isOpen, onClose, }) => { @@ -54,7 +46,6 @@ const HeroVideoModal: React.FC = ({ if (!isOpen) return null; const currentSrc = sources[index]; - const hasSteps = !!steps && steps.length === sources.length; return (
= ({ aria-label="Product walkthrough video" >
e.stopPropagation()} >
); diff --git a/src/components/home-page/HomeHeroVibe.tsx b/src/components/home-page/HomeHeroVibe.tsx index 4a98d47..002e0b4 100644 --- a/src/components/home-page/HomeHeroVibe.tsx +++ b/src/components/home-page/HomeHeroVibe.tsx @@ -2,7 +2,6 @@ import React, { useRef, useState, useEffect } from "react"; import { Globe, AppWindow, - FlaskConical, Landmark, ShoppingCart, Play, @@ -10,7 +9,6 @@ import { Sparkles, ChevronDown, Check, - CheckCircle2, } from "lucide-react"; import { Button } from "@/components/ui/button"; @@ -18,9 +16,7 @@ import { Button } from "@/components/ui/button"; import { AppType } from "./vibe/enums"; import LoginDialog from "./vibe/LoginDialog"; import HeroVideoModal from "./HeroVideoModal"; -import HeroVideoInline from "./HeroVideoInline"; import HeroTrustedByStrip from "./HeroTrustedByStrip"; -import { stepsData } from "../../data/steps"; const appTemplates = { [AppType.WEBSITE]: { @@ -74,9 +70,11 @@ const DEMO_SCENARIOS: AppType[] = [ const URL_REGEX = /^(https?:\/\/)?(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/; -// Same clips (and order) as the "How it works" section, so the fullscreen -// modal can label each fragment with its step title/subtitle. -const heroVideoSources = stepsData.map((s) => s.videoSrc); +const heroVideoSources = [ + "/how-it-works/step-1.webm", + "/how-it-works/step-2.webm", + "/how-it-works/step-3.webm", +]; const HomeHeroVibe = () => { const [appUrl, setAppUrl] = useState(appTemplates[defaultTemplate].url); @@ -137,9 +135,10 @@ const HomeHeroVibe = () => { const triggerDemo = DEMO_SCENARIOS.includes(appType) ? appType : AppType.E_COMMERCE; + const TriggerIcon = appTemplates[triggerDemo].icon; return ( -
+
{ }} /> -
-
+
+
+ · + + + Watch demo + +

AI Testing Agents @@ -175,125 +183,13 @@ const HomeHeroVibe = () => {

-
- {/* Faint demo video backdrop behind the content. */} - setVideoOpen(true)} - className="col-start-1 row-start-1 z-0 w-[104%]" - aspectClassName="aspect-video" - /> -
-

- {"Enter a URL, choose what to test, and Wopee's AI agent creates runnable tests with screenshots, checks, and self-healing steps."} -

-
+
+
-
- - {/* App selector — segmented "Your app" / "Demo app" toggle. - "Demo app" switches to a demo and opens the picker so a - specific demo (Website / E-commerce / Banking) stays - selectable. */} -
-
handleAppTypeChange(AppType.YOUR_APPLICATION)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - handleAppTypeChange(AppType.YOUR_APPLICATION); - } - }} - className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold leading-none cursor-pointer select-none transition-all ${ - appType === AppType.YOUR_APPLICATION - ? "bg-secondary-wopee text-white shadow-sm" - : "text-secondary-wopee/70 hover:text-secondary-wopee hover:bg-secondary-wopee/10 dark:text-white/70 dark:hover:text-white dark:hover:bg-white/10" - }`} - > - - Your app -
-
-
{ - if (!DEMO_SCENARIOS.includes(appType)) { - handleAppTypeChange(triggerDemo); - } - setDemoMenuOpen((open) => !open); - }} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - if (!DEMO_SCENARIOS.includes(appType)) { - handleAppTypeChange(triggerDemo); - } - setDemoMenuOpen((open) => !open); - } - }} - className={`inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md text-xs font-semibold leading-none cursor-pointer select-none transition-all ${ - DEMO_SCENARIOS.includes(appType) - ? "bg-secondary-wopee text-white shadow-sm" - : "text-secondary-wopee/70 hover:text-secondary-wopee hover:bg-secondary-wopee/10 dark:text-white/70 dark:hover:text-white dark:hover:bg-white/10" - }`} - > - - Demo app - -
- {demoMenuOpen && ( -
- {DEMO_SCENARIOS.map((type) => { - const tpl = appTemplates[type]; - const Icon = tpl.icon; - const selected = appType === type; - return ( -
handleAppTypeChange(type)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - handleAppTypeChange(type); - } - }} - className={`flex items-center gap-2 px-3 py-1.5 text-[11px] cursor-pointer select-none transition-colors hover:bg-gray-100 dark:hover:bg-gray-800 ${selected ? "text-secondary-wopee dark:text-primary-wopee font-semibold" : "text-gray-700 dark:text-gray-300"}`} - > - - {tpl.label} - {selected && ( - - )} -
- ); - })} -
- )} -
-
-
+
{ })()}
-
+
+ {/* Your app chip on the left, then "or try a demos:" label, + then a single expander showing the selected demo. Clicking + it reveals the three demo options; picking one pre-fills URL + + instructions and collapses the menu. One click on "Your + app" returns to the empty custom-URL state. */} +
+ {(() => { + const tpl = appTemplates[AppType.YOUR_APPLICATION]; + const Icon = tpl.icon; + // "Your app" is only visually selected once the visitor has + // typed a URL in Your-app mode — otherwise the chip would + // read as active on landing while the CTA is disabled. + const selected = + appType === AppType.YOUR_APPLICATION && appUrl.length > 0; + return ( +
+ handleAppTypeChange(AppType.YOUR_APPLICATION) + } + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleAppTypeChange(AppType.YOUR_APPLICATION); + } + }} + className={`scenario-chip ${selected ? "scenario-chip--selected" : ""} inline-flex items-center gap-1 px-1.5 py-0.5 rounded text-[11px] font-normal cursor-pointer select-none transition-colors`} + aria-label={tpl.label} + > + + {tpl.label} +
+ ); + })()} + + or try a demos: + +
+ + {demoMenuOpen && ( +
+ {DEMO_SCENARIOS.map((type) => { + const tpl = appTemplates[type]; + const Icon = tpl.icon; + const selected = appType === type; + return ( +
handleAppTypeChange(type)} + onKeyDown={(e) => { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + handleAppTypeChange(type); + } + }} + className={`flex items-center gap-2 px-3 py-1.5 text-[11px] cursor-pointer select-none transition-colors hover:bg-gray-100 dark:hover:bg-gray-800 ${selected ? "text-secondary-wopee dark:text-primary-wopee font-semibold" : "text-gray-700 dark:text-gray-300"}`} + > + + {tpl.label} + {selected && ( + + )} +
+ ); + })} +
+ )} +
+
+
-
- - - Free to start - - - - No credit card required - - - - Works with your Playwright setup - -
- -
-
- {/* Watch-demo affordance over the video below the form. */} -
setVideoOpen(true)} - onKeyDown={(e) => { - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - setVideoOpen(true); - } - }} - aria-label="Watch 90-second demo" - className="group/play inline-flex items-center gap-2.5 cursor-pointer text-white/60 transition-colors duration-300 hover:text-white" - > - - - - Watch 90-sec demo
@@ -429,7 +383,6 @@ const HomeHeroVibe = () => { setVideoOpen(false)} /> diff --git a/src/css/custom.css b/src/css/custom.css index 0619c90..d190ed1 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -397,9 +397,6 @@ body.is-home .navbar.navbar--revealed { background-color: rgb(0 0 0 / 0.05); color: rgb(75 85 99); /* gray-600 */ border: 1px solid rgb(0 0 0 / 0.08); - /* Normalise line-height so the
"Your app" chip and the