19 Commits

Author SHA1 Message Date
68e5f92dde Update src/components/button/useButtonClick.ts 2026-03-25 23:39:02 +00:00
b76d1546b5 Update src/components/button/ButtonBounceEffect/ButtonBounceEffect.tsx 2026-03-25 23:38:13 +00:00
2eb4be8f1c Update src/components/button/ButtonBounceEffect/ButtonBounceEffect.tsx 2026-03-25 23:37:26 +00:00
99daeff82c Update src/components/button/useButtonClick.ts 2026-03-25 23:36:52 +00:00
c0c6b67710 Update src/components/button/ButtonBounceEffect/ButtonBounceEffect.tsx 2026-03-25 23:36:52 +00:00
a6f99ff072 Update src/components/button/useButtonClick.ts 2026-03-25 23:34:03 +00:00
b842d2ba67 Update src/app/page.tsx 2026-03-25 23:34:03 +00:00
05a3691716 Merge version_6 into main
Merge version_6 into main
2026-03-25 23:30:09 +00:00
498aafdfb6 Update src/app/page.tsx 2026-03-25 23:30:06 +00:00
b67d96e954 Switch to version 4: modified src/app/page.tsx 2026-03-25 23:27:07 +00:00
5e6075de8c Merge version_5 into main
Merge version_5 into main
2026-03-25 20:35:41 +00:00
a5d78ee848 Update src/app/page.tsx 2026-03-25 20:35:35 +00:00
3d9c52f1c4 Merge version_5 into main
Merge version_5 into main
2026-03-25 20:34:59 +00:00
f5f4494897 Update src/app/page.tsx 2026-03-25 20:34:56 +00:00
bdcd89802a Merge version_4 into main
Merge version_4 into main
2026-03-25 20:24:18 +00:00
40ba90567e Update src/app/page.tsx 2026-03-25 20:24:15 +00:00
7b5e6496f3 Merge version_3 into main
Merge version_3 into main
2026-03-25 20:21:14 +00:00
c58995ef46 Update src/app/styles/variables.css 2026-03-25 20:21:11 +00:00
b8495e866b Update src/app/page.tsx 2026-03-25 20:21:10 +00:00
4 changed files with 87 additions and 146 deletions

View File

@@ -1,7 +1,6 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import ReactLenis from "lenis/react";
import ContactCTA from '@/components/sections/contact/ContactCTA';
import FaqDouble from '@/components/sections/faq/FaqDouble';
import FeatureCardTwentyThree from '@/components/sections/feature/FeatureCardTwentyThree';
@@ -20,13 +19,13 @@ export default function LandingPage() {
borderRadius="pill"
contentWidth="medium"
sizing="mediumLarge"
background="noise"
background="floatingGradient"
cardStyle="glass-elevated"
primaryButtonStyle="gradient"
secondaryButtonStyle="layered"
headingFontWeight="bold"
>
<ReactLenis root>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
navItems={[
@@ -91,8 +90,8 @@ export default function LandingPage() {
id: "6", title: "Realtor Support", tags: [],
imageSrc: "http://img.b2bpic.net/free-photo/real-estate-agent-presenting-floor-plan_74855-3057.jpg", imageAlt: "Realtor support icon"},
]}
title="Built to win trust fast and turn visitors into booked inspections."
description="This layout leans into the strongest conversion points: credibility, clarity, responsiveness, and a premium brand feel that separates Results Roofing from average contractors."
title="Comprehensive Roofing & Exterior Services for Your Home"
description="Results Roofing offers a full spectrum of services, including detailed inspections, reliable repairs, full roof replacements, and seamless insurance claim assistance. We also handle gutters and exterior work, providing realtors and homeowners with a trusted partner for all their roofing needs."
tag="Services"
tagIcon={Wrench}
tagAnimation="slide-up"
@@ -179,11 +178,11 @@ export default function LandingPage() {
background={{
variant: "radial-gradient"}}
tag="Ready when you are"
title="Protect your home with a roof that looks better and performs better."
description="Whether you need an inspection, a fast repair, or a full replacement, Results Roofing is positioned here as the premium choice that still feels approachable."
title="Get Your Free Roofing Estimate"
description="Need an inspection, repair, or full roof replacement? Tell us what is going on and our team will reach out to schedule your free estimate."
buttons={[
{
text: "Get a Free Estimate", href: "#quote"},
text: "Request Free Estimate", href: "#quote"},
{
text: "Call Results Roofing", href: "tel:+12145550199"},
]}
@@ -231,7 +230,7 @@ export default function LandingPage() {
copyrightText="© 2024 | Results Roofing. All rights reserved."
/>
</div>
</ReactLenis>
</ThemeProvider>
);
}

