Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/app/comparison/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MarketingPage } from '@/components/MarketingPage'

const Layout = ({ children }) => <MarketingPage>{children}</MarketingPage>
const Layout = ({ children }) => <MarketingPage withGradient>{children}</MarketingPage>
export default Layout
2 changes: 1 addition & 1 deletion src/app/migrate/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MarketingPage } from '@/components/MarketingPage'

const Layout = ({ children }) => <MarketingPage>{children}</MarketingPage>
const Layout = ({ children }) => <MarketingPage withGradient>{children}</MarketingPage>
export default Layout
6 changes: 4 additions & 2 deletions src/app/showcase/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
import Image from 'next/image'
import Link from 'next/link'
import { formatNumber } from '@/lib/common'
import { ShowcaseGradient } from '@/components/ShowcaseGradient'
import companies from './companies.json'
import testimonials from '../../../utils/testimonials.json'

Expand Down Expand Up @@ -53,8 +54,9 @@ export default function ShowcasePage() {
}, [])

return (
<div className="min-h-screen bg-slate-900">
<div className="mx-auto max-w-5xl px-4 py-16 sm:px-6 lg:px-8">
<div className="relative min-h-screen overflow-x-clip bg-slate-900">
<ShowcaseGradient />
<div className="relative mx-auto max-w-5xl px-4 py-16 sm:px-6 lg:px-8">
{/* Hero */}
<div className="text-center">
<h1 className="font-display text-4xl font-bold tracking-tight text-white">
Expand Down
2 changes: 1 addition & 1 deletion src/app/why-gofr/layout.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MarketingPage } from '@/components/MarketingPage'

const Layout = ({ children }) => <MarketingPage>{children}</MarketingPage>
const Layout = ({ children }) => <MarketingPage withGradient>{children}</MarketingPage>
export default Layout
4 changes: 3 additions & 1 deletion src/components/HomePage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { EcosystemRecognition } from '@/components/EcosystemRecognition'
import { FadeInOnScroll } from '@/components/FadeInOnScroll'
import { StaggerChildren } from '@/components/StaggerChildren'
import blurCyanImage from "@/images/blur-cyan.png";
import { ShowcaseGradient } from '@/components/ShowcaseGradient'
import Image from "next/image";
import React from "react";
import Testimonials from "@/components/Reviews";
Expand All @@ -19,7 +20,8 @@ import Testimonials from "@/components/Reviews";
// continuous strip rather than two seams.
export function HomePage() {
return (
<div className="m-auto w-auto max-w-screen-2xl">
<div className="relative m-auto w-auto max-w-screen-2xl overflow-x-clip">
<ShowcaseGradient />
Comment on lines +23 to +24
{/* Density-matched section padding. Uniform `py-24` everywhere
made the page feel padded-for-padding's-sake when section
content was thin (a 100 px marquee strip, a 1-row logo wall).
Expand Down
17 changes: 15 additions & 2 deletions src/components/MarketingPage.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import { ShowcaseGradient } from '@/components/ShowcaseGradient'

// Wrapper for the SEO-only Markdoc pages (/why-gofr, /comparison/*,
// /migrate/*, /learn, /faq). It supplies the flex container DocsLayout
// expects, but unlike DocsPage it does NOT render a left sidebar — these
// pages aren't core navigation, they're SEO landing content. Right-rail
// "On this page" TOC from DocsLayout still renders. Cross-links to the
// other SEO pages live in the global footer.
export function MarketingPage({ children }) {
//
// `withGradient` adds the decorative orb layer (ShowcaseGradient).
// Opt-in because /faq and /learn are reading-mode reference pages
// where the gradient is just visual noise; /why-gofr, /comparison/*,
// /migrate/* are positioning surfaces where it belongs.
export function MarketingPage({ children, withGradient = false }) {
return (
<div>
<div className="relative mx-auto flex w-full max-w-screen-2xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12">
<div
className={
'relative mx-auto flex w-full max-w-screen-2xl flex-auto justify-center sm:px-2 lg:px-8 xl:px-12' +
(withGradient ? ' overflow-x-clip' : '')
}
>
{withGradient && <ShowcaseGradient />}
{children}
</div>
</div>
Expand Down
8 changes: 6 additions & 2 deletions src/components/Reviews.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ export default function Testimonials() {
{/*<h2 className="text-center text-lg font-semibold leading-8 text-white mb-10">*/}
{/* User Testimonials*/}
{/*</h2>*/}
<div className="sm:columns-2 md:columns-3">
<div className="gap-x-6 sm:columns-2 md:columns-3">
{testimonials.map((testimonial, index) => (
<div key={index} className="group inline-block relative my-3 rounded-xl border cursor-default border-slate-200 dark:border-slate-800 p-1">
// `block break-inside-avoid` keeps each card whole inside
// the CSS multi-column flow. Without it, a tall card gets
// split at the column boundary and the two halves render
// on top of each other on narrow viewports.
<div key={index} className="group block break-inside-avoid w-full relative my-3 rounded-xl border cursor-default border-slate-200 dark:border-slate-800 p-1">
<div className="absolute -inset-px rounded-xl border-2 border-transparent opacity-0 [background:linear-gradient(var(--quick-links-hover-bg,theme(colors.sky.50)),var(--quick-links-hover-bg,theme(colors.sky.50)))_padding-box,linear-gradient(to_top,theme(colors.indigo.400),theme(colors.cyan.400),theme(colors.sky.500))_border-box] group-hover:opacity-100 dark:[--quick-links-hover-bg:theme(colors.slate.800)]" />

<div className="relative overflow-hidden rounded-xl p-6">
Expand Down
56 changes: 56 additions & 0 deletions src/components/ShowcaseGradient.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import Image from 'next/image'
import blurCyanImage from '@/images/blur-cyan.png'
import blurIndigoImage from '@/images/blur-indigo.png'

// Decorative gradient layer for the framework's pitch / showcase
// surfaces — homepage, /why-gofr, /comparison/*, /showcase, /migrate/*.
// Three pointer-events-none orbs distributed down the page at
// alternating sides, reusing the cyan + indigo vocabulary the hero
// already establishes. Drop inside any `relative overflow-x-clip`
// wrapper.
//
// Why an absolute layer instead of a CSS background-image:
// - Matches the existing Hero implementation (Image PNGs, opacity).
// - Lets us anchor each orb relative to a known parent, so different
// pages can opt in without re-tuning a body-level gradient.
//
// Why `unoptimized` is mandatory: the site builds with
// `output: 'export'`, which disables /_next/image. Without unoptimized,
// Next emits a /_next/image?url=... src that 404s in production and
// renders as a broken-image icon.
Comment on lines +17 to +20
export function ShowcaseGradient() {
return (
<>
<Image
aria-hidden="true"
className="pointer-events-none absolute -left-32 top-[30%] hidden select-none opacity-20 sm:block"
src={blurCyanImage}
alt=""
width={530}
height={530}
loading="lazy"
unoptimized
/>
<Image
aria-hidden="true"
className="pointer-events-none absolute -right-40 top-[55%] hidden select-none opacity-20 sm:block"
src={blurIndigoImage}
alt=""
width={567}
height={567}
loading="lazy"
unoptimized
/>
<Image
aria-hidden="true"
className="pointer-events-none absolute -left-40 top-[80%] hidden select-none opacity-15 sm:block"
src={blurCyanImage}
alt=""
width={530}
height={530}
loading="lazy"
unoptimized
/>
</>
)
}
Loading