25 Commits

Author SHA1 Message Date
385ad0a8a5 Merge version_10_1781403820526 into main
Merge version_10_1781403820526 into main
2026-06-14 06:50:54 +00:00
962b917081 Remove watermark 2026-06-14 06:50:51 +00:00
da66f344d5 Merge version_10_1781403820526 into main
Merge version_10_1781403820526 into main
2026-06-14 02:24:54 +00:00
kudinDmitriyUp
43fa145079 Bob AI: Changed navbar to NavbarInline to display menu items horizon 2026-06-14 02:24:15 +00:00
a2249cfb34 Merge version_9_1781402099362 into main
Merge version_9_1781402099362 into main
2026-06-14 01:56:11 +00:00
kudinDmitriyUp
97d5ccc5e6 Bob AI: Swapped NavbarFloatingLogo for NavbarFloating to show inline 2026-06-14 01:55:32 +00:00
f0c3215725 Merge version_8_1781401909283 into main
Merge version_8_1781401909283 into main
2026-06-14 01:52:33 +00:00
kudinDmitriyUp
4281068724 Bob AI: Fix the 5-star review element in the hero section so it displays correctly witho 2026-06-14 01:52:30 +00:00
b9d7be215e Merge version_7_1781400938404 into main
Merge version_7_1781400938404 into main
2026-06-14 01:37:16 +00:00
kudinDmitriyUp
07e395b319 Bob AI: Add 5-star review under h2 in hero section 2026-06-14 01:36:34 +00:00
3b3f190ba6 Merge version_6_1781383904384 into main
Merge version_6_1781383904384 into main
2026-06-13 20:54:09 +00:00
kudinDmitriyUp
91e031e073 Bob AI: Added a 5-star review below the h2 in the hero section. 2026-06-13 20:53:24 +00:00
f2b381f5b7 Merge version_5_1781383572183 into main
Merge version_5_1781383572183 into main
2026-06-13 20:48:08 +00:00
kudinDmitriyUp
0846e1dc6c Bob AI: Add learn more button to hero section 2026-06-13 20:47:16 +00:00
6feffa039d Merge version_4_1781383069274 into main
Merge version_4_1781383069274 into main
2026-06-13 20:40:00 +00:00
kudinDmitriyUp
ce604fbd8b Bob AI: Add another button to the hero section with a leran more tha 2026-06-13 20:39:21 +00:00
7ce71f2ebd Merge version_3_1781382872550 into main
Merge version_3_1781382872550 into main
2026-06-13 20:37:21 +00:00
e0fb1f9b5a Update src/pages/HomePage.tsx 2026-06-13 20:37:17 +00:00
59926d28ec Update src/pages/HomePage/sections/Hero.tsx 2026-06-13 20:37:17 +00:00
6fd00c324b Update src/pages/HomePage/sections/Faq.tsx 2026-06-13 20:37:17 +00:00
0dca57a3ef Update src/pages/HomePage/sections/About.tsx 2026-06-13 20:37:16 +00:00
b607beaa2d Merge version_3_1781382872550 into main
Merge version_3_1781382872550 into main
2026-06-13 20:37:10 +00:00
kudinDmitriyUp
669b812d45 Bob AI: Add another button to the hero section with a learn more tha 2026-06-13 20:36:37 +00:00
ef28f59a65 Merge version_2_1781382089816 into main
Merge version_2_1781382089816 into main
2026-06-13 20:26:04 +00:00
kudinDmitriyUp
d564a6d9f4 Bob AI: Revert failed prop addition 2026-06-13 20:25:58 +00:00
8 changed files with 516 additions and 157 deletions

View File