View File

@@ -10,15 +10,15 @@
--accent: #ffffff;
--background-accent: #ffffff; */
--background: #020617;
--card: #0f172a;
--foreground: #e2e8f0;
--primary-cta: #c4d8f9;
--primary-cta-text: #020617;
--secondary-cta: #041633;
--secondary-cta-text: #e2e8f0;
--accent: #2d30f3;
--background-accent: #1d4ed8;
--background: #010110;
--card: #08081F;
--foreground: #E8E8FF;
--primary-cta: #4A7CFF;
--primary-cta-text: #FFFFFF;
--secondary-cta: #1A2A4C;
--secondary-cta-text: #E8E8FF;
--accent: #70A0FF;
--background-accent: #030320;
/* text sizing - set by ThemeProvider */
/* --text-2xs: clamp(0.465rem, 0.62vw, 0.62rem);

View File

@@ -1,74 +1,57 @@
"use client";
import React, { forwardRef } from "react";
import { cn } from "@/lib/utils";
import { useButtonClick } from "@/components/button/useButtonClick";
import { useRef, memo } from "react";
import { useCharAnimation } from "../useCharAnimation";
import { useButtonClick } from "../useButtonClick";
import { cls } from "@/lib/utils";
import "./BounceButton.css";
interface ButtonBounceEffectProps {
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
text: string;
onClick?: () => void;
href?: string;
className?: string;
bgClassName?: string;
textClassName?: string;
disabled?: boolean;
ariaLabel?: string;
type?: "button" | "submit" | "reset";
scrollToSection?: boolean;
iconClassName?: string;
newTab?: boolean;
}
const ButtonBounceEffect = ({
text,
onClick,
href,
className = "",
bgClassName = "",
textClassName = "",
disabled = false,
ariaLabel,
type = "button",
scrollToSection,
}: ButtonBounceEffectProps) => {
const buttonRef = useRef<HTMLButtonElement>(null);
const handleClick = useButtonClick(href, onClick, scrollToSection);
export const ButtonBounceEffect = forwardRef<HTMLButtonElement, ButtonProps>(
(
{
text,
onClick,
href,
className,
bgClassName,
textClassName,
iconClassName,
disabled = false,
ariaLabel,
type = "button", newTab,
...props
},
ref
) => {
const clickHandler = useButtonClick(href, onClick, newTab);
useCharAnimation(buttonRef, text);
return (
<button
ref={buttonRef}
type={type}
onClick={handleClick}
data-href={href}
disabled={disabled}
aria-label={ariaLabel || text}
className={cls(
"bounce-button relative cursor-pointer flex items-center justify-center bg-transparent border-none leading-none no-underline h-9 px-6 min-w-0 w-fit max-w-full rounded-theme text-primary-cta-text",
"disabled:cursor-not-allowed disabled:opacity-50",
className
)}
>
<div
className={cls(
"bounce-button-bg absolute! inset-0 rounded-theme primary-button",
bgClassName
)}
></div>
<span
data-button-animate-chars=""
className={cls(
"bounce-button-text relative text-sm inline-block overflow-hidden truncate whitespace-nowrap",
textClassName
return (
<button
className={cn(
"group relative flex h-12 w-full items-center justify-center rounded-lg bg-primary-cta p-3 text-sm font-medium text-primary-cta-foreground transition-all duration-300 ease-out active:scale-95", className
)}
onClick={clickHandler}
aria-label={ariaLabel}
disabled={disabled}
type={type}
ref={ref}
{...props}
>
{text}
</span>
</button>
);
};
<span
className={cn(
"relative flex items-center gap-2 translate-y-0 group-hover:-translate-y-1 group-active:translate-y-0 transition-transform duration-300 ease-out", textClassName
)}
>
{text}
</span>
</button>
);
}
);
ButtonBounceEffect.displayName = "ButtonBounceEffect";
export default memo(ButtonBounceEffect);

View File

@@ -1,74 +1,33 @@
"use client";
import { useLenis } from "lenis/react";
import { useRouter, usePathname } from "next/navigation";
import { useEffect } from "react";
import { useCallback } from "react";
// No import for 'lenis' or 'lenis/react'
export const useButtonClick = (
href?: string,
onClick?: () => void,
scrollToSection?: boolean
) => {
const lenis = useLenis();
const router = useRouter();
const pathname = usePathname();
/**
* A hook to provide a consistent click handler for buttons, especially for internal hash navigation.
* It ensures smooth scrolling without relying on external libraries like Lenis or problematic querySelector patterns.
*/
export function useButtonClick() {
const handleButtonClick = useCallback((event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>, href?: string) => {
if (href && href.startsWith("#")) {
const id = href.substring(1); // Remove the '#'
// Use getElementById directly to avoid querySelector issues with complex IDs (like '##quote')
const targetElement = document.getElementById(id);
const scrollToElement = (sectionId: string, delay: number = 100) => {
setTimeout(() => {
if (lenis) {
lenis.scrollTo(`#${sectionId}`, { offset: 0 });
if (targetElement) {
event.preventDefault(); // Prevent default browser jump
targetElement.scrollIntoView({ behavior: "smooth" });
// Optionally update the URL hash without a full page reload or additional scroll
// history.pushState(null, '', href);
} else {
const element = document.getElementById(sectionId);
if (element) {
element.scrollIntoView({ behavior: "smooth", block: "start" });
}
}
}, delay);
};
const handleClick = () => {
if (href) {
const isExternalLink = /^(https?:\/\/|www\.)/.test(href);
if (isExternalLink) {
window.open(
href.startsWith("www.") ? `https://${href}` : href,
"_blank",
"noopener,noreferrer"
);
} else if (href.startsWith("/")) {
const [path, hash] = href.split("#");
if (path !== pathname) {
router.push(path);
if (hash) {
setTimeout(() => {
window.location.hash = hash;
scrollToElement(hash, 100);
}, 100);
}
} else {
if (hash) {
window.location.hash = hash;
scrollToElement(hash, 50);
} else if (scrollToSection) {
const sectionId = path.replace(/^\//, "").replace(/\//g, "-");
scrollToElement(sectionId, 50);
}
}
} else {
scrollToElement(href, 50);
console.warn(`Attempted to scroll to element with ID '${id}', but it was not found on the page.`);
// If the element is not found, we let the default behavior happen (which might lead to a page refresh to the root)
// or prevent it and do nothing. Given it's a "fix" for a bug, a silent failure with a console warning is safer than unexpected navigation.
}
}
onClick?.();
};
// For non-hash hrefs (external links, full paths), let the browser handle it
// unless there's a specific programmatic override needed (which isn't requested here).
}, []);
useEffect(() => {
if (typeof window !== "undefined" && window.location.hash) {
const hash = window.location.hash.replace("#", "");
scrollToElement(hash, 300);
}
}, [pathname]);
return handleClick;
};
return { handleButtonClick };
}