@@ -2,16 +2,15 @@ import { Outlet } from 'react-router-dom';
import { StyleProvider } from '@/components/ui/StyleProvider';
import SiteBackgroundSlot from '@/components/ui/SiteBackgroundSlot';
import NavbarFloatingLogo from "@/components/ui/NavbarFloatingLogo";
import NavbarInline from "@/components/ui/NavbarInline";
import FooterMinimal from "@/components/sections/footer/FooterMinimal";
export default function Layout() {
return (
<StyleProvider buttonVariant="default" siteBackground="none" heroBackground="none">
<SiteBackgroundSlot />
<NavbarFloatingLogo
<NavbarInline
logo="Joseph Alexander"
logoImageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp"
navItems={[
{ name: "Work", href: "#work" },
{ name: "About", href: "#about" },

View File

@@ -1,20 +1,26 @@
// AUTO-GENERATED shell by per-section-migrate.
// Section bodies live in ./<PageBase>/sections/<X>.tsx. Edit the section
// files directly. Non-block content (wrappers, non-inlinable sections) is
// preserved inline; extracted section blocks become <XSection/> refs.
import { motion } from "motion/react";
import { StyleProvider } from "@/components/ui/StyleProvider";
import SiteBackgroundSlot from "@/components/ui/SiteBackgroundSlot";
import TestimonialTrustCard from "@/components/sections/testimonial/TestimonialTrustCard";
import HeroWorkScrollStack from "@/components/sections/hero/HeroWorkScrollStack";
import AboutTestimonialParallax from "@/components/sections/about/AboutTestimonialParallax";
import FeaturesBentoGridCta from "@/components/sections/features/FeaturesBentoGridCta";
import FaqTabbedAccordion from "@/components/sections/faq/FaqTabbedAccordion";
import ContactSplitFormParallax from "@/components/sections/contact/ContactSplitFormParallax";
import LoaderReveal from "@/components/ui/LoaderReveal";
import CornerGlowBackground from "@/components/ui/CornerGlowBackground";
import React from 'react';
import HeroSection from './HomePage/sections/Hero';
import TestimonialSection from './HomePage/sections/Testimonial';
import AboutSection from './HomePage/sections/About';
import ServicesSection from './HomePage/sections/Services';
import FaqSection from './HomePage/sections/Faq';
import ContactSection from './HomePage/sections/Contact';
export default function HomePage() {
export default function HomePage(): React.JSX.Element {
return (
<StyleProvider siteBackground="none" heroBackground="none" buttonVariant="stagger">
<LoaderReveal
imageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp"
imageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp?_wi=1"
title="Joseph Alexander"
/>
@@ -29,157 +35,17 @@ export default function HomePage() {
</motion.div>
<HeroWorkScrollStack
heroAnimationDelay={4}
tag="1 spot left this month"
title="Design that"
titleHighlight="commands attention."
description="Design engineered for performance, not just aesthetics."
descriptionMuted="I craft every visual touchpoint your brand needs to capture attention and convert it into revenue."
primaryButton={{
text: "Book a call with me",
href: "#contact",
avatarSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp",
avatarLabel: "You",
}}
sectionTag="Selected Work"
sectionTitle="Projects That Speak for Themselves"
sectionDescription="A curated selection of design work that drove real business results for ambitious brands."
items={[
{
title: "HydroFlow Product Launch",
description: "Beverage brand shoot. Every frame engineered to sell.",
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/screen-1.webp",
tag: "Product Shot",
},
{
title: "Webild Athlete Campaign",
description: "Sports tech shoot. Wearables captured in raw motion.",
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/screen-2.webp",
tag: "Photography",
},
{
title: "Maru Residence",
description: "Architectural interior shoot. Minimal compositions.",
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/screen-3.webp",
tag: "Interior Design",
},
]}
secondaryButton={{ text: "View all my projects", href: "#" }}
/>
<HeroSection />
<TestimonialTrustCard
quote="Working with Joseph felt like having a seasoned design partner who truly understood our vision for KYMA and brought it to life in ways we hadn't even imagined."
rating={5}
author="Thomas Weber — Co-founder of KYMA"
avatars={[
{ name: "Thomas Weber", imageSrc: "https://randomuser.me/api/portraits/men/75.jpg" },
]}
/>
<TestimonialSection />
<div id="about" data-section="about">
<AboutTestimonialParallax
tag="About"
quote="I don't design to decorate — I design to solve. Sharp, intentional work that moves brands forward."
author="Joseph Alexander"
role="Independent Designer"
imageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp"
socialLinks={[
{ icon: "Twitter", label: "Twitter", href: "#" },
{ icon: "Linkedin", label: "LinkedIn", href: "#" },
{ icon: "Instagram", label: "Instagram", href: "#" },
]}
/>
</div>
<AboutSection />
<div id="services" data-section="services">
<FeaturesBentoGridCta
tag="Services"
title="What I Bring to the Table"
description="End-to-end creative services designed to make your brand impossible to ignore — from the first frame to the final pixel."
features={[
{ title: "Photography", description: "Art-directed shoots that capture your brand's personality. Every image is color-graded and built to stop the scroll.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/photography.webp" },
{ title: "Product Design", description: "User-centered interfaces for apps and SaaS products. From wireframe to pixel-perfect UI — intuitive experiences that keep users coming back.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/product-design.webp" },
{ title: "Website", description: "Conversion-focused websites that look sharp and perform. Clean layouts, strategic CTAs, and responsive design that turns traffic into revenue.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/website.webp" },
{ title: "Videos", description: "Brand films and product videos engineered for engagement. Story-driven visuals that convert viewers into customers.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/videos.webp" },
]}
ctaButton={{
text: "Book a call with me",
href: "#contact",
avatarSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp",
avatarLabel: "You",
}}
/>
</div>
<ServicesSection />
<FaqTabbedAccordion
tag="FAQ"
title="Frequently Asked Questions"
description="Everything you need to know before we start working together."
categories={[
{
name: "General",
items: [
{ question: "What type of clients do you work with?", answer: "I work with ambitious brands, startups, and established businesses that value premium creative work. Whether you're launching a new product or refreshing your brand identity, I bring the same level of craft and attention to detail." },
{ question: "What's your availability like?", answer: "I typically take on 23 projects at a time to ensure each client gets my full attention. Reach out to check my current availability — I'm happy to discuss timelines." },
{ question: "Do you work remotely or on-site?", answer: "Primarily remote, but I'm open to on-site work for shoots, workshops, or strategy sessions depending on the project scope and location." },
{ question: "Can I see more examples of your work?", answer: "Absolutely. The projects on this site are a curated selection. I'm happy to share additional case studies relevant to your industry during our initial call." },
],
},
{
name: "Pricing",
items: [
{ question: "How do you structure your pricing?", answer: "I offer project-based pricing tailored to scope and deliverables. Every engagement starts with a discovery call so I can provide an accurate, transparent quote — no surprises." },
{ question: "Do you require a deposit?", answer: "Yes, I require a 50% deposit to secure your spot and begin work. The remaining balance is due upon delivery of final assets." },
{ question: "Do you offer retainer packages?", answer: "I do. For clients with ongoing creative needs, monthly retainers offer priority access, discounted rates, and faster turnaround times." },
{ question: "What's included in a typical project quote?", answer: "Quotes include all creative direction, production, editing, and delivery of final files. Revisions are built in — I want you to be thrilled with the result." },
],
},
{
name: "Process",
items: [
{ question: "What does your process look like?", answer: "Discovery call → Creative brief → Concept development → Production → Review & refinement → Final delivery. I keep you in the loop at every stage with clear timelines and checkpoints." },
{ question: "How long does a typical project take?", answer: "Most projects wrap within 24 weeks depending on complexity. Larger campaigns or multi-deliverable projects may extend further, and I'll set expectations upfront." },
{ question: "How many revisions are included?", answer: "Two rounds of revisions are standard. In practice, my clients rarely need more than one — I invest heavily in understanding your vision before production begins." },
{ question: "What do you need from me to get started?", answer: "A brief overview of your brand, goals, and any existing assets or references. I'll guide you through the rest during our kickoff call." },
],
},
{
name: "Results",
items: [
{ question: "What kind of results can I expect?", answer: "My work is designed to drive measurable outcomes — higher engagement, increased conversions, and a brand presence that commands attention. I'll share relevant case studies during our call." },
{ question: "Do you track performance metrics?", answer: "While I focus on the creative, I design everything with performance in mind. I'm happy to collaborate with your marketing team to align on KPIs and measure impact." },
{ question: "Can you share client testimonials?", answer: "Yes — I have testimonials and references available. Many of my clients see 23x improvements in engagement after implementing new creative assets." },
{ question: "What makes your work different?", answer: "I combine strategic thinking with high-end execution. Every project is approached as a partnership — I'm invested in your success, not just delivering files." },
],
},
]}
cta={{
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp",
name: "More questions? Reach out anytime.",
role: "joseph@alexandercreative.com",
buttonText: "Book a call",
buttonHref: "#contact",
}}
/>
<FaqSection />
<div id="contact" data-section="contact">
<ContactSplitFormParallax
tag="Get in Touch"
title="Let's Build"
description="Have a project in mind? Drop me a message and I'll get back to you within 24 hours."
inputs={[
{ name: "name", type: "text", placeholder: "Your name", required: true },
{ name: "email", type: "email", placeholder: "Your email", required: true }
]}
textarea={{ name: "message", placeholder: "Tell me about your project...", rows: 5, required: true }}
buttonText="Send Message"
imageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/contact.webp"
ctaLinks={[
{ icon: "Video", label: "Book a Call", href: "#" },
]}
/>
</div>
<ContactSection />
</StyleProvider>

View File

@@ -0,0 +1,24 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "about" section.
import React from 'react';
import AboutTestimonialParallax from "@/components/sections/about/AboutTestimonialParallax";
export default function AboutSection(): React.JSX.Element {
return (
<div id="about" data-section="about">
<AboutTestimonialParallax
tag="About"
quote="I don't design to decorate — I design to solve. Sharp, intentional work that moves brands forward."
author="Joseph Alexander"
role="Independent Designer"
imageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp?_wi=2"
socialLinks={[
{ icon: "Twitter", label: "Twitter", href: "#" },
{ icon: "Linkedin", label: "LinkedIn", href: "#" },
{ icon: "Instagram", label: "Instagram", href: "#" },
]}
/>
</div>
);
}

View File

@@ -0,0 +1,27 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "contact" section.
import React from 'react';
import ContactSplitFormParallax from "@/components/sections/contact/ContactSplitFormParallax";
export default function ContactSection(): React.JSX.Element {
return (
<div id="contact" data-section="contact">
<ContactSplitFormParallax
tag="Get in Touch"
title="Let's Build"
description="Have a project in mind? Drop me a message and I'll get back to you within 24 hours."
inputs={[
{ name: "name", type: "text", placeholder: "Your name", required: true },
{ name: "email", type: "email", placeholder: "Your email", required: true }
]}
textarea={{ name: "message", placeholder: "Tell me about your project...", rows: 5, required: true }}
buttonText="Send Message"
imageSrc="https://storage.googleapis.com/webild/default/templates/creative-portfolio/contact.webp"
ctaLinks={[
{ icon: "Video", label: "Book a Call", href: "#" },
]}
/>
</div>
);
}

View File

@@ -0,0 +1,62 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "faq" section.
import React from 'react';
import FaqTabbedAccordion from "@/components/sections/faq/FaqTabbedAccordion";
export default function FaqSection(): React.JSX.Element {
return (
<div id="faq" data-section="faq">
<FaqTabbedAccordion
tag="FAQ"
title="Frequently Asked Questions"
description="Everything you need to know before we start working together."
categories={[
{
name: "General",
items: [
{ question: "What type of clients do you work with?", answer: "I work with ambitious brands, startups, and established businesses that value premium creative work. Whether you're launching a new product or refreshing your brand identity, I bring the same level of craft and attention to detail." },
{ question: "What's your availability like?", answer: "I typically take on 23 projects at a time to ensure each client gets my full attention. Reach out to check my current availability — I'm happy to discuss timelines." },
{ question: "Do you work remotely or on-site?", answer: "Primarily remote, but I'm open to on-site work for shoots, workshops, or strategy sessions depending on the project scope and location." },
{ question: "Can I see more examples of your work?", answer: "Absolutely. The projects on this site are a curated selection. I'm happy to share additional case studies relevant to your industry during our initial call." },
],
},
{
name: "Pricing",
items: [
{ question: "How do you structure your pricing?", answer: "I offer project-based pricing tailored to scope and deliverables. Every engagement starts with a discovery call so I can provide an accurate, transparent quote — no surprises." },
{ question: "Do you require a deposit?", answer: "Yes, I require a 50% deposit to secure your spot and begin work. The remaining balance is due upon delivery of final assets." },
{ question: "Do you offer retainer packages?", answer: "I do. For clients with ongoing creative needs, monthly retainers offer priority access, discounted rates, and faster turnaround times." },
{ question: "What's included in a typical project quote?", answer: "Quotes include all creative direction, production, editing, and delivery of final files. Revisions are built in — I want you to be thrilled with the result." },
],
},
{
name: "Process",
items: [
{ question: "What does your process look like?", answer: "Discovery call → Creative brief → Concept development → Production → Review & refinement → Final delivery. I keep you in the loop at every stage with clear timelines and checkpoints." },
{ question: "How long does a typical project take?", answer: "Most projects wrap within 24 weeks depending on complexity. Larger campaigns or multi-deliverable projects may extend further, and I'll set expectations upfront." },
{ question: "How many revisions are included?", answer: "Two rounds of revisions are standard. In practice, my clients rarely need more than one — I invest heavily in understanding your vision before production begins." },
{ question: "What do you need from me to get started?", answer: "A brief overview of your brand, goals, and any existing assets or references. I'll guide you through the rest during our kickoff call." },
],
},
{
name: "Results",
items: [
{ question: "What kind of results can I expect?", answer: "My work is designed to drive measurable outcomes — higher engagement, increased conversions, and a brand presence that commands attention. I'll share relevant case studies during our call." },
{ question: "Do you track performance metrics?", answer: "While I focus on the creative, I design everything with performance in mind. I'm happy to collaborate with your marketing team to align on KPIs and measure impact." },
{ question: "Can you share client testimonials?", answer: "Yes — I have testimonials and references available. Many of my clients see 23x improvements in engagement after implementing new creative assets." },
{ question: "What makes your work different?", answer: "I combine strategic thinking with high-end execution. Every project is approached as a partnership — I'm invested in your success, not just delivering files." },
],
},
]}
cta={{
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp?_wi=3",
name: "More questions? Reach out anytime.",
role: "joseph@alexandercreative.com",
buttonText: "Book a call",
buttonHref: "#contact",
}}
/>
</div>
);
}

View File

@@ -0,0 +1,332 @@
/* eslint-disable */
// @ts-nocheck — generated by catalog-eject; runtime-correct but TS strict-mode false-positives on inlined catalog body
import { useRef, useEffect } from "react";
import { motion } from "motion/react";
import { ArrowRight } from "lucide-react";
import gsap from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import ImageOrVideo from "@/components/ui/ImageOrVideo";
import HeroBackgroundSlot from "@/components/ui/HeroBackgroundSlot";
import TextAnimation from "@/components/ui/TextAnimation";
import RatingStars from "@/components/ui/RatingStars";
import { useButtonClick } from "@/hooks/useButtonClick";
const primaryButton = {
text: "Book a call with me",
href: "#contact",
avatarSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp",
avatarLabel: "You"
};
const items = [
{
title: "HydroFlow Product Launch",
description: "Beverage brand shoot. Every frame engineered to sell.",
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/screen-1.webp",
tag: "Product Shot"
},
{
title: "Webild Athlete Campaign",
description: "Sports tech shoot. Wearables captured in raw motion.",
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/screen-2.webp",
tag: "Photography"
},
{
title: "Maru Residence",
description: "Architectural interior shoot. Minimal compositions.",
imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/screen-3.webp",
tag: "Interior Design"
}
];
const learnMoreButton = { text: "Learn more", href: "#services" };
const secondaryButton = {
text: "View all my projects",
href: "#"
};
gsap.registerPlugin(ScrollTrigger);
interface HeroWorkScrollStackProps {
tag: string;
title: string;
titleHighlight: string;
description: string;
descriptionMuted: string;
primaryButton: { text: string; href: string; avatarSrc: string; avatarLabel: string };
sectionTag: string;
sectionTitle: string;
sectionDescription: string;
items: [
{ title: string; description: string; imageSrc: string; tag: string },
{ title: string; description: string; imageSrc: string; tag: string },
{ title: string; description: string; imageSrc: string; tag: string }
];
secondaryButton?: { text: string; href: string };
heroAnimationDelay?: number;
}
const HeroInline = () => {
const animationRef = useRef<HTMLDivElement>(null);
const placeholderRef = useRef<HTMLDivElement>(null);
const card1Ref = useRef<HTMLDivElement>(null);
const card2Ref = useRef<HTMLDivElement>(null);
const card3Ref = useRef<HTMLDivElement>(null);
const handlePrimaryClick = useButtonClick(primaryButton.href);
const handleSecondaryClick = useButtonClick(secondaryButton?.href || "#");
useEffect(() => {
const isDesktop = window.matchMedia("(min-width: 768px)").matches;
const ctx = gsap.context(() => {
const cardRefs = [card1Ref.current, card2Ref.current, card3Ref.current];
const placeholder = placeholderRef.current;
if (!placeholder) return;
const placeholderRect = placeholder.getBoundingClientRect();
const placeholderCenterY = placeholderRect.top + placeholderRect.height / 2;
if (isDesktop) {
// DESKTOP: Scrub animation tied to scroll position
const xOffsets = ["32rem", "14.5rem", "-1.8rem"];
const yAdjustments = [0, -48, 0];
const rotations = [-5, 0, 5];
const scales = [1.35, 1.3, 1.25];
const zIndexes = [30, 20, 10];
const tl = gsap.timeline({
scrollTrigger: {
trigger: animationRef.current,
start: "top top",
end: "bottom bottom",
scrub: 1,
},
});
cardRefs.forEach((card, i) => {
if (!card) return;
const cardRect = card.getBoundingClientRect();
const cardCenterY = cardRect.top + cardRect.height / 2;
const yOffset = placeholderCenterY - cardCenterY;
gsap.set(card, {
x: xOffsets[i],
y: yOffset + yAdjustments[i],
rotation: rotations[i],
scale: scales[i],
zIndex: zIndexes[i],
willChange: "transform",
force3D: true,
});
tl.to(card, { x: 0, y: 0, rotation: 0, scale: 1, duration: 0.4, ease: "none" }, 0);
tl.to(card, { zIndex: 1, duration: 0.1, ease: "none" }, 0.3);
});
} else {
// MOBILE: Toggle animation - play/reverse on scroll
const xOffsets = ["2.5rem", "0.5rem", "-1rem"];
const yAdjustments = [-10, -30, 10];
const rotations = [-5, 0, 5];
const scales = [0.65, 0.7, 0.75];
const zIndexes = [30, 20, 10];
cardRefs.forEach((card, i) => {
if (!card) return;
const cardRect = card.getBoundingClientRect();
const cardCenterY = cardRect.top + cardRect.height / 2;
const yOffset = placeholderCenterY - cardCenterY;
gsap.set(card, {
x: xOffsets[i],
y: yOffset + yAdjustments[i],
rotation: rotations[i],
scale: scales[i],
zIndex: zIndexes[i],
willChange: "transform",
force3D: true,
});
gsap.to(card, {
x: 0,
y: 0,
rotation: 0,
scale: 1,
duration: 1.2,
ease: "power2.inOut",
scrollTrigger: {
trigger: placeholder,
start: "top 35%",
toggleActions: "play none none reverse",
},
});
});
}
}, animationRef);
return () => ctx.revert();
}, []);
return (
<div ref={animationRef}>
<div id="hero" data-section="hero">
<section aria-label="Hero section" className="relative h-fit md:h-svh pt-30 pb-20 md:py-0 flex items-center overflow-hidden md:overflow-visible">
<HeroBackgroundSlot />
<div className="w-content-width mx-auto">
<div className="flex flex-col md:flex-row items-center gap-10 md:gap-20 w-full">
<motion.div
initial={{ y: 10, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 1.8, ease: [0.16, 1, 0.3, 1], delay: 4 ?? 0 }}
className="w-full md:w-[46%] flex flex-col items-center md:items-start gap-3"
>
<div className="card backdrop-blur flex items-center gap-2 px-3 py-1 rounded">
<span className="size-2 rounded-full bg-green-500 animate-pulsate [--accent:#22c55e]" />
<p className="text-sm leading-snug font-medium text-foreground">{"1 spot left this month"}</p>
</div>
<h1 className="text-6xl md:text-7xl 2xl:text-8xl font-medium leading-[1.05] tracking-tight text-center md:text-left">
<span className="inline pb-[0.1em] -mb-[0.1em] bg-linear-to-r from-foreground to-primary-cta bg-clip-text text-transparent">
{"Design that"}{" "}
<span className="font-bold">{"commands attention."}</span>
</span>
</h1>
<div className="flex justify-center md:justify-start mt-2 mb-2">
<div className="flex items-center gap-1 text-yellow-500">
{[...Array(5)].map((_, i) => (
<svg key={i} xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" className="w-5 h-5">
<path fillRule="evenodd" d="M10.788 3.21c.448-1.077 1.976-1.077 2.424 0l2.082 5.006 5.404.434c1.164.093 1.636 1.545.749 2.305l-4.117 3.527 1.257 5.273c.271 1.136-.964 2.033-1.96 1.425L12 18.354 7.373 21.18c-.996.608-2.231-.29-1.96-1.425l1.257-5.273-4.117-3.527c-.887-.76-.415-2.212.749-2.305l5.404-.434 2.082-5.005Z" clipRule="evenodd" />
</svg>
))}
</div>
</div>
<p className="text-base md:text-lg font-medium leading-snug text-center md:text-left max-w-[95%]">
{"Design engineered for performance, not just aesthetics."}{" "}
<span className="text-foreground/50">{"I craft every visual touchpoint your brand needs to capture attention and convert it into revenue."}</span>
</p>
<div className="flex flex-wrap items-center gap-4 mt-2">
<a
href={primaryButton.href}
onClick={handlePrimaryClick}
className="group flex items-center gap-3 text-primary-cta-text rounded-full pl-3 pr-6 py-3 w-fit primary-button transition-all duration-300"
>
<div className="flex items-center">
<div className="card p-px rounded-full transition-transform duration-500 ease-out group-hover:-rotate-6">
<img
src={primaryButton.avatarSrc}
className="w-9 h-9 rounded-full object-cover"
alt=""
/>
</div>
<div className="grid grid-cols-[0fr] group-hover:grid-cols-[1fr] transition-all duration-500 ease-out">
<div className="overflow-hidden flex items-center">
<span className="text-primary-cta-text text-sm font-medium mx-2 transition-transform duration-500 ease-out -translate-x-3 group-hover:translate-x-0">
+
</span>
<div className="card p-px rounded-full shrink-0 transition-transform duration-500 ease-out -translate-x-5 group-hover:translate-x-0 group-hover:rotate-6">
<span className="w-9 h-9 rounded-full flex items-center justify-center">
<span className="text-foreground text-xs font-bold">{primaryButton.avatarLabel}</span>
</span>
</div>
</div>
</div>
</div>
<span className="text-base font-medium whitespace-nowrap">{primaryButton.text}</span>
</a>
<a
href="#services"
className="secondary-button flex items-center gap-2 px-6 py-3 rounded-full transition-all duration-300"
>
{learnMoreButton.text}
</a>
</div>
</motion.div>
<div ref={placeholderRef} className="w-full md:w-[54%] relative h-80 md:h-96">
<div className="absolute inset-0 card rounded-2xl md:hidden" />
</div>
</div>
</div>
</section>
</div>
<div id="work" data-section="work">
<section aria-label="Work section" className="py-20 md:pt-0">
<div className="flex flex-col gap-8 w-content-width mx-auto">
<div className="flex flex-col items-center gap-2">
<div className="px-3 py-1 mb-1 text-sm card rounded w-fit">
<p>{"Selected Work"}</p>
</div>
<TextAnimation
text={"Projects That Speak for Themselves"}
variant="slide-up"
gradientText={true}
tag="h2"
className="md:max-w-8/10 text-6xl 2xl:text-7xl leading-[1.15] font-semibold text-center text-balance"
/>
<div className="flex justify-center mt-4">
<RatingStars rating={5} />
</div>
<TextAnimation
text={"A curated selection of design work that drove real business results for ambitious brands."}
variant="slide-up"
gradientText={false}
tag="p"
className="md:max-w-7/10 text-lg md:text-xl leading-snug text-center text-balance"
/>
</div>
<div className="grid md:grid-cols-3 gap-5">
{items.map((item, index) => {
const cardRef = index === 0 ? card1Ref : index === 1 ? card2Ref : card3Ref;
return (
<div key={item.title} className="flex flex-col gap-3 xl:gap-4 2xl:gap-5">
<div
ref={cardRef}
className="aspect-4/3 rounded-2xl shadow-2xl relative card p-2 xl:p-3 2xl:p-4"
>
<div className="w-full h-full rounded-xl overflow-hidden relative">
<ImageOrVideo imageSrc={item.imageSrc} className="w-full h-full object-cover" />
<span className="absolute bottom-2 left-2 xl:bottom-3 xl:left-3 2xl:bottom-4 2xl:left-4 px-3 py-1.5 text-xs font-medium text-primary-cta-text rounded-full backdrop-blur-xl bg-primary-cta-text/15 border border-primary-cta-text/20">
{item.tag}
</span>
</div>
</div>
<p className="text-lg md:text-xl lg:text-2xl leading-snug">
<span className="font-semibold text-foreground">{item.title}. </span>
<span className="text-foreground/50">{item.description}</span>
</p>
</div>
);
})}
</div>
{secondaryButton && (
<div className="flex justify-center">
<a
href={secondaryButton.href}
onClick={handleSecondaryClick}
className="group flex items-center gap-2 px-6 py-3 text-base font-medium rounded-full secondary-button text-secondary-cta-text transition-all duration-300"
>
<span>{secondaryButton.text}</span>
<ArrowRight className="size-4 transition-transform duration-300 group-hover:translate-x-1" />
</a>
</div>
)}
</div>
</section>
</div>
</div>
);
};
export default function HeroSection() {
return (
<div data-webild-section="hero" id="hero">
<HeroInline />
</div>
);
}

View File

@@ -0,0 +1,29 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "services" section.
import React from 'react';
import FeaturesBentoGridCta from "@/components/sections/features/FeaturesBentoGridCta";
export default function ServicesSection(): React.JSX.Element {
return (
<div id="services" data-section="services">
<FeaturesBentoGridCta
tag="Services"
title="What I Bring to the Table"
description="End-to-end creative services designed to make your brand impossible to ignore — from the first frame to the final pixel."
features={[
{ title: "Photography", description: "Art-directed shoots that capture your brand's personality. Every image is color-graded and built to stop the scroll.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/photography.webp" },
{ title: "Product Design", description: "User-centered interfaces for apps and SaaS products. From wireframe to pixel-perfect UI — intuitive experiences that keep users coming back.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/product-design.webp" },
{ title: "Website", description: "Conversion-focused websites that look sharp and perform. Clean layouts, strategic CTAs, and responsive design that turns traffic into revenue.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/website.webp" },
{ title: "Videos", description: "Brand films and product videos engineered for engagement. Story-driven visuals that convert viewers into customers.", imageSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/videos.webp" },
]}
ctaButton={{
text: "Book a call with me",
href: "#contact",
avatarSrc: "https://storage.googleapis.com/webild/default/templates/creative-portfolio/avatar.webp",
avatarLabel: "You",
}}
/>
</div>
);
}

View File

@@ -0,0 +1,20 @@
// AUTO-GENERATED by per-section-migrate. Edit freely — Bob will treat this
// file as the canonical source for the "testimonial" section.
import React from 'react';
import TestimonialTrustCard from "@/components/sections/testimonial/TestimonialTrustCard";
export default function TestimonialSection(): React.JSX.Element {
return (
<div id="testimonial" data-section="testimonial">
<TestimonialTrustCard
quote="Working with Joseph felt like having a seasoned design partner who truly understood our vision for KYMA and brought it to life in ways we hadn't even imagined."
rating={5}
author="Thomas Weber — Co-founder of KYMA"
avatars={[
{ name: "Thomas Weber", imageSrc: "https://randomuser.me/api/portraits/men/75.jpg" },
]}
/>
</div>
);
